blob: 2c1277cb4ae4528e931afb4498410bc60b61cec9 [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>
8
9#include "session.h"
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -020010#include "sort.h"
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020011#include "util.h"
12
13static int perf_session__open(struct perf_session *self, bool force)
14{
15 struct stat input_stat;
16
Tom Zanussi8dc58102010-04-01 23:59:15 -050017 if (!strcmp(self->filename, "-")) {
18 self->fd_pipe = true;
19 self->fd = STDIN_FILENO;
20
21 if (perf_header__read(self, self->fd) < 0)
22 pr_err("incompatible file format");
23
24 return 0;
25 }
26
Xiao Guangrongf887f302010-02-04 16:46:42 +080027 self->fd = open(self->filename, O_RDONLY);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020028 if (self->fd < 0) {
29 pr_err("failed to open file: %s", self->filename);
30 if (!strcmp(self->filename, "perf.data"))
31 pr_err(" (try 'perf record' first)");
32 pr_err("\n");
33 return -errno;
34 }
35
36 if (fstat(self->fd, &input_stat) < 0)
37 goto out_close;
38
39 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
40 pr_err("file %s not owned by current user or root\n",
41 self->filename);
42 goto out_close;
43 }
44
45 if (!input_stat.st_size) {
46 pr_info("zero-sized file (%s), nothing to do!\n",
47 self->filename);
48 goto out_close;
49 }
50
Tom Zanussi8dc58102010-04-01 23:59:15 -050051 if (perf_header__read(self, self->fd) < 0) {
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020052 pr_err("incompatible file format");
53 goto out_close;
54 }
55
56 self->size = input_stat.st_size;
57 return 0;
58
59out_close:
60 close(self->fd);
61 self->fd = -1;
62 return -1;
63}
64
Tom Zanussi8dc58102010-04-01 23:59:15 -050065void perf_session__update_sample_type(struct perf_session *self)
66{
67 self->sample_type = perf_header__sample_type(&self->header);
68}
69
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -020070struct perf_session *perf_session__new(const char *filename, int mode, bool force)
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020071{
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -020072 size_t len = filename ? strlen(filename) + 1 : 0;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020073 struct perf_session *self = zalloc(sizeof(*self) + len);
74
75 if (self == NULL)
76 goto out;
77
78 if (perf_header__init(&self->header) < 0)
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -020079 goto out_free;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020080
81 memcpy(self->filename, filename, len);
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -020082 self->threads = RB_ROOT;
Eric B Munsoncb8f0932010-03-05 12:51:07 -030083 self->stats_by_id = RB_ROOT;
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -020084 self->last_match = NULL;
Arnaldo Carvalho de Meloec913362009-12-13 19:50:27 -020085 self->mmap_window = 32;
86 self->cwd = NULL;
87 self->cwdlen = 0;
Arnaldo Carvalho de Melo31d337c2009-12-27 21:37:03 -020088 self->unknown_events = 0;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -020089 map_groups__init(&self->kmaps);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020090
Arnaldo Carvalho de Melo64abebf72010-01-27 21:05:52 -020091 if (mode == O_RDONLY) {
92 if (perf_session__open(self, force) < 0)
93 goto out_delete;
94 } else if (mode == O_WRONLY) {
95 /*
96 * In O_RDONLY mode this will be performed when reading the
97 * kernel MMAP event, in event__process_mmap().
98 */
99 if (perf_session__create_kernel_maps(self) < 0)
100 goto out_delete;
101 }
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200102
Tom Zanussi8dc58102010-04-01 23:59:15 -0500103 perf_session__update_sample_type(self);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200104out:
105 return self;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -0200106out_free:
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200107 free(self);
108 return NULL;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -0200109out_delete:
110 perf_session__delete(self);
111 return NULL;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200112}
113
114void perf_session__delete(struct perf_session *self)
115{
116 perf_header__exit(&self->header);
117 close(self->fd);
Arnaldo Carvalho de Meloec913362009-12-13 19:50:27 -0200118 free(self->cwd);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200119 free(self);
120}
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200121
122static bool symbol__match_parent_regex(struct symbol *sym)
123{
124 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
125 return 1;
126
127 return 0;
128}
129
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300130struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
131 struct thread *thread,
132 struct ip_callchain *chain,
133 struct symbol **parent)
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200134{
135 u8 cpumode = PERF_RECORD_MISC_USER;
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200136 unsigned int i;
Arnaldo Carvalho de Meload5b2172010-04-02 10:04:18 -0300137 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms));
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200138
Arnaldo Carvalho de Meload5b2172010-04-02 10:04:18 -0300139 if (!syms)
140 return NULL;
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200141
142 for (i = 0; i < chain->nr; i++) {
143 u64 ip = chain->ips[i];
144 struct addr_location al;
145
146 if (ip >= PERF_CONTEXT_MAX) {
147 switch (ip) {
148 case PERF_CONTEXT_HV:
149 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
150 case PERF_CONTEXT_KERNEL:
151 cpumode = PERF_RECORD_MISC_KERNEL; break;
152 case PERF_CONTEXT_USER:
153 cpumode = PERF_RECORD_MISC_USER; break;
154 default:
155 break;
156 }
157 continue;
158 }
159
160 thread__find_addr_location(thread, self, cpumode,
161 MAP__FUNCTION, ip, &al, NULL);
162 if (al.sym != NULL) {
163 if (sort__has_parent && !*parent &&
164 symbol__match_parent_regex(al.sym))
165 *parent = al.sym;
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200166 if (!symbol_conf.use_callchain)
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200167 break;
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300168 syms[i].map = al.map;
169 syms[i].sym = al.sym;
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200170 }
171 }
172
173 return syms;
174}
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200175
176static int process_event_stub(event_t *event __used,
177 struct perf_session *session __used)
178{
179 dump_printf(": unhandled!\n");
180 return 0;
181}
182
183static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
184{
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200185 if (handler->sample == NULL)
186 handler->sample = process_event_stub;
187 if (handler->mmap == NULL)
188 handler->mmap = process_event_stub;
189 if (handler->comm == NULL)
190 handler->comm = process_event_stub;
191 if (handler->fork == NULL)
192 handler->fork = process_event_stub;
193 if (handler->exit == NULL)
194 handler->exit = process_event_stub;
195 if (handler->lost == NULL)
196 handler->lost = process_event_stub;
197 if (handler->read == NULL)
198 handler->read = process_event_stub;
199 if (handler->throttle == NULL)
200 handler->throttle = process_event_stub;
201 if (handler->unthrottle == NULL)
202 handler->unthrottle = process_event_stub;
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200203}
204
205static const char *event__name[] = {
206 [0] = "TOTAL",
207 [PERF_RECORD_MMAP] = "MMAP",
208 [PERF_RECORD_LOST] = "LOST",
209 [PERF_RECORD_COMM] = "COMM",
210 [PERF_RECORD_EXIT] = "EXIT",
211 [PERF_RECORD_THROTTLE] = "THROTTLE",
212 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
213 [PERF_RECORD_FORK] = "FORK",
214 [PERF_RECORD_READ] = "READ",
215 [PERF_RECORD_SAMPLE] = "SAMPLE",
216};
217
Tom Zanussi8dc58102010-04-01 23:59:15 -0500218unsigned long event__total[PERF_RECORD_HEADER_MAX];
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200219
220void event__print_totals(void)
221{
222 int i;
Tom Zanussi8dc58102010-04-01 23:59:15 -0500223 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
224 if (!event__name[i])
225 continue;
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200226 pr_info("%10s events: %10ld\n",
227 event__name[i], event__total[i]);
Tom Zanussi8dc58102010-04-01 23:59:15 -0500228 }
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200229}
230
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200231void mem_bswap_64(void *src, int byte_size)
232{
233 u64 *m = src;
234
235 while (byte_size > 0) {
236 *m = bswap_64(*m);
237 byte_size -= sizeof(u64);
238 ++m;
239 }
240}
241
242static void event__all64_swap(event_t *self)
243{
244 struct perf_event_header *hdr = &self->header;
245 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
246}
247
248static void event__comm_swap(event_t *self)
249{
250 self->comm.pid = bswap_32(self->comm.pid);
251 self->comm.tid = bswap_32(self->comm.tid);
252}
253
254static void event__mmap_swap(event_t *self)
255{
256 self->mmap.pid = bswap_32(self->mmap.pid);
257 self->mmap.tid = bswap_32(self->mmap.tid);
258 self->mmap.start = bswap_64(self->mmap.start);
259 self->mmap.len = bswap_64(self->mmap.len);
260 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
261}
262
263static void event__task_swap(event_t *self)
264{
265 self->fork.pid = bswap_32(self->fork.pid);
266 self->fork.tid = bswap_32(self->fork.tid);
267 self->fork.ppid = bswap_32(self->fork.ppid);
268 self->fork.ptid = bswap_32(self->fork.ptid);
269 self->fork.time = bswap_64(self->fork.time);
270}
271
272static void event__read_swap(event_t *self)
273{
274 self->read.pid = bswap_32(self->read.pid);
275 self->read.tid = bswap_32(self->read.tid);
276 self->read.value = bswap_64(self->read.value);
277 self->read.time_enabled = bswap_64(self->read.time_enabled);
278 self->read.time_running = bswap_64(self->read.time_running);
279 self->read.id = bswap_64(self->read.id);
280}
281
282typedef void (*event__swap_op)(event_t *self);
283
284static event__swap_op event__swap_ops[] = {
285 [PERF_RECORD_MMAP] = event__mmap_swap,
286 [PERF_RECORD_COMM] = event__comm_swap,
287 [PERF_RECORD_FORK] = event__task_swap,
288 [PERF_RECORD_EXIT] = event__task_swap,
289 [PERF_RECORD_LOST] = event__all64_swap,
290 [PERF_RECORD_READ] = event__read_swap,
291 [PERF_RECORD_SAMPLE] = event__all64_swap,
Tom Zanussi8dc58102010-04-01 23:59:15 -0500292 [PERF_RECORD_HEADER_MAX] = NULL,
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200293};
294
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200295static int perf_session__process_event(struct perf_session *self,
296 event_t *event,
297 struct perf_event_ops *ops,
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200298 u64 offset, u64 head)
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200299{
300 trace_event(event);
301
Tom Zanussi8dc58102010-04-01 23:59:15 -0500302 if (event->header.type < PERF_RECORD_HEADER_MAX) {
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200303 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
Arnaldo Carvalho de Melo0d755032010-01-14 12:23:09 -0200304 offset + head, event->header.size,
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200305 event__name[event->header.type]);
306 ++event__total[0];
307 ++event__total[event->header.type];
308 }
309
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200310 if (self->header.needs_swap && event__swap_ops[event->header.type])
311 event__swap_ops[event->header.type](event);
312
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200313 switch (event->header.type) {
314 case PERF_RECORD_SAMPLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200315 return ops->sample(event, self);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200316 case PERF_RECORD_MMAP:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200317 return ops->mmap(event, self);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200318 case PERF_RECORD_COMM:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200319 return ops->comm(event, self);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200320 case PERF_RECORD_FORK:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200321 return ops->fork(event, self);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200322 case PERF_RECORD_EXIT:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200323 return ops->exit(event, self);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200324 case PERF_RECORD_LOST:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200325 return ops->lost(event, self);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200326 case PERF_RECORD_READ:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200327 return ops->read(event, self);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200328 case PERF_RECORD_THROTTLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200329 return ops->throttle(event, self);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200330 case PERF_RECORD_UNTHROTTLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200331 return ops->unthrottle(event, self);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200332 default:
Arnaldo Carvalho de Melo31d337c2009-12-27 21:37:03 -0200333 self->unknown_events++;
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200334 return -1;
335 }
336}
337
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200338void perf_event_header__bswap(struct perf_event_header *self)
339{
340 self->type = bswap_32(self->type);
341 self->misc = bswap_16(self->misc);
342 self->size = bswap_16(self->size);
343}
344
345int perf_header__read_build_ids(struct perf_header *self,
346 int input, u64 offset, u64 size)
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200347{
348 struct build_id_event bev;
349 char filename[PATH_MAX];
350 u64 limit = offset + size;
351 int err = -1;
352
353 while (offset < limit) {
354 struct dso *dso;
355 ssize_t len;
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -0200356 struct list_head *head = &dsos__user;
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200357
358 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
359 goto out;
360
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200361 if (self->needs_swap)
362 perf_event_header__bswap(&bev.header);
363
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200364 len = bev.header.size - sizeof(bev);
365 if (read(input, filename, len) != len)
366 goto out;
367
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -0200368 if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
369 head = &dsos__kernel;
370
371 dso = __dsos__findnew(head, filename);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200372 if (dso != NULL) {
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200373 dso__set_build_id(dso, &bev.build_id);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200374 if (head == &dsos__kernel && filename[0] == '[')
375 dso->kernel = 1;
376 }
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200377
378 offset += bev.header.size;
379 }
380 err = 0;
381out:
382 return err;
383}
384
385static struct thread *perf_session__register_idle_thread(struct perf_session *self)
386{
387 struct thread *thread = perf_session__findnew(self, 0);
388
389 if (thread == NULL || thread__set_comm(thread, "swapper")) {
390 pr_err("problem inserting idle task.\n");
391 thread = NULL;
392 }
393
394 return thread;
395}
396
Tom Zanussi8dc58102010-04-01 23:59:15 -0500397int do_read(int fd, void *buf, size_t size)
398{
399 void *buf_start = buf;
400
401 while (size) {
402 int ret = read(fd, buf, size);
403
404 if (ret <= 0)
405 return ret;
406
407 size -= ret;
408 buf += ret;
409 }
410
411 return buf - buf_start;
412}
413
414#define session_done() (*(volatile int *)(&session_done))
415volatile int session_done;
416
417static int __perf_session__process_pipe_events(struct perf_session *self,
418 struct perf_event_ops *ops)
419{
420 event_t event;
421 uint32_t size;
422 int skip = 0;
423 u64 head;
424 int err;
425 void *p;
426
427 perf_event_ops__fill_defaults(ops);
428
429 head = 0;
430more:
431 err = do_read(self->fd, &event, sizeof(struct perf_event_header));
432 if (err <= 0) {
433 if (err == 0)
434 goto done;
435
436 pr_err("failed to read event header\n");
437 goto out_err;
438 }
439
440 if (self->header.needs_swap)
441 perf_event_header__bswap(&event.header);
442
443 size = event.header.size;
444 if (size == 0)
445 size = 8;
446
447 p = &event;
448 p += sizeof(struct perf_event_header);
449
450 err = do_read(self->fd, p, size - sizeof(struct perf_event_header));
451 if (err <= 0) {
452 if (err == 0) {
453 pr_err("unexpected end of event stream\n");
454 goto done;
455 }
456
457 pr_err("failed to read event data\n");
458 goto out_err;
459 }
460
461 if (size == 0 ||
462 (skip = perf_session__process_event(self, &event, ops,
463 0, head)) < 0) {
464 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
465 head, event.header.size, event.header.type);
466 /*
467 * assume we lost track of the stream, check alignment, and
468 * increment a single u64 in the hope to catch on again 'soon'.
469 */
470 if (unlikely(head & 7))
471 head &= ~7ULL;
472
473 size = 8;
474 }
475
476 head += size;
477
478 dump_printf("\n%#Lx [%#x]: event: %d\n",
479 head, event.header.size, event.header.type);
480
481 if (skip > 0)
482 head += skip;
483
484 if (!session_done())
485 goto more;
486done:
487 err = 0;
488out_err:
489 return err;
490}
491
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200492int __perf_session__process_events(struct perf_session *self,
493 u64 data_offset, u64 data_size,
494 u64 file_size, struct perf_event_ops *ops)
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200495{
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200496 int err, mmap_prot, mmap_flags;
497 u64 head, shift;
498 u64 offset = 0;
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200499 size_t page_size;
500 event_t *event;
501 uint32_t size;
502 char *buf;
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300503 struct ui_progress *progress = ui_progress__new("Processing events...",
504 self->size);
505 if (progress == NULL)
506 return -1;
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200507
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200508 perf_event_ops__fill_defaults(ops);
509
Arnaldo Carvalho de Melo1b759622010-01-14 18:30:04 -0200510 page_size = sysconf(_SC_PAGESIZE);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200511
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200512 head = data_offset;
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200513 shift = page_size * (head / page_size);
514 offset += shift;
515 head -= shift;
516
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200517 mmap_prot = PROT_READ;
518 mmap_flags = MAP_SHARED;
519
520 if (self->header.needs_swap) {
521 mmap_prot |= PROT_WRITE;
522 mmap_flags = MAP_PRIVATE;
523 }
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200524remap:
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200525 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
526 mmap_flags, self->fd, offset);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200527 if (buf == MAP_FAILED) {
528 pr_err("failed to mmap file\n");
529 err = -errno;
530 goto out_err;
531 }
532
533more:
534 event = (event_t *)(buf + head);
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300535 ui_progress__update(progress, offset);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200536
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200537 if (self->header.needs_swap)
538 perf_event_header__bswap(&event->header);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200539 size = event->header.size;
540 if (size == 0)
541 size = 8;
542
543 if (head + event->header.size >= page_size * self->mmap_window) {
544 int munmap_ret;
545
546 shift = page_size * (head / page_size);
547
548 munmap_ret = munmap(buf, page_size * self->mmap_window);
549 assert(munmap_ret == 0);
550
551 offset += shift;
552 head -= shift;
553 goto remap;
554 }
555
556 size = event->header.size;
557
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200558 dump_printf("\n%#Lx [%#x]: event: %d\n",
Arnaldo Carvalho de Melo0d755032010-01-14 12:23:09 -0200559 offset + head, event->header.size, event->header.type);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200560
561 if (size == 0 ||
562 perf_session__process_event(self, event, ops, offset, head) < 0) {
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200563 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
Arnaldo Carvalho de Melo0d755032010-01-14 12:23:09 -0200564 offset + head, event->header.size,
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200565 event->header.type);
566 /*
567 * assume we lost track of the stream, check alignment, and
568 * increment a single u64 in the hope to catch on again 'soon'.
569 */
570 if (unlikely(head & 7))
571 head &= ~7ULL;
572
573 size = 8;
574 }
575
576 head += size;
577
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200578 if (offset + head >= data_offset + data_size)
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200579 goto done;
580
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200581 if (offset + head < file_size)
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200582 goto more;
583done:
584 err = 0;
585out_err:
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300586 ui_progress__delete(progress);
Arnaldo Carvalho de Melo06aae5902009-12-27 21:36:59 -0200587 return err;
588}
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200589
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200590int perf_session__process_events(struct perf_session *self,
591 struct perf_event_ops *ops)
592{
593 int err;
594
595 if (perf_session__register_idle_thread(self) == NULL)
596 return -ENOMEM;
597
598 if (!symbol_conf.full_paths) {
599 char bf[PATH_MAX];
600
601 if (getcwd(bf, sizeof(bf)) == NULL) {
602 err = -errno;
603out_getcwd_err:
604 pr_err("failed to get the current directory\n");
605 goto out_err;
606 }
607 self->cwd = strdup(bf);
608 if (self->cwd == NULL) {
609 err = -ENOMEM;
610 goto out_getcwd_err;
611 }
612 self->cwdlen = strlen(self->cwd);
613 }
614
Tom Zanussi8dc58102010-04-01 23:59:15 -0500615 if (!self->fd_pipe)
616 err = __perf_session__process_events(self,
617 self->header.data_offset,
618 self->header.data_size,
619 self->size, ops);
620 else
621 err = __perf_session__process_pipe_events(self, ops);
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200622out_err:
623 return err;
624}
625
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200626bool perf_session__has_traces(struct perf_session *self, const char *msg)
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200627{
628 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200629 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
630 return false;
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200631 }
632
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200633 return true;
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200634}
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200635
636int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
637 const char *symbol_name,
638 u64 addr)
639{
640 char *bracket;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200641 enum map_type i;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200642
643 self->ref_reloc_sym.name = strdup(symbol_name);
644 if (self->ref_reloc_sym.name == NULL)
645 return -ENOMEM;
646
647 bracket = strchr(self->ref_reloc_sym.name, ']');
648 if (bracket)
649 *bracket = '\0';
650
651 self->ref_reloc_sym.addr = addr;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200652
653 for (i = 0; i < MAP__NR_TYPES; ++i) {
654 struct kmap *kmap = map__kmap(self->vmlinux_maps[i]);
655 kmap->ref_reloc_sym = &self->ref_reloc_sym;
656 }
657
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200658 return 0;
659}