blob: 52672dad1fe93c5a6d219ef89de2c7ae67498f4b [file] [log] [blame]
Xiao Guangrongb8f46c52010-02-03 11:53:14 +08001#define _FILE_OFFSET_BITS 64
2
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -02003#include <linux/kernel.h>
4
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -02005#include <byteswap.h>
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -02006#include <unistd.h>
7#include <sys/types.h>
Arnaldo Carvalho de Meloa41794c2010-05-18 18:29:23 -03008#include <sys/mman.h>
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -02009
10#include "session.h"
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -020011#include "sort.h"
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020012#include "util.h"
13
14static int perf_session__open(struct perf_session *self, bool force)
15{
16 struct stat input_stat;
17
Tom Zanussi8dc58102010-04-01 23:59:15 -050018 if (!strcmp(self->filename, "-")) {
19 self->fd_pipe = true;
20 self->fd = STDIN_FILENO;
21
22 if (perf_header__read(self, self->fd) < 0)
23 pr_err("incompatible file format");
24
25 return 0;
26 }
27
Xiao Guangrongf887f302010-02-04 16:46:42 +080028 self->fd = open(self->filename, O_RDONLY);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020029 if (self->fd < 0) {
Andy Isaacson0f2c3de2010-06-11 20:36:15 -070030 int err = errno;
31
32 pr_err("failed to open %s: %s", self->filename, strerror(err));
33 if (err == ENOENT && !strcmp(self->filename, "perf.data"))
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020034 pr_err(" (try 'perf record' first)");
35 pr_err("\n");
36 return -errno;
37 }
38
39 if (fstat(self->fd, &input_stat) < 0)
40 goto out_close;
41
42 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
43 pr_err("file %s not owned by current user or root\n",
44 self->filename);
45 goto out_close;
46 }
47
48 if (!input_stat.st_size) {
49 pr_info("zero-sized file (%s), nothing to do!\n",
50 self->filename);
51 goto out_close;
52 }
53
Tom Zanussi8dc58102010-04-01 23:59:15 -050054 if (perf_header__read(self, self->fd) < 0) {
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020055 pr_err("incompatible file format");
56 goto out_close;
57 }
58
59 self->size = input_stat.st_size;
60 return 0;
61
62out_close:
63 close(self->fd);
64 self->fd = -1;
65 return -1;
66}
67
Tom Zanussi8dc58102010-04-01 23:59:15 -050068void perf_session__update_sample_type(struct perf_session *self)
69{
70 self->sample_type = perf_header__sample_type(&self->header);
71}
72
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080073int perf_session__create_kernel_maps(struct perf_session *self)
74{
Arnaldo Carvalho de Melod118f8b2010-05-10 12:51:05 -030075 int ret = machine__create_kernel_maps(&self->host_machine);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080076
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080077 if (ret >= 0)
Arnaldo Carvalho de Melod118f8b2010-05-10 12:51:05 -030078 ret = machines__create_guest_kernel_maps(&self->machines);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080079 return ret;
80}
81
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -030082static void perf_session__destroy_kernel_maps(struct perf_session *self)
83{
84 machine__destroy_kernel_maps(&self->host_machine);
85 machines__destroy_guest_kernel_maps(&self->machines);
86}
87
Tom Zanussi454c4072010-05-01 01:41:20 -050088struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe)
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020089{
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -020090 size_t len = filename ? strlen(filename) + 1 : 0;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020091 struct perf_session *self = zalloc(sizeof(*self) + len);
92
93 if (self == NULL)
94 goto out;
95
96 if (perf_header__init(&self->header) < 0)
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -020097 goto out_free;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020098
99 memcpy(self->filename, filename, len);
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -0200100 self->threads = RB_ROOT;
Arnaldo Carvalho de Melo720a3ae2010-06-17 08:37:44 -0300101 INIT_LIST_HEAD(&self->dead_threads);
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300102 self->hists_tree = RB_ROOT;
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -0200103 self->last_match = NULL;
Thomas Gleixner55b44622010-11-30 17:49:46 +0000104 /*
105 * On 64bit we can mmap the data file in one go. No need for tiny mmap
106 * slices. On 32bit we use 32MB.
107 */
108#if BITS_PER_LONG == 64
109 self->mmap_window = ULLONG_MAX;
110#else
111 self->mmap_window = 32 * 1024 * 1024ULL;
112#endif
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300113 self->machines = RB_ROOT;
Tom Zanussi454c4072010-05-01 01:41:20 -0500114 self->repipe = repipe;
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000115 INIT_LIST_HEAD(&self->ordered_samples.samples);
Thomas Gleixner020bb752010-11-30 17:49:53 +0000116 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
Thomas Gleixner5c891f32010-11-30 17:49:55 +0000117 INIT_LIST_HEAD(&self->ordered_samples.to_free);
Arnaldo Carvalho de Melo1f626bc2010-05-09 19:57:08 -0300118 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200119
Arnaldo Carvalho de Melo64abebf2010-01-27 21:05:52 -0200120 if (mode == O_RDONLY) {
121 if (perf_session__open(self, force) < 0)
122 goto out_delete;
123 } else if (mode == O_WRONLY) {
124 /*
125 * In O_RDONLY mode this will be performed when reading the
126 * kernel MMAP event, in event__process_mmap().
127 */
128 if (perf_session__create_kernel_maps(self) < 0)
129 goto out_delete;
130 }
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200131
Tom Zanussi8dc58102010-04-01 23:59:15 -0500132 perf_session__update_sample_type(self);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200133out:
134 return self;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -0200135out_free:
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200136 free(self);
137 return NULL;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -0200138out_delete:
139 perf_session__delete(self);
140 return NULL;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200141}
142
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300143static void perf_session__delete_dead_threads(struct perf_session *self)
144{
145 struct thread *n, *t;
146
147 list_for_each_entry_safe(t, n, &self->dead_threads, node) {
148 list_del(&t->node);
149 thread__delete(t);
150 }
151}
152
153static void perf_session__delete_threads(struct perf_session *self)
154{
155 struct rb_node *nd = rb_first(&self->threads);
156
157 while (nd) {
158 struct thread *t = rb_entry(nd, struct thread, rb_node);
159
160 rb_erase(&t->rb_node, &self->threads);
161 nd = rb_next(nd);
162 thread__delete(t);
163 }
164}
165
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200166void perf_session__delete(struct perf_session *self)
167{
168 perf_header__exit(&self->header);
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -0300169 perf_session__destroy_kernel_maps(self);
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300170 perf_session__delete_dead_threads(self);
171 perf_session__delete_threads(self);
172 machine__exit(&self->host_machine);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200173 close(self->fd);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200174 free(self);
175}
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200176
Arnaldo Carvalho de Melo720a3ae2010-06-17 08:37:44 -0300177void perf_session__remove_thread(struct perf_session *self, struct thread *th)
178{
Arnaldo Carvalho de Melo70597f22010-08-02 18:59:28 -0300179 self->last_match = NULL;
Arnaldo Carvalho de Melo720a3ae2010-06-17 08:37:44 -0300180 rb_erase(&th->rb_node, &self->threads);
181 /*
182 * We may have references to this thread, for instance in some hist_entry
183 * instances, so just move them to a separate list.
184 */
185 list_add_tail(&th->node, &self->dead_threads);
186}
187
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200188static bool symbol__match_parent_regex(struct symbol *sym)
189{
190 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
191 return 1;
192
193 return 0;
194}
195
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300196struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
197 struct thread *thread,
198 struct ip_callchain *chain,
199 struct symbol **parent)
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200200{
201 u8 cpumode = PERF_RECORD_MISC_USER;
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200202 unsigned int i;
Arnaldo Carvalho de Meload5b2172010-04-02 10:04:18 -0300203 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms));
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200204
Arnaldo Carvalho de Meload5b2172010-04-02 10:04:18 -0300205 if (!syms)
206 return NULL;
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200207
208 for (i = 0; i < chain->nr; i++) {
209 u64 ip = chain->ips[i];
210 struct addr_location al;
211
212 if (ip >= PERF_CONTEXT_MAX) {
213 switch (ip) {
214 case PERF_CONTEXT_HV:
215 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
216 case PERF_CONTEXT_KERNEL:
217 cpumode = PERF_RECORD_MISC_KERNEL; break;
218 case PERF_CONTEXT_USER:
219 cpumode = PERF_RECORD_MISC_USER; break;
220 default:
221 break;
222 }
223 continue;
224 }
225
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800226 al.filtered = false;
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200227 thread__find_addr_location(thread, self, cpumode,
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800228 MAP__FUNCTION, thread->pid, ip, &al, NULL);
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200229 if (al.sym != NULL) {
230 if (sort__has_parent && !*parent &&
231 symbol__match_parent_regex(al.sym))
232 *parent = al.sym;
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200233 if (!symbol_conf.use_callchain)
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200234 break;
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300235 syms[i].map = al.map;
236 syms[i].sym = al.sym;
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200237 }
238 }
239
240 return syms;
241}
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200242
243static int process_event_stub(event_t *event __used,
244 struct perf_session *session __used)
245{
246 dump_printf(": unhandled!\n");
247 return 0;
248}
249
Frederic Weisbeckerd6b17be2010-05-03 15:14:33 +0200250static int process_finished_round_stub(event_t *event __used,
251 struct perf_session *session __used,
252 struct perf_event_ops *ops __used)
253{
254 dump_printf(": unhandled!\n");
255 return 0;
256}
257
258static int process_finished_round(event_t *event,
259 struct perf_session *session,
260 struct perf_event_ops *ops);
261
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200262static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
263{
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200264 if (handler->sample == NULL)
265 handler->sample = process_event_stub;
266 if (handler->mmap == NULL)
267 handler->mmap = process_event_stub;
268 if (handler->comm == NULL)
269 handler->comm = process_event_stub;
270 if (handler->fork == NULL)
271 handler->fork = process_event_stub;
272 if (handler->exit == NULL)
273 handler->exit = process_event_stub;
274 if (handler->lost == NULL)
Arnaldo Carvalho de Melo37982ba2010-11-26 18:31:54 -0200275 handler->lost = event__process_lost;
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200276 if (handler->read == NULL)
277 handler->read = process_event_stub;
278 if (handler->throttle == NULL)
279 handler->throttle = process_event_stub;
280 if (handler->unthrottle == NULL)
281 handler->unthrottle = process_event_stub;
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500282 if (handler->attr == NULL)
283 handler->attr = process_event_stub;
Tom Zanussicd19a032010-04-01 23:59:20 -0500284 if (handler->event_type == NULL)
285 handler->event_type = process_event_stub;
Tom Zanussi92155452010-04-01 23:59:21 -0500286 if (handler->tracing_data == NULL)
287 handler->tracing_data = process_event_stub;
Tom Zanussic7929e42010-04-01 23:59:22 -0500288 if (handler->build_id == NULL)
289 handler->build_id = process_event_stub;
Frederic Weisbeckerd6b17be2010-05-03 15:14:33 +0200290 if (handler->finished_round == NULL) {
291 if (handler->ordered_samples)
292 handler->finished_round = process_finished_round;
293 else
294 handler->finished_round = process_finished_round_stub;
295 }
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200296}
297
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200298void mem_bswap_64(void *src, int byte_size)
299{
300 u64 *m = src;
301
302 while (byte_size > 0) {
303 *m = bswap_64(*m);
304 byte_size -= sizeof(u64);
305 ++m;
306 }
307}
308
309static void event__all64_swap(event_t *self)
310{
311 struct perf_event_header *hdr = &self->header;
312 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
313}
314
315static void event__comm_swap(event_t *self)
316{
317 self->comm.pid = bswap_32(self->comm.pid);
318 self->comm.tid = bswap_32(self->comm.tid);
319}
320
321static void event__mmap_swap(event_t *self)
322{
323 self->mmap.pid = bswap_32(self->mmap.pid);
324 self->mmap.tid = bswap_32(self->mmap.tid);
325 self->mmap.start = bswap_64(self->mmap.start);
326 self->mmap.len = bswap_64(self->mmap.len);
327 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
328}
329
330static void event__task_swap(event_t *self)
331{
332 self->fork.pid = bswap_32(self->fork.pid);
333 self->fork.tid = bswap_32(self->fork.tid);
334 self->fork.ppid = bswap_32(self->fork.ppid);
335 self->fork.ptid = bswap_32(self->fork.ptid);
336 self->fork.time = bswap_64(self->fork.time);
337}
338
339static void event__read_swap(event_t *self)
340{
341 self->read.pid = bswap_32(self->read.pid);
342 self->read.tid = bswap_32(self->read.tid);
343 self->read.value = bswap_64(self->read.value);
344 self->read.time_enabled = bswap_64(self->read.time_enabled);
345 self->read.time_running = bswap_64(self->read.time_running);
346 self->read.id = bswap_64(self->read.id);
347}
348
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500349static void event__attr_swap(event_t *self)
350{
351 size_t size;
352
353 self->attr.attr.type = bswap_32(self->attr.attr.type);
354 self->attr.attr.size = bswap_32(self->attr.attr.size);
355 self->attr.attr.config = bswap_64(self->attr.attr.config);
356 self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period);
357 self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type);
358 self->attr.attr.read_format = bswap_64(self->attr.attr.read_format);
359 self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events);
360 self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type);
361 self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr);
362 self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len);
363
364 size = self->header.size;
365 size -= (void *)&self->attr.id - (void *)self;
366 mem_bswap_64(self->attr.id, size);
367}
368
Tom Zanussicd19a032010-04-01 23:59:20 -0500369static void event__event_type_swap(event_t *self)
370{
371 self->event_type.event_type.event_id =
372 bswap_64(self->event_type.event_type.event_id);
373}
374
Tom Zanussi92155452010-04-01 23:59:21 -0500375static void event__tracing_data_swap(event_t *self)
376{
377 self->tracing_data.size = bswap_32(self->tracing_data.size);
378}
379
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200380typedef void (*event__swap_op)(event_t *self);
381
382static event__swap_op event__swap_ops[] = {
383 [PERF_RECORD_MMAP] = event__mmap_swap,
384 [PERF_RECORD_COMM] = event__comm_swap,
385 [PERF_RECORD_FORK] = event__task_swap,
386 [PERF_RECORD_EXIT] = event__task_swap,
387 [PERF_RECORD_LOST] = event__all64_swap,
388 [PERF_RECORD_READ] = event__read_swap,
389 [PERF_RECORD_SAMPLE] = event__all64_swap,
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500390 [PERF_RECORD_HEADER_ATTR] = event__attr_swap,
Tom Zanussicd19a032010-04-01 23:59:20 -0500391 [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap,
Tom Zanussi92155452010-04-01 23:59:21 -0500392 [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap,
Tom Zanussic7929e42010-04-01 23:59:22 -0500393 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
Tom Zanussi8dc58102010-04-01 23:59:15 -0500394 [PERF_RECORD_HEADER_MAX] = NULL,
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200395};
396
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200397struct sample_queue {
398 u64 timestamp;
Thomas Gleixner28990f72010-11-30 17:49:35 +0000399 event_t *event;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200400 struct list_head list;
401};
402
Thomas Gleixner020bb752010-11-30 17:49:53 +0000403static void perf_session_free_sample_buffers(struct perf_session *session)
404{
405 struct ordered_samples *os = &session->ordered_samples;
406
Thomas Gleixner5c891f32010-11-30 17:49:55 +0000407 while (!list_empty(&os->to_free)) {
Thomas Gleixner020bb752010-11-30 17:49:53 +0000408 struct sample_queue *sq;
409
Thomas Gleixner5c891f32010-11-30 17:49:55 +0000410 sq = list_entry(os->to_free.next, struct sample_queue, list);
Thomas Gleixner020bb752010-11-30 17:49:53 +0000411 list_del(&sq->list);
412 free(sq);
413 }
414}
415
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200416static void flush_sample_queue(struct perf_session *s,
417 struct perf_event_ops *ops)
418{
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000419 struct ordered_samples *os = &s->ordered_samples;
420 struct list_head *head = &os->samples;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200421 struct sample_queue *tmp, *iter;
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000422 u64 limit = os->next_flush;
423 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200424
Frederic Weisbeckerd6b17be2010-05-03 15:14:33 +0200425 if (!ops->ordered_samples || !limit)
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200426 return;
427
428 list_for_each_entry_safe(iter, tmp, head, list) {
429 if (iter->timestamp > limit)
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000430 break;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200431
Thomas Gleixner28990f72010-11-30 17:49:35 +0000432 ops->sample(iter->event, s);
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200433
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000434 os->last_flush = iter->timestamp;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200435 list_del(&iter->list);
Thomas Gleixner020bb752010-11-30 17:49:53 +0000436 list_add(&iter->list, &os->sample_cache);
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200437 }
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000438
439 if (list_empty(head)) {
440 os->last_sample = NULL;
441 } else if (last_ts <= limit) {
442 os->last_sample =
443 list_entry(head->prev, struct sample_queue, list);
444 }
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200445}
446
Frederic Weisbeckerd6b17be2010-05-03 15:14:33 +0200447/*
448 * When perf record finishes a pass on every buffers, it records this pseudo
449 * event.
450 * We record the max timestamp t found in the pass n.
451 * Assuming these timestamps are monotonic across cpus, we know that if
452 * a buffer still has events with timestamps below t, they will be all
453 * available and then read in the pass n + 1.
454 * Hence when we start to read the pass n + 2, we can safely flush every
455 * events with timestamps below t.
456 *
457 * ============ PASS n =================
458 * CPU 0 | CPU 1
459 * |
460 * cnt1 timestamps | cnt2 timestamps
461 * 1 | 2
462 * 2 | 3
463 * - | 4 <--- max recorded
464 *
465 * ============ PASS n + 1 ==============
466 * CPU 0 | CPU 1
467 * |
468 * cnt1 timestamps | cnt2 timestamps
469 * 3 | 5
470 * 4 | 6
471 * 5 | 7 <---- max recorded
472 *
473 * Flush every events below timestamp 4
474 *
475 * ============ PASS n + 2 ==============
476 * CPU 0 | CPU 1
477 * |
478 * cnt1 timestamps | cnt2 timestamps
479 * 6 | 8
480 * 7 | 9
481 * - | 10
482 *
483 * Flush every events below timestamp 7
484 * etc...
485 */
486static int process_finished_round(event_t *event __used,
487 struct perf_session *session,
488 struct perf_event_ops *ops)
489{
490 flush_sample_queue(session, ops);
491 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
492
493 return 0;
494}
495
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200496/* The queue is ordered by time */
497static void __queue_sample_event(struct sample_queue *new,
498 struct perf_session *s)
499{
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000500 struct ordered_samples *os = &s->ordered_samples;
501 struct sample_queue *sample = os->last_sample;
502 u64 timestamp = new->timestamp;
503 struct list_head *p;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200504
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000505 os->last_sample = new;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200506
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000507 if (!sample) {
508 list_add(&new->list, &os->samples);
509 os->max_timestamp = timestamp;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200510 return;
511 }
512
513 /*
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000514 * last_sample might point to some random place in the list as it's
515 * the last queued event. We expect that the new event is close to
516 * this.
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200517 */
Thomas Gleixnera1225de2010-11-30 17:49:33 +0000518 if (sample->timestamp <= timestamp) {
519 while (sample->timestamp <= timestamp) {
520 p = sample->list.next;
521 if (p == &os->samples) {
522 list_add_tail(&new->list, &os->samples);
523 os->max_timestamp = timestamp;
524 return;
525 }
526 sample = list_entry(p, struct sample_queue, list);
527 }
528 list_add_tail(&new->list, &sample->list);
529 } else {
530 while (sample->timestamp > timestamp) {
531 p = sample->list.prev;
532 if (p == &os->samples) {
533 list_add(&new->list, &os->samples);
534 return;
535 }
536 sample = list_entry(p, struct sample_queue, list);
537 }
538 list_add(&new->list, &sample->list);
539 }
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200540}
541
Thomas Gleixner5c891f32010-11-30 17:49:55 +0000542#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
543
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200544static int queue_sample_event(event_t *event, struct sample_data *data,
Frederic Weisbeckerd6b17be2010-05-03 15:14:33 +0200545 struct perf_session *s)
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200546{
Thomas Gleixner5c891f32010-11-30 17:49:55 +0000547 struct ordered_samples *os = &s->ordered_samples;
548 struct list_head *sc = &os->sample_cache;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200549 u64 timestamp = data->time;
550 struct sample_queue *new;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200551
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200552 if (timestamp < s->ordered_samples.last_flush) {
553 printf("Warning: Timestamp below last timeslice flush\n");
554 return -EINVAL;
555 }
556
Thomas Gleixner020bb752010-11-30 17:49:53 +0000557 if (!list_empty(sc)) {
558 new = list_entry(sc->next, struct sample_queue, list);
559 list_del(&new->list);
Thomas Gleixner5c891f32010-11-30 17:49:55 +0000560 } else if (os->sample_buffer) {
561 new = os->sample_buffer + os->sample_buffer_idx;
562 if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER)
563 os->sample_buffer = NULL;
Thomas Gleixner020bb752010-11-30 17:49:53 +0000564 } else {
Thomas Gleixner5c891f32010-11-30 17:49:55 +0000565 os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new));
566 if (!os->sample_buffer)
Thomas Gleixner020bb752010-11-30 17:49:53 +0000567 return -ENOMEM;
Thomas Gleixner5c891f32010-11-30 17:49:55 +0000568 list_add(&os->sample_buffer->list, &os->to_free);
569 os->sample_buffer_idx = 2;
570 new = os->sample_buffer + 1;
Thomas Gleixner020bb752010-11-30 17:49:53 +0000571 }
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200572
573 new->timestamp = timestamp;
Thomas Gleixnerfe174202010-11-30 17:49:49 +0000574 new->event = event;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200575
576 __queue_sample_event(new, s);
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200577
578 return 0;
579}
580
581static int perf_session__process_sample(event_t *event, struct perf_session *s,
582 struct perf_event_ops *ops)
583{
584 struct sample_data data;
585
586 if (!ops->ordered_samples)
587 return ops->sample(event, s);
588
589 bzero(&data, sizeof(struct sample_data));
590 event__parse_sample(event, s->sample_type, &data);
591
Frederic Weisbeckerd6b17be2010-05-03 15:14:33 +0200592 queue_sample_event(event, &data, s);
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200593
594 return 0;
595}
596
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200597static int perf_session__process_event(struct perf_session *self,
598 event_t *event,
599 struct perf_event_ops *ops,
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000600 u64 file_offset)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200601{
602 trace_event(event);
603
Tom Zanussi8dc58102010-04-01 23:59:15 -0500604 if (event->header.type < PERF_RECORD_HEADER_MAX) {
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200605 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000606 file_offset, event->header.size,
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200607 event__name[event->header.type]);
Arnaldo Carvalho de Melocee75ac2010-05-14 13:16:55 -0300608 hists__inc_nr_events(&self->hists, event->header.type);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200609 }
610
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200611 if (self->header.needs_swap && event__swap_ops[event->header.type])
612 event__swap_ops[event->header.type](event);
613
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200614 switch (event->header.type) {
615 case PERF_RECORD_SAMPLE:
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200616 return perf_session__process_sample(event, self, ops);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200617 case PERF_RECORD_MMAP:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200618 return ops->mmap(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200619 case PERF_RECORD_COMM:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200620 return ops->comm(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200621 case PERF_RECORD_FORK:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200622 return ops->fork(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200623 case PERF_RECORD_EXIT:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200624 return ops->exit(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200625 case PERF_RECORD_LOST:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200626 return ops->lost(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200627 case PERF_RECORD_READ:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200628 return ops->read(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200629 case PERF_RECORD_THROTTLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200630 return ops->throttle(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200631 case PERF_RECORD_UNTHROTTLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200632 return ops->unthrottle(event, self);
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500633 case PERF_RECORD_HEADER_ATTR:
634 return ops->attr(event, self);
Tom Zanussicd19a032010-04-01 23:59:20 -0500635 case PERF_RECORD_HEADER_EVENT_TYPE:
636 return ops->event_type(event, self);
Tom Zanussi92155452010-04-01 23:59:21 -0500637 case PERF_RECORD_HEADER_TRACING_DATA:
638 /* setup for reading amidst mmap */
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000639 lseek(self->fd, file_offset, SEEK_SET);
Tom Zanussi92155452010-04-01 23:59:21 -0500640 return ops->tracing_data(event, self);
Tom Zanussic7929e42010-04-01 23:59:22 -0500641 case PERF_RECORD_HEADER_BUILD_ID:
642 return ops->build_id(event, self);
Frederic Weisbeckerd6b17be2010-05-03 15:14:33 +0200643 case PERF_RECORD_FINISHED_ROUND:
644 return ops->finished_round(event, self, ops);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200645 default:
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -0300646 ++self->hists.stats.nr_unknown_events;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200647 return -1;
648 }
649}
650
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200651void perf_event_header__bswap(struct perf_event_header *self)
652{
653 self->type = bswap_32(self->type);
654 self->misc = bswap_16(self->misc);
655 self->size = bswap_16(self->size);
656}
657
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200658static struct thread *perf_session__register_idle_thread(struct perf_session *self)
659{
660 struct thread *thread = perf_session__findnew(self, 0);
661
662 if (thread == NULL || thread__set_comm(thread, "swapper")) {
663 pr_err("problem inserting idle task.\n");
664 thread = NULL;
665 }
666
667 return thread;
668}
669
Tom Zanussi8dc58102010-04-01 23:59:15 -0500670int do_read(int fd, void *buf, size_t size)
671{
672 void *buf_start = buf;
673
674 while (size) {
675 int ret = read(fd, buf, size);
676
677 if (ret <= 0)
678 return ret;
679
680 size -= ret;
681 buf += ret;
682 }
683
684 return buf - buf_start;
685}
686
687#define session_done() (*(volatile int *)(&session_done))
688volatile int session_done;
689
690static int __perf_session__process_pipe_events(struct perf_session *self,
691 struct perf_event_ops *ops)
692{
693 event_t event;
694 uint32_t size;
695 int skip = 0;
696 u64 head;
697 int err;
698 void *p;
699
700 perf_event_ops__fill_defaults(ops);
701
702 head = 0;
703more:
704 err = do_read(self->fd, &event, sizeof(struct perf_event_header));
705 if (err <= 0) {
706 if (err == 0)
707 goto done;
708
709 pr_err("failed to read event header\n");
710 goto out_err;
711 }
712
713 if (self->header.needs_swap)
714 perf_event_header__bswap(&event.header);
715
716 size = event.header.size;
717 if (size == 0)
718 size = 8;
719
720 p = &event;
721 p += sizeof(struct perf_event_header);
722
Tom Zanussi794e43b2010-05-05 00:27:40 -0500723 if (size - sizeof(struct perf_event_header)) {
724 err = do_read(self->fd, p,
725 size - sizeof(struct perf_event_header));
726 if (err <= 0) {
727 if (err == 0) {
728 pr_err("unexpected end of event stream\n");
729 goto done;
730 }
Tom Zanussi8dc58102010-04-01 23:59:15 -0500731
Tom Zanussi794e43b2010-05-05 00:27:40 -0500732 pr_err("failed to read event data\n");
733 goto out_err;
734 }
Tom Zanussi8dc58102010-04-01 23:59:15 -0500735 }
736
737 if (size == 0 ||
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000738 (skip = perf_session__process_event(self, &event, ops, head)) < 0) {
Tom Zanussi8dc58102010-04-01 23:59:15 -0500739 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
740 head, event.header.size, event.header.type);
741 /*
742 * assume we lost track of the stream, check alignment, and
743 * increment a single u64 in the hope to catch on again 'soon'.
744 */
745 if (unlikely(head & 7))
746 head &= ~7ULL;
747
748 size = 8;
749 }
750
751 head += size;
752
753 dump_printf("\n%#Lx [%#x]: event: %d\n",
754 head, event.header.size, event.header.type);
755
756 if (skip > 0)
757 head += skip;
758
759 if (!session_done())
760 goto more;
761done:
762 err = 0;
763out_err:
Thomas Gleixner020bb752010-11-30 17:49:53 +0000764 perf_session_free_sample_buffers(self);
Tom Zanussi8dc58102010-04-01 23:59:15 -0500765 return err;
766}
767
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000768int __perf_session__process_events(struct perf_session *session,
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200769 u64 data_offset, u64 data_size,
770 u64 file_size, struct perf_event_ops *ops)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200771{
Thomas Gleixner55b44622010-11-30 17:49:46 +0000772 u64 head, page_offset, file_offset, file_pos, progress_next;
Thomas Gleixnerfe174202010-11-30 17:49:49 +0000773 int err, mmap_prot, mmap_flags, map_idx = 0;
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000774 struct ui_progress *progress;
Thomas Gleixner55b44622010-11-30 17:49:46 +0000775 size_t page_size, mmap_size;
Thomas Gleixnerfe174202010-11-30 17:49:49 +0000776 char *buf, *mmaps[8];
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200777 event_t *event;
778 uint32_t size;
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000779
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200780 perf_event_ops__fill_defaults(ops);
781
Arnaldo Carvalho de Melo1b759622010-01-14 18:30:04 -0200782 page_size = sysconf(_SC_PAGESIZE);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200783
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000784 page_offset = page_size * (data_offset / page_size);
785 file_offset = page_offset;
786 head = data_offset - page_offset;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200787
Thomas Gleixnerd6513282010-11-30 17:49:44 +0000788 if (data_offset + data_size < file_size)
789 file_size = data_offset + data_size;
790
Thomas Gleixner55b44622010-11-30 17:49:46 +0000791 progress_next = file_size / 16;
792 progress = ui_progress__new("Processing events...", file_size);
793 if (progress == NULL)
794 return -1;
795
796 mmap_size = session->mmap_window;
797 if (mmap_size > file_size)
798 mmap_size = file_size;
799
Thomas Gleixnerfe174202010-11-30 17:49:49 +0000800 memset(mmaps, 0, sizeof(mmaps));
801
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200802 mmap_prot = PROT_READ;
803 mmap_flags = MAP_SHARED;
804
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000805 if (session->header.needs_swap) {
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200806 mmap_prot |= PROT_WRITE;
807 mmap_flags = MAP_PRIVATE;
808 }
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200809remap:
Thomas Gleixner55b44622010-11-30 17:49:46 +0000810 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd,
811 file_offset);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200812 if (buf == MAP_FAILED) {
813 pr_err("failed to mmap file\n");
814 err = -errno;
815 goto out_err;
816 }
Thomas Gleixnerfe174202010-11-30 17:49:49 +0000817 mmaps[map_idx] = buf;
818 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1);
Thomas Gleixnerd6513282010-11-30 17:49:44 +0000819 file_pos = file_offset + head;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200820
821more:
822 event = (event_t *)(buf + head);
823
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000824 if (session->header.needs_swap)
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200825 perf_event_header__bswap(&event->header);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200826 size = event->header.size;
827 if (size == 0)
828 size = 8;
829
Thomas Gleixner55b44622010-11-30 17:49:46 +0000830 if (head + event->header.size >= mmap_size) {
Thomas Gleixnerfe174202010-11-30 17:49:49 +0000831 if (mmaps[map_idx]) {
832 munmap(mmaps[map_idx], mmap_size);
833 mmaps[map_idx] = NULL;
834 }
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200835
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000836 page_offset = page_size * (head / page_size);
837 file_offset += page_offset;
838 head -= page_offset;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200839 goto remap;
840 }
841
842 size = event->header.size;
843
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200844 dump_printf("\n%#Lx [%#x]: event: %d\n",
Thomas Gleixnerd6513282010-11-30 17:49:44 +0000845 file_pos, event->header.size, event->header.type);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200846
Thomas Gleixnerd6513282010-11-30 17:49:44 +0000847 if (size == 0 ||
848 perf_session__process_event(session, event, ops, file_pos) < 0) {
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200849 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000850 file_offset + head, event->header.size,
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200851 event->header.type);
852 /*
853 * assume we lost track of the stream, check alignment, and
854 * increment a single u64 in the hope to catch on again 'soon'.
855 */
856 if (unlikely(head & 7))
857 head &= ~7ULL;
858
859 size = 8;
860 }
861
862 head += size;
Thomas Gleixnerd6513282010-11-30 17:49:44 +0000863 file_pos += size;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200864
Thomas Gleixner55b44622010-11-30 17:49:46 +0000865 if (file_pos >= progress_next) {
866 progress_next += file_size / 16;
867 ui_progress__update(progress, file_pos);
868 }
869
Thomas Gleixnerd6513282010-11-30 17:49:44 +0000870 if (file_pos < file_size)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200871 goto more;
Thomas Gleixnerd6513282010-11-30 17:49:44 +0000872
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200873 err = 0;
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200874 /* do the final flush for ordered samples */
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000875 session->ordered_samples.next_flush = ULLONG_MAX;
876 flush_sample_queue(session, ops);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200877out_err:
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300878 ui_progress__delete(progress);
Arnaldo Carvalho de Melo068ffaa2010-11-27 02:41:01 -0200879
880 if (ops->lost == event__process_lost &&
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000881 session->hists.stats.total_lost != 0) {
Arnaldo Carvalho de Melo068ffaa2010-11-27 02:41:01 -0200882 ui__warning("Processed %Lu events and LOST %Lu!\n\n"
883 "Check IO/CPU overload!\n\n",
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000884 session->hists.stats.total_period,
885 session->hists.stats.total_lost);
Arnaldo Carvalho de Melo068ffaa2010-11-27 02:41:01 -0200886 }
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000887
888 if (session->hists.stats.nr_unknown_events != 0) {
Arnaldo Carvalho de Melo068ffaa2010-11-27 02:41:01 -0200889 ui__warning("Found %u unknown events!\n\n"
890 "Is this an older tool processing a perf.data "
891 "file generated by a more recent tool?\n\n"
892 "If that is not the case, consider "
893 "reporting to linux-kernel@vger.kernel.org.\n\n",
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000894 session->hists.stats.nr_unknown_events);
Arnaldo Carvalho de Melo068ffaa2010-11-27 02:41:01 -0200895 }
Thomas Gleixner0331ee02010-11-30 17:49:38 +0000896
Thomas Gleixner020bb752010-11-30 17:49:53 +0000897 perf_session_free_sample_buffers(session);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200898 return err;
899}
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200900
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200901int perf_session__process_events(struct perf_session *self,
902 struct perf_event_ops *ops)
903{
904 int err;
905
906 if (perf_session__register_idle_thread(self) == NULL)
907 return -ENOMEM;
908
Tom Zanussi8dc58102010-04-01 23:59:15 -0500909 if (!self->fd_pipe)
910 err = __perf_session__process_events(self,
911 self->header.data_offset,
912 self->header.data_size,
913 self->size, ops);
914 else
915 err = __perf_session__process_pipe_events(self, ops);
Dave Martin88ca8952010-07-27 11:46:12 -0300916
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200917 return err;
918}
919
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200920bool perf_session__has_traces(struct perf_session *self, const char *msg)
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200921{
922 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200923 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
924 return false;
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200925 }
926
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200927 return true;
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200928}
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200929
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800930int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200931 const char *symbol_name,
932 u64 addr)
933{
934 char *bracket;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200935 enum map_type i;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800936 struct ref_reloc_sym *ref;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200937
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800938 ref = zalloc(sizeof(struct ref_reloc_sym));
939 if (ref == NULL)
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200940 return -ENOMEM;
941
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800942 ref->name = strdup(symbol_name);
943 if (ref->name == NULL) {
944 free(ref);
945 return -ENOMEM;
946 }
947
948 bracket = strchr(ref->name, ']');
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200949 if (bracket)
950 *bracket = '\0';
951
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800952 ref->addr = addr;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200953
954 for (i = 0; i < MAP__NR_TYPES; ++i) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800955 struct kmap *kmap = map__kmap(maps[i]);
956 kmap->ref_reloc_sym = ref;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200957 }
958
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200959 return 0;
960}
Arnaldo Carvalho de Melo1f626bc2010-05-09 19:57:08 -0300961
962size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
963{
964 return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) +
965 __dsos__fprintf(&self->host_machine.user_dsos, fp) +
966 machines__fprintf_dsos(&self->machines, fp);
967}
Arnaldo Carvalho de Melof8690972010-05-19 13:41:23 -0300968
969size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
970 bool with_hits)
971{
972 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
973 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
974}