diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 603 |
1 files changed, 290 insertions, 313 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 989fa2dee2fd..93862a8027ea 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <linux/list.h> | 8 | #include <linux/list.h> |
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
10 | 10 | ||
11 | #include "evlist.h" | ||
12 | #include "evsel.h" | ||
11 | #include "util.h" | 13 | #include "util.h" |
12 | #include "header.h" | 14 | #include "header.h" |
13 | #include "../perf.h" | 15 | #include "../perf.h" |
@@ -18,89 +20,6 @@ | |||
18 | 20 | ||
19 | static bool no_buildid_cache = false; | 21 | static bool no_buildid_cache = false; |
20 | 22 | ||
21 | /* | ||
22 | * Create new perf.data header attribute: | ||
23 | */ | ||
24 | struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) | ||
25 | { | ||
26 | struct perf_header_attr *self = malloc(sizeof(*self)); | ||
27 | |||
28 | if (self != NULL) { | ||
29 | self->attr = *attr; | ||
30 | self->ids = 0; | ||
31 | self->size = 1; | ||
32 | self->id = malloc(sizeof(u64)); | ||
33 | if (self->id == NULL) { | ||
34 | free(self); | ||
35 | self = NULL; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | return self; | ||
40 | } | ||
41 | |||
42 | void perf_header_attr__delete(struct perf_header_attr *self) | ||
43 | { | ||
44 | free(self->id); | ||
45 | free(self); | ||
46 | } | ||
47 | |||
48 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | ||
49 | { | ||
50 | int pos = self->ids; | ||
51 | |||
52 | self->ids++; | ||
53 | if (self->ids > self->size) { | ||
54 | int nsize = self->size * 2; | ||
55 | u64 *nid = realloc(self->id, nsize * sizeof(u64)); | ||
56 | |||
57 | if (nid == NULL) | ||
58 | return -1; | ||
59 | |||
60 | self->size = nsize; | ||
61 | self->id = nid; | ||
62 | } | ||
63 | self->id[pos] = id; | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | int perf_header__init(struct perf_header *self) | ||
68 | { | ||
69 | self->size = 1; | ||
70 | self->attr = malloc(sizeof(void *)); | ||
71 | return self->attr == NULL ? -ENOMEM : 0; | ||
72 | } | ||
73 | |||
74 | void perf_header__exit(struct perf_header *self) | ||
75 | { | ||
76 | int i; | ||
77 | for (i = 0; i < self->attrs; ++i) | ||
78 | perf_header_attr__delete(self->attr[i]); | ||
79 | free(self->attr); | ||
80 | } | ||
81 | |||
82 | int perf_header__add_attr(struct perf_header *self, | ||
83 | struct perf_header_attr *attr) | ||
84 | { | ||
85 | if (self->frozen) | ||
86 | return -1; | ||
87 | |||
88 | if (self->attrs == self->size) { | ||
89 | int nsize = self->size * 2; | ||
90 | struct perf_header_attr **nattr; | ||
91 | |||
92 | nattr = realloc(self->attr, nsize * sizeof(void *)); | ||
93 | if (nattr == NULL) | ||
94 | return -1; | ||
95 | |||
96 | self->size = nsize; | ||
97 | self->attr = nattr; | ||
98 | } | ||
99 | |||
100 | self->attr[self->attrs++] = attr; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int event_count; | 23 | static int event_count; |
105 | static struct perf_trace_event_type *events; | 24 | static struct perf_trace_event_type *events; |
106 | 25 | ||
@@ -147,19 +66,19 @@ struct perf_file_attr { | |||
147 | struct perf_file_section ids; | 66 | struct perf_file_section ids; |
148 | }; | 67 | }; |
149 | 68 | ||
150 | void perf_header__set_feat(struct perf_header *self, int feat) | 69 | void perf_header__set_feat(struct perf_header *header, int feat) |
151 | { | 70 | { |
152 | set_bit(feat, self->adds_features); | 71 | set_bit(feat, header->adds_features); |
153 | } | 72 | } |
154 | 73 | ||
155 | void perf_header__clear_feat(struct perf_header *self, int feat) | 74 | void perf_header__clear_feat(struct perf_header *header, int feat) |
156 | { | 75 | { |
157 | clear_bit(feat, self->adds_features); | 76 | clear_bit(feat, header->adds_features); |
158 | } | 77 | } |
159 | 78 | ||
160 | bool perf_header__has_feat(const struct perf_header *self, int feat) | 79 | bool perf_header__has_feat(const struct perf_header *header, int feat) |
161 | { | 80 | { |
162 | return test_bit(feat, self->adds_features); | 81 | return test_bit(feat, header->adds_features); |
163 | } | 82 | } |
164 | 83 | ||
165 | static int do_write(int fd, const void *buf, size_t size) | 84 | static int do_write(int fd, const void *buf, size_t size) |
@@ -228,22 +147,22 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, | |||
228 | return 0; | 147 | return 0; |
229 | } | 148 | } |
230 | 149 | ||
231 | static int machine__write_buildid_table(struct machine *self, int fd) | 150 | static int machine__write_buildid_table(struct machine *machine, int fd) |
232 | { | 151 | { |
233 | int err; | 152 | int err; |
234 | u16 kmisc = PERF_RECORD_MISC_KERNEL, | 153 | u16 kmisc = PERF_RECORD_MISC_KERNEL, |
235 | umisc = PERF_RECORD_MISC_USER; | 154 | umisc = PERF_RECORD_MISC_USER; |
236 | 155 | ||
237 | if (!machine__is_host(self)) { | 156 | if (!machine__is_host(machine)) { |
238 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; | 157 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; |
239 | umisc = PERF_RECORD_MISC_GUEST_USER; | 158 | umisc = PERF_RECORD_MISC_GUEST_USER; |
240 | } | 159 | } |
241 | 160 | ||
242 | err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid, | 161 | err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, |
243 | kmisc, fd); | 162 | kmisc, fd); |
244 | if (err == 0) | 163 | if (err == 0) |
245 | err = __dsos__write_buildid_table(&self->user_dsos, | 164 | err = __dsos__write_buildid_table(&machine->user_dsos, |
246 | self->pid, umisc, fd); | 165 | machine->pid, umisc, fd); |
247 | return err; | 166 | return err; |
248 | } | 167 | } |
249 | 168 | ||
@@ -270,11 +189,15 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
270 | const char *name, bool is_kallsyms) | 189 | const char *name, bool is_kallsyms) |
271 | { | 190 | { |
272 | const size_t size = PATH_MAX; | 191 | const size_t size = PATH_MAX; |
273 | char *realname = realpath(name, NULL), | 192 | char *realname, *filename = malloc(size), |
274 | *filename = malloc(size), | ||
275 | *linkname = malloc(size), *targetname; | 193 | *linkname = malloc(size), *targetname; |
276 | int len, err = -1; | 194 | int len, err = -1; |
277 | 195 | ||
196 | if (is_kallsyms) | ||
197 | realname = (char *)name; | ||
198 | else | ||
199 | realname = realpath(name, NULL); | ||
200 | |||
278 | if (realname == NULL || filename == NULL || linkname == NULL) | 201 | if (realname == NULL || filename == NULL || linkname == NULL) |
279 | goto out_free; | 202 | goto out_free; |
280 | 203 | ||
@@ -306,7 +229,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
306 | if (symlink(targetname, linkname) == 0) | 229 | if (symlink(targetname, linkname) == 0) |
307 | err = 0; | 230 | err = 0; |
308 | out_free: | 231 | out_free: |
309 | free(realname); | 232 | if (!is_kallsyms) |
233 | free(realname); | ||
310 | free(filename); | 234 | free(filename); |
311 | free(linkname); | 235 | free(linkname); |
312 | return err; | 236 | return err; |
@@ -361,12 +285,12 @@ out_free: | |||
361 | return err; | 285 | return err; |
362 | } | 286 | } |
363 | 287 | ||
364 | static int dso__cache_build_id(struct dso *self, const char *debugdir) | 288 | static int dso__cache_build_id(struct dso *dso, const char *debugdir) |
365 | { | 289 | { |
366 | bool is_kallsyms = self->kernel && self->long_name[0] != '/'; | 290 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; |
367 | 291 | ||
368 | return build_id_cache__add_b(self->build_id, sizeof(self->build_id), | 292 | return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), |
369 | self->long_name, debugdir, is_kallsyms); | 293 | dso->long_name, debugdir, is_kallsyms); |
370 | } | 294 | } |
371 | 295 | ||
372 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | 296 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) |
@@ -381,14 +305,14 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | |||
381 | return err; | 305 | return err; |
382 | } | 306 | } |
383 | 307 | ||
384 | static int machine__cache_build_ids(struct machine *self, const char *debugdir) | 308 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) |
385 | { | 309 | { |
386 | int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir); | 310 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); |
387 | ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir); | 311 | ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); |
388 | return ret; | 312 | return ret; |
389 | } | 313 | } |
390 | 314 | ||
391 | static int perf_session__cache_build_ids(struct perf_session *self) | 315 | static int perf_session__cache_build_ids(struct perf_session *session) |
392 | { | 316 | { |
393 | struct rb_node *nd; | 317 | struct rb_node *nd; |
394 | int ret; | 318 | int ret; |
@@ -399,28 +323,28 @@ static int perf_session__cache_build_ids(struct perf_session *self) | |||
399 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | 323 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) |
400 | return -1; | 324 | return -1; |
401 | 325 | ||
402 | ret = machine__cache_build_ids(&self->host_machine, debugdir); | 326 | ret = machine__cache_build_ids(&session->host_machine, debugdir); |
403 | 327 | ||
404 | for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { | 328 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { |
405 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 329 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
406 | ret |= machine__cache_build_ids(pos, debugdir); | 330 | ret |= machine__cache_build_ids(pos, debugdir); |
407 | } | 331 | } |
408 | return ret ? -1 : 0; | 332 | return ret ? -1 : 0; |
409 | } | 333 | } |
410 | 334 | ||
411 | static bool machine__read_build_ids(struct machine *self, bool with_hits) | 335 | static bool machine__read_build_ids(struct machine *machine, bool with_hits) |
412 | { | 336 | { |
413 | bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits); | 337 | bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); |
414 | ret |= __dsos__read_build_ids(&self->user_dsos, with_hits); | 338 | ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); |
415 | return ret; | 339 | return ret; |
416 | } | 340 | } |
417 | 341 | ||
418 | static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits) | 342 | static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) |
419 | { | 343 | { |
420 | struct rb_node *nd; | 344 | struct rb_node *nd; |
421 | bool ret = machine__read_build_ids(&self->host_machine, with_hits); | 345 | bool ret = machine__read_build_ids(&session->host_machine, with_hits); |
422 | 346 | ||
423 | for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { | 347 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { |
424 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 348 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
425 | ret |= machine__read_build_ids(pos, with_hits); | 349 | ret |= machine__read_build_ids(pos, with_hits); |
426 | } | 350 | } |
@@ -428,7 +352,8 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi | |||
428 | return ret; | 352 | return ret; |
429 | } | 353 | } |
430 | 354 | ||
431 | static int perf_header__adds_write(struct perf_header *self, int fd) | 355 | static int perf_header__adds_write(struct perf_header *header, |
356 | struct perf_evlist *evlist, int fd) | ||
432 | { | 357 | { |
433 | int nr_sections; | 358 | int nr_sections; |
434 | struct perf_session *session; | 359 | struct perf_session *session; |
@@ -437,13 +362,13 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
437 | u64 sec_start; | 362 | u64 sec_start; |
438 | int idx = 0, err; | 363 | int idx = 0, err; |
439 | 364 | ||
440 | session = container_of(self, struct perf_session, header); | 365 | session = container_of(header, struct perf_session, header); |
441 | 366 | ||
442 | if (perf_header__has_feat(self, HEADER_BUILD_ID && | 367 | if (perf_header__has_feat(header, HEADER_BUILD_ID && |
443 | !perf_session__read_build_ids(session, true))) | 368 | !perf_session__read_build_ids(session, true))) |
444 | perf_header__clear_feat(self, HEADER_BUILD_ID); | 369 | perf_header__clear_feat(header, HEADER_BUILD_ID); |
445 | 370 | ||
446 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 371 | nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); |
447 | if (!nr_sections) | 372 | if (!nr_sections) |
448 | return 0; | 373 | return 0; |
449 | 374 | ||
@@ -453,28 +378,28 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
453 | 378 | ||
454 | sec_size = sizeof(*feat_sec) * nr_sections; | 379 | sec_size = sizeof(*feat_sec) * nr_sections; |
455 | 380 | ||
456 | sec_start = self->data_offset + self->data_size; | 381 | sec_start = header->data_offset + header->data_size; |
457 | lseek(fd, sec_start + sec_size, SEEK_SET); | 382 | lseek(fd, sec_start + sec_size, SEEK_SET); |
458 | 383 | ||
459 | if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { | 384 | if (perf_header__has_feat(header, HEADER_TRACE_INFO)) { |
460 | struct perf_file_section *trace_sec; | 385 | struct perf_file_section *trace_sec; |
461 | 386 | ||
462 | trace_sec = &feat_sec[idx++]; | 387 | trace_sec = &feat_sec[idx++]; |
463 | 388 | ||
464 | /* Write trace info */ | 389 | /* Write trace info */ |
465 | trace_sec->offset = lseek(fd, 0, SEEK_CUR); | 390 | trace_sec->offset = lseek(fd, 0, SEEK_CUR); |
466 | read_tracing_data(fd, &evsel_list); | 391 | read_tracing_data(fd, &evlist->entries); |
467 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; | 392 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; |
468 | } | 393 | } |
469 | 394 | ||
470 | if (perf_header__has_feat(self, HEADER_BUILD_ID)) { | 395 | if (perf_header__has_feat(header, HEADER_BUILD_ID)) { |
471 | struct perf_file_section *buildid_sec; | 396 | struct perf_file_section *buildid_sec; |
472 | 397 | ||
473 | buildid_sec = &feat_sec[idx++]; | 398 | buildid_sec = &feat_sec[idx++]; |
474 | 399 | ||
475 | /* Write build-ids */ | 400 | /* Write build-ids */ |
476 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); | 401 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); |
477 | err = dsos__write_buildid_table(self, fd); | 402 | err = dsos__write_buildid_table(header, fd); |
478 | if (err < 0) { | 403 | if (err < 0) { |
479 | pr_debug("failed to write buildid table\n"); | 404 | pr_debug("failed to write buildid table\n"); |
480 | goto out_free; | 405 | goto out_free; |
@@ -513,32 +438,41 @@ int perf_header__write_pipe(int fd) | |||
513 | return 0; | 438 | return 0; |
514 | } | 439 | } |
515 | 440 | ||
516 | int perf_header__write(struct perf_header *self, int fd, bool at_exit) | 441 | int perf_session__write_header(struct perf_session *session, |
442 | struct perf_evlist *evlist, | ||
443 | int fd, bool at_exit) | ||
517 | { | 444 | { |
518 | struct perf_file_header f_header; | 445 | struct perf_file_header f_header; |
519 | struct perf_file_attr f_attr; | 446 | struct perf_file_attr f_attr; |
520 | struct perf_header_attr *attr; | 447 | struct perf_header *header = &session->header; |
521 | int i, err; | 448 | struct perf_evsel *attr, *pair = NULL; |
449 | int err; | ||
522 | 450 | ||
523 | lseek(fd, sizeof(f_header), SEEK_SET); | 451 | lseek(fd, sizeof(f_header), SEEK_SET); |
524 | 452 | ||
525 | for (i = 0; i < self->attrs; i++) { | 453 | if (session->evlist != evlist) |
526 | attr = self->attr[i]; | 454 | pair = list_entry(session->evlist->entries.next, struct perf_evsel, node); |
527 | 455 | ||
456 | list_for_each_entry(attr, &evlist->entries, node) { | ||
528 | attr->id_offset = lseek(fd, 0, SEEK_CUR); | 457 | attr->id_offset = lseek(fd, 0, SEEK_CUR); |
529 | err = do_write(fd, attr->id, attr->ids * sizeof(u64)); | 458 | err = do_write(fd, attr->id, attr->ids * sizeof(u64)); |
530 | if (err < 0) { | 459 | if (err < 0) { |
460 | out_err_write: | ||
531 | pr_debug("failed to write perf header\n"); | 461 | pr_debug("failed to write perf header\n"); |
532 | return err; | 462 | return err; |
533 | } | 463 | } |
464 | if (session->evlist != evlist) { | ||
465 | err = do_write(fd, pair->id, pair->ids * sizeof(u64)); | ||
466 | if (err < 0) | ||
467 | goto out_err_write; | ||
468 | attr->ids += pair->ids; | ||
469 | pair = list_entry(pair->node.next, struct perf_evsel, node); | ||
470 | } | ||
534 | } | 471 | } |
535 | 472 | ||
473 | header->attr_offset = lseek(fd, 0, SEEK_CUR); | ||
536 | 474 | ||
537 | self->attr_offset = lseek(fd, 0, SEEK_CUR); | 475 | list_for_each_entry(attr, &evlist->entries, node) { |
538 | |||
539 | for (i = 0; i < self->attrs; i++) { | ||
540 | attr = self->attr[i]; | ||
541 | |||
542 | f_attr = (struct perf_file_attr){ | 476 | f_attr = (struct perf_file_attr){ |
543 | .attr = attr->attr, | 477 | .attr = attr->attr, |
544 | .ids = { | 478 | .ids = { |
@@ -553,20 +487,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) | |||
553 | } | 487 | } |
554 | } | 488 | } |
555 | 489 | ||
556 | self->event_offset = lseek(fd, 0, SEEK_CUR); | 490 | header->event_offset = lseek(fd, 0, SEEK_CUR); |
557 | self->event_size = event_count * sizeof(struct perf_trace_event_type); | 491 | header->event_size = event_count * sizeof(struct perf_trace_event_type); |
558 | if (events) { | 492 | if (events) { |
559 | err = do_write(fd, events, self->event_size); | 493 | err = do_write(fd, events, header->event_size); |
560 | if (err < 0) { | 494 | if (err < 0) { |
561 | pr_debug("failed to write perf header events\n"); | 495 | pr_debug("failed to write perf header events\n"); |
562 | return err; | 496 | return err; |
563 | } | 497 | } |
564 | } | 498 | } |
565 | 499 | ||
566 | self->data_offset = lseek(fd, 0, SEEK_CUR); | 500 | header->data_offset = lseek(fd, 0, SEEK_CUR); |
567 | 501 | ||
568 | if (at_exit) { | 502 | if (at_exit) { |
569 | err = perf_header__adds_write(self, fd); | 503 | err = perf_header__adds_write(header, evlist, fd); |
570 | if (err < 0) | 504 | if (err < 0) |
571 | return err; | 505 | return err; |
572 | } | 506 | } |
@@ -576,20 +510,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) | |||
576 | .size = sizeof(f_header), | 510 | .size = sizeof(f_header), |
577 | .attr_size = sizeof(f_attr), | 511 | .attr_size = sizeof(f_attr), |
578 | .attrs = { | 512 | .attrs = { |
579 | .offset = self->attr_offset, | 513 | .offset = header->attr_offset, |
580 | .size = self->attrs * sizeof(f_attr), | 514 | .size = evlist->nr_entries * sizeof(f_attr), |
581 | }, | 515 | }, |
582 | .data = { | 516 | .data = { |
583 | .offset = self->data_offset, | 517 | .offset = header->data_offset, |
584 | .size = self->data_size, | 518 | .size = header->data_size, |
585 | }, | 519 | }, |
586 | .event_types = { | 520 | .event_types = { |
587 | .offset = self->event_offset, | 521 | .offset = header->event_offset, |
588 | .size = self->event_size, | 522 | .size = header->event_size, |
589 | }, | 523 | }, |
590 | }; | 524 | }; |
591 | 525 | ||
592 | memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); | 526 | memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); |
593 | 527 | ||
594 | lseek(fd, 0, SEEK_SET); | 528 | lseek(fd, 0, SEEK_SET); |
595 | err = do_write(fd, &f_header, sizeof(f_header)); | 529 | err = do_write(fd, &f_header, sizeof(f_header)); |
@@ -597,26 +531,26 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) | |||
597 | pr_debug("failed to write perf header\n"); | 531 | pr_debug("failed to write perf header\n"); |
598 | return err; | 532 | return err; |
599 | } | 533 | } |
600 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 534 | lseek(fd, header->data_offset + header->data_size, SEEK_SET); |
601 | 535 | ||
602 | self->frozen = 1; | 536 | header->frozen = 1; |
603 | return 0; | 537 | return 0; |
604 | } | 538 | } |
605 | 539 | ||
606 | static int perf_header__getbuffer64(struct perf_header *self, | 540 | static int perf_header__getbuffer64(struct perf_header *header, |
607 | int fd, void *buf, size_t size) | 541 | int fd, void *buf, size_t size) |
608 | { | 542 | { |
609 | if (readn(fd, buf, size) <= 0) | 543 | if (readn(fd, buf, size) <= 0) |
610 | return -1; | 544 | return -1; |
611 | 545 | ||
612 | if (self->needs_swap) | 546 | if (header->needs_swap) |
613 | mem_bswap_64(buf, size); | 547 | mem_bswap_64(buf, size); |
614 | 548 | ||
615 | return 0; | 549 | return 0; |
616 | } | 550 | } |
617 | 551 | ||
618 | int perf_header__process_sections(struct perf_header *self, int fd, | 552 | int perf_header__process_sections(struct perf_header *header, int fd, |
619 | int (*process)(struct perf_file_section *self, | 553 | int (*process)(struct perf_file_section *section, |
620 | struct perf_header *ph, | 554 | struct perf_header *ph, |
621 | int feat, int fd)) | 555 | int feat, int fd)) |
622 | { | 556 | { |
@@ -626,7 +560,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
626 | int idx = 0; | 560 | int idx = 0; |
627 | int err = -1, feat = 1; | 561 | int err = -1, feat = 1; |
628 | 562 | ||
629 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 563 | nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); |
630 | if (!nr_sections) | 564 | if (!nr_sections) |
631 | return 0; | 565 | return 0; |
632 | 566 | ||
@@ -636,17 +570,17 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
636 | 570 | ||
637 | sec_size = sizeof(*feat_sec) * nr_sections; | 571 | sec_size = sizeof(*feat_sec) * nr_sections; |
638 | 572 | ||
639 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 573 | lseek(fd, header->data_offset + header->data_size, SEEK_SET); |
640 | 574 | ||
641 | if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) | 575 | if (perf_header__getbuffer64(header, fd, feat_sec, sec_size)) |
642 | goto out_free; | 576 | goto out_free; |
643 | 577 | ||
644 | err = 0; | 578 | err = 0; |
645 | while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { | 579 | while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { |
646 | if (perf_header__has_feat(self, feat)) { | 580 | if (perf_header__has_feat(header, feat)) { |
647 | struct perf_file_section *sec = &feat_sec[idx++]; | 581 | struct perf_file_section *sec = &feat_sec[idx++]; |
648 | 582 | ||
649 | err = process(sec, self, feat, fd); | 583 | err = process(sec, header, feat, fd); |
650 | if (err < 0) | 584 | if (err < 0) |
651 | break; | 585 | break; |
652 | } | 586 | } |
@@ -657,35 +591,35 @@ out_free: | |||
657 | return err; | 591 | return err; |
658 | } | 592 | } |
659 | 593 | ||
660 | int perf_file_header__read(struct perf_file_header *self, | 594 | int perf_file_header__read(struct perf_file_header *header, |
661 | struct perf_header *ph, int fd) | 595 | struct perf_header *ph, int fd) |
662 | { | 596 | { |
663 | lseek(fd, 0, SEEK_SET); | 597 | lseek(fd, 0, SEEK_SET); |
664 | 598 | ||
665 | if (readn(fd, self, sizeof(*self)) <= 0 || | 599 | if (readn(fd, header, sizeof(*header)) <= 0 || |
666 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | 600 | memcmp(&header->magic, __perf_magic, sizeof(header->magic))) |
667 | return -1; | 601 | return -1; |
668 | 602 | ||
669 | if (self->attr_size != sizeof(struct perf_file_attr)) { | 603 | if (header->attr_size != sizeof(struct perf_file_attr)) { |
670 | u64 attr_size = bswap_64(self->attr_size); | 604 | u64 attr_size = bswap_64(header->attr_size); |
671 | 605 | ||
672 | if (attr_size != sizeof(struct perf_file_attr)) | 606 | if (attr_size != sizeof(struct perf_file_attr)) |
673 | return -1; | 607 | return -1; |
674 | 608 | ||
675 | mem_bswap_64(self, offsetof(struct perf_file_header, | 609 | mem_bswap_64(header, offsetof(struct perf_file_header, |
676 | adds_features)); | 610 | adds_features)); |
677 | ph->needs_swap = true; | 611 | ph->needs_swap = true; |
678 | } | 612 | } |
679 | 613 | ||
680 | if (self->size != sizeof(*self)) { | 614 | if (header->size != sizeof(*header)) { |
681 | /* Support the previous format */ | 615 | /* Support the previous format */ |
682 | if (self->size == offsetof(typeof(*self), adds_features)) | 616 | if (header->size == offsetof(typeof(*header), adds_features)) |
683 | bitmap_zero(self->adds_features, HEADER_FEAT_BITS); | 617 | bitmap_zero(header->adds_features, HEADER_FEAT_BITS); |
684 | else | 618 | else |
685 | return -1; | 619 | return -1; |
686 | } | 620 | } |
687 | 621 | ||
688 | memcpy(&ph->adds_features, &self->adds_features, | 622 | memcpy(&ph->adds_features, &header->adds_features, |
689 | sizeof(ph->adds_features)); | 623 | sizeof(ph->adds_features)); |
690 | /* | 624 | /* |
691 | * FIXME: hack that assumes that if we need swap the perf.data file | 625 | * FIXME: hack that assumes that if we need swap the perf.data file |
@@ -699,10 +633,10 @@ int perf_file_header__read(struct perf_file_header *self, | |||
699 | perf_header__set_feat(ph, HEADER_BUILD_ID); | 633 | perf_header__set_feat(ph, HEADER_BUILD_ID); |
700 | } | 634 | } |
701 | 635 | ||
702 | ph->event_offset = self->event_types.offset; | 636 | ph->event_offset = header->event_types.offset; |
703 | ph->event_size = self->event_types.size; | 637 | ph->event_size = header->event_types.size; |
704 | ph->data_offset = self->data.offset; | 638 | ph->data_offset = header->data.offset; |
705 | ph->data_size = self->data.size; | 639 | ph->data_size = header->data.size; |
706 | return 0; | 640 | return 0; |
707 | } | 641 | } |
708 | 642 | ||
@@ -761,14 +695,50 @@ out: | |||
761 | return err; | 695 | return err; |
762 | } | 696 | } |
763 | 697 | ||
764 | static int perf_header__read_build_ids(struct perf_header *self, | 698 | static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, |
765 | int input, u64 offset, u64 size) | 699 | int input, u64 offset, u64 size) |
766 | { | 700 | { |
767 | struct perf_session *session = container_of(self, | 701 | struct perf_session *session = container_of(header, struct perf_session, header); |
768 | struct perf_session, header); | 702 | struct { |
703 | struct perf_event_header header; | ||
704 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; | ||
705 | char filename[0]; | ||
706 | } old_bev; | ||
769 | struct build_id_event bev; | 707 | struct build_id_event bev; |
770 | char filename[PATH_MAX]; | 708 | char filename[PATH_MAX]; |
771 | u64 limit = offset + size; | 709 | u64 limit = offset + size; |
710 | |||
711 | while (offset < limit) { | ||
712 | ssize_t len; | ||
713 | |||
714 | if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) | ||
715 | return -1; | ||
716 | |||
717 | if (header->needs_swap) | ||
718 | perf_event_header__bswap(&old_bev.header); | ||
719 | |||
720 | len = old_bev.header.size - sizeof(old_bev); | ||
721 | if (read(input, filename, len) != len) | ||
722 | return -1; | ||
723 | |||
724 | bev.header = old_bev.header; | ||
725 | bev.pid = 0; | ||
726 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); | ||
727 | __event_process_build_id(&bev, filename, session); | ||
728 | |||
729 | offset += bev.header.size; | ||
730 | } | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static int perf_header__read_build_ids(struct perf_header *header, | ||
736 | int input, u64 offset, u64 size) | ||
737 | { | ||
738 | struct perf_session *session = container_of(header, struct perf_session, header); | ||
739 | struct build_id_event bev; | ||
740 | char filename[PATH_MAX]; | ||
741 | u64 limit = offset + size, orig_offset = offset; | ||
772 | int err = -1; | 742 | int err = -1; |
773 | 743 | ||
774 | while (offset < limit) { | 744 | while (offset < limit) { |
@@ -777,12 +747,30 @@ static int perf_header__read_build_ids(struct perf_header *self, | |||
777 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | 747 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) |
778 | goto out; | 748 | goto out; |
779 | 749 | ||
780 | if (self->needs_swap) | 750 | if (header->needs_swap) |
781 | perf_event_header__bswap(&bev.header); | 751 | perf_event_header__bswap(&bev.header); |
782 | 752 | ||
783 | len = bev.header.size - sizeof(bev); | 753 | len = bev.header.size - sizeof(bev); |
784 | if (read(input, filename, len) != len) | 754 | if (read(input, filename, len) != len) |
785 | goto out; | 755 | goto out; |
756 | /* | ||
757 | * The a1645ce1 changeset: | ||
758 | * | ||
759 | * "perf: 'perf kvm' tool for monitoring guest performance from host" | ||
760 | * | ||
761 | * Added a field to struct build_id_event that broke the file | ||
762 | * format. | ||
763 | * | ||
764 | * Since the kernel build-id is the first entry, process the | ||
765 | * table using the old format if the well known | ||
766 | * '[kernel.kallsyms]' string for the kernel build-id has the | ||
767 | * first 4 characters chopped off (where the pid_t sits). | ||
768 | */ | ||
769 | if (memcmp(filename, "nel.kallsyms]", 13) == 0) { | ||
770 | if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1) | ||
771 | return -1; | ||
772 | return perf_header__read_build_ids_abi_quirk(header, input, offset, size); | ||
773 | } | ||
786 | 774 | ||
787 | __event_process_build_id(&bev, filename, session); | 775 | __event_process_build_id(&bev, filename, session); |
788 | 776 | ||
@@ -793,13 +781,13 @@ out: | |||
793 | return err; | 781 | return err; |
794 | } | 782 | } |
795 | 783 | ||
796 | static int perf_file_section__process(struct perf_file_section *self, | 784 | static int perf_file_section__process(struct perf_file_section *section, |
797 | struct perf_header *ph, | 785 | struct perf_header *ph, |
798 | int feat, int fd) | 786 | int feat, int fd) |
799 | { | 787 | { |
800 | if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) { | 788 | if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { |
801 | pr_debug("Failed to lseek to %Ld offset for feature %d, " | 789 | pr_debug("Failed to lseek to %" PRIu64 " offset for feature " |
802 | "continuing...\n", self->offset, feat); | 790 | "%d, continuing...\n", section->offset, feat); |
803 | return 0; | 791 | return 0; |
804 | } | 792 | } |
805 | 793 | ||
@@ -809,7 +797,7 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
809 | break; | 797 | break; |
810 | 798 | ||
811 | case HEADER_BUILD_ID: | 799 | case HEADER_BUILD_ID: |
812 | if (perf_header__read_build_ids(ph, fd, self->offset, self->size)) | 800 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) |
813 | pr_debug("Failed to read buildids, continuing...\n"); | 801 | pr_debug("Failed to read buildids, continuing...\n"); |
814 | break; | 802 | break; |
815 | default: | 803 | default: |
@@ -819,21 +807,21 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
819 | return 0; | 807 | return 0; |
820 | } | 808 | } |
821 | 809 | ||
822 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, | 810 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, |
823 | struct perf_header *ph, int fd, | 811 | struct perf_header *ph, int fd, |
824 | bool repipe) | 812 | bool repipe) |
825 | { | 813 | { |
826 | if (readn(fd, self, sizeof(*self)) <= 0 || | 814 | if (readn(fd, header, sizeof(*header)) <= 0 || |
827 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | 815 | memcmp(&header->magic, __perf_magic, sizeof(header->magic))) |
828 | return -1; | 816 | return -1; |
829 | 817 | ||
830 | if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0) | 818 | if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) |
831 | return -1; | 819 | return -1; |
832 | 820 | ||
833 | if (self->size != sizeof(*self)) { | 821 | if (header->size != sizeof(*header)) { |
834 | u64 size = bswap_64(self->size); | 822 | u64 size = bswap_64(header->size); |
835 | 823 | ||
836 | if (size != sizeof(*self)) | 824 | if (size != sizeof(*header)) |
837 | return -1; | 825 | return -1; |
838 | 826 | ||
839 | ph->needs_swap = true; | 827 | ph->needs_swap = true; |
@@ -844,10 +832,10 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, | |||
844 | 832 | ||
845 | static int perf_header__read_pipe(struct perf_session *session, int fd) | 833 | static int perf_header__read_pipe(struct perf_session *session, int fd) |
846 | { | 834 | { |
847 | struct perf_header *self = &session->header; | 835 | struct perf_header *header = &session->header; |
848 | struct perf_pipe_file_header f_header; | 836 | struct perf_pipe_file_header f_header; |
849 | 837 | ||
850 | if (perf_file_header__read_pipe(&f_header, self, fd, | 838 | if (perf_file_header__read_pipe(&f_header, header, fd, |
851 | session->repipe) < 0) { | 839 | session->repipe) < 0) { |
852 | pr_debug("incompatible file format\n"); | 840 | pr_debug("incompatible file format\n"); |
853 | return -EINVAL; | 841 | return -EINVAL; |
@@ -858,18 +846,22 @@ static int perf_header__read_pipe(struct perf_session *session, int fd) | |||
858 | return 0; | 846 | return 0; |
859 | } | 847 | } |
860 | 848 | ||
861 | int perf_header__read(struct perf_session *session, int fd) | 849 | int perf_session__read_header(struct perf_session *session, int fd) |
862 | { | 850 | { |
863 | struct perf_header *self = &session->header; | 851 | struct perf_header *header = &session->header; |
864 | struct perf_file_header f_header; | 852 | struct perf_file_header f_header; |
865 | struct perf_file_attr f_attr; | 853 | struct perf_file_attr f_attr; |
866 | u64 f_id; | 854 | u64 f_id; |
867 | int nr_attrs, nr_ids, i, j; | 855 | int nr_attrs, nr_ids, i, j; |
868 | 856 | ||
857 | session->evlist = perf_evlist__new(NULL, NULL); | ||
858 | if (session->evlist == NULL) | ||
859 | return -ENOMEM; | ||
860 | |||
869 | if (session->fd_pipe) | 861 | if (session->fd_pipe) |
870 | return perf_header__read_pipe(session, fd); | 862 | return perf_header__read_pipe(session, fd); |
871 | 863 | ||
872 | if (perf_file_header__read(&f_header, self, fd) < 0) { | 864 | if (perf_file_header__read(&f_header, header, fd) < 0) { |
873 | pr_debug("incompatible file format\n"); | 865 | pr_debug("incompatible file format\n"); |
874 | return -EINVAL; | 866 | return -EINVAL; |
875 | } | 867 | } |
@@ -878,33 +870,39 @@ int perf_header__read(struct perf_session *session, int fd) | |||
878 | lseek(fd, f_header.attrs.offset, SEEK_SET); | 870 | lseek(fd, f_header.attrs.offset, SEEK_SET); |
879 | 871 | ||
880 | for (i = 0; i < nr_attrs; i++) { | 872 | for (i = 0; i < nr_attrs; i++) { |
881 | struct perf_header_attr *attr; | 873 | struct perf_evsel *evsel; |
882 | off_t tmp; | 874 | off_t tmp; |
883 | 875 | ||
884 | if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) | 876 | if (perf_header__getbuffer64(header, fd, &f_attr, sizeof(f_attr))) |
885 | goto out_errno; | 877 | goto out_errno; |
886 | 878 | ||
887 | tmp = lseek(fd, 0, SEEK_CUR); | 879 | tmp = lseek(fd, 0, SEEK_CUR); |
880 | evsel = perf_evsel__new(&f_attr.attr, i); | ||
888 | 881 | ||
889 | attr = perf_header_attr__new(&f_attr.attr); | 882 | if (evsel == NULL) |
890 | if (attr == NULL) | 883 | goto out_delete_evlist; |
891 | return -ENOMEM; | 884 | /* |
885 | * Do it before so that if perf_evsel__alloc_id fails, this | ||
886 | * entry gets purged too at perf_evlist__delete(). | ||
887 | */ | ||
888 | perf_evlist__add(session->evlist, evsel); | ||
892 | 889 | ||
893 | nr_ids = f_attr.ids.size / sizeof(u64); | 890 | nr_ids = f_attr.ids.size / sizeof(u64); |
891 | /* | ||
892 | * We don't have the cpu and thread maps on the header, so | ||
893 | * for allocating the perf_sample_id table we fake 1 cpu and | ||
894 | * hattr->ids threads. | ||
895 | */ | ||
896 | if (perf_evsel__alloc_id(evsel, 1, nr_ids)) | ||
897 | goto out_delete_evlist; | ||
898 | |||
894 | lseek(fd, f_attr.ids.offset, SEEK_SET); | 899 | lseek(fd, f_attr.ids.offset, SEEK_SET); |
895 | 900 | ||
896 | for (j = 0; j < nr_ids; j++) { | 901 | for (j = 0; j < nr_ids; j++) { |
897 | if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) | 902 | if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id))) |
898 | goto out_errno; | 903 | goto out_errno; |
899 | 904 | ||
900 | if (perf_header_attr__add_id(attr, f_id) < 0) { | 905 | perf_evlist__id_add(session->evlist, evsel, 0, j, f_id); |
901 | perf_header_attr__delete(attr); | ||
902 | return -ENOMEM; | ||
903 | } | ||
904 | } | ||
905 | if (perf_header__add_attr(self, attr) < 0) { | ||
906 | perf_header_attr__delete(attr); | ||
907 | return -ENOMEM; | ||
908 | } | 906 | } |
909 | 907 | ||
910 | lseek(fd, tmp, SEEK_SET); | 908 | lseek(fd, tmp, SEEK_SET); |
@@ -915,93 +913,63 @@ int perf_header__read(struct perf_session *session, int fd) | |||
915 | events = malloc(f_header.event_types.size); | 913 | events = malloc(f_header.event_types.size); |
916 | if (events == NULL) | 914 | if (events == NULL) |
917 | return -ENOMEM; | 915 | return -ENOMEM; |
918 | if (perf_header__getbuffer64(self, fd, events, | 916 | if (perf_header__getbuffer64(header, fd, events, |
919 | f_header.event_types.size)) | 917 | f_header.event_types.size)) |
920 | goto out_errno; | 918 | goto out_errno; |
921 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | 919 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); |
922 | } | 920 | } |
923 | 921 | ||
924 | perf_header__process_sections(self, fd, perf_file_section__process); | 922 | perf_header__process_sections(header, fd, perf_file_section__process); |
925 | 923 | ||
926 | lseek(fd, self->data_offset, SEEK_SET); | 924 | lseek(fd, header->data_offset, SEEK_SET); |
927 | 925 | ||
928 | self->frozen = 1; | 926 | header->frozen = 1; |
929 | return 0; | 927 | return 0; |
930 | out_errno: | 928 | out_errno: |
931 | return -errno; | 929 | return -errno; |
930 | |||
931 | out_delete_evlist: | ||
932 | perf_evlist__delete(session->evlist); | ||
933 | session->evlist = NULL; | ||
934 | return -ENOMEM; | ||
932 | } | 935 | } |
933 | 936 | ||
934 | u64 perf_header__sample_type(struct perf_header *header) | 937 | u64 perf_evlist__sample_type(struct perf_evlist *evlist) |
935 | { | 938 | { |
939 | struct perf_evsel *pos; | ||
936 | u64 type = 0; | 940 | u64 type = 0; |
937 | int i; | ||
938 | |||
939 | for (i = 0; i < header->attrs; i++) { | ||
940 | struct perf_header_attr *attr = header->attr[i]; | ||
941 | 941 | ||
942 | list_for_each_entry(pos, &evlist->entries, node) { | ||
942 | if (!type) | 943 | if (!type) |
943 | type = attr->attr.sample_type; | 944 | type = pos->attr.sample_type; |
944 | else if (type != attr->attr.sample_type) | 945 | else if (type != pos->attr.sample_type) |
945 | die("non matching sample_type"); | 946 | die("non matching sample_type"); |
946 | } | 947 | } |
947 | 948 | ||
948 | return type; | 949 | return type; |
949 | } | 950 | } |
950 | 951 | ||
951 | bool perf_header__sample_id_all(const struct perf_header *header) | 952 | bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) |
952 | { | 953 | { |
953 | bool value = false, first = true; | 954 | bool value = false, first = true; |
954 | int i; | 955 | struct perf_evsel *pos; |
955 | |||
956 | for (i = 0; i < header->attrs; i++) { | ||
957 | struct perf_header_attr *attr = header->attr[i]; | ||
958 | 956 | ||
957 | list_for_each_entry(pos, &evlist->entries, node) { | ||
959 | if (first) { | 958 | if (first) { |
960 | value = attr->attr.sample_id_all; | 959 | value = pos->attr.sample_id_all; |
961 | first = false; | 960 | first = false; |
962 | } else if (value != attr->attr.sample_id_all) | 961 | } else if (value != pos->attr.sample_id_all) |
963 | die("non matching sample_id_all"); | 962 | die("non matching sample_id_all"); |
964 | } | 963 | } |
965 | 964 | ||
966 | return value; | 965 | return value; |
967 | } | 966 | } |
968 | 967 | ||
969 | struct perf_event_attr * | 968 | int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, |
970 | perf_header__find_attr(u64 id, struct perf_header *header) | 969 | perf_event__handler_t process, |
971 | { | 970 | struct perf_session *session) |
972 | int i; | ||
973 | |||
974 | /* | ||
975 | * We set id to -1 if the data file doesn't contain sample | ||
976 | * ids. This can happen when the data file contains one type | ||
977 | * of event and in that case, the header can still store the | ||
978 | * event attribute information. Check for this and avoid | ||
979 | * walking through the entire list of ids which may be large. | ||
980 | */ | ||
981 | if (id == -1ULL) { | ||
982 | if (header->attrs > 0) | ||
983 | return &header->attr[0]->attr; | ||
984 | return NULL; | ||
985 | } | ||
986 | |||
987 | for (i = 0; i < header->attrs; i++) { | ||
988 | struct perf_header_attr *attr = header->attr[i]; | ||
989 | int j; | ||
990 | |||
991 | for (j = 0; j < attr->ids; j++) { | ||
992 | if (attr->id[j] == id) | ||
993 | return &attr->attr; | ||
994 | } | ||
995 | } | ||
996 | |||
997 | return NULL; | ||
998 | } | ||
999 | |||
1000 | int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | ||
1001 | event__handler_t process, | ||
1002 | struct perf_session *session) | ||
1003 | { | 971 | { |
1004 | event_t *ev; | 972 | union perf_event *ev; |
1005 | size_t size; | 973 | size_t size; |
1006 | int err; | 974 | int err; |
1007 | 975 | ||
@@ -1028,17 +996,15 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | |||
1028 | return err; | 996 | return err; |
1029 | } | 997 | } |
1030 | 998 | ||
1031 | int event__synthesize_attrs(struct perf_header *self, event__handler_t process, | 999 | int perf_session__synthesize_attrs(struct perf_session *session, |
1032 | struct perf_session *session) | 1000 | perf_event__handler_t process) |
1033 | { | 1001 | { |
1034 | struct perf_header_attr *attr; | 1002 | struct perf_evsel *attr; |
1035 | int i, err = 0; | 1003 | int err = 0; |
1036 | |||
1037 | for (i = 0; i < self->attrs; i++) { | ||
1038 | attr = self->attr[i]; | ||
1039 | 1004 | ||
1040 | err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, | 1005 | list_for_each_entry(attr, &session->evlist->entries, node) { |
1041 | process, session); | 1006 | err = perf_event__synthesize_attr(&attr->attr, attr->ids, |
1007 | attr->id, process, session); | ||
1042 | if (err) { | 1008 | if (err) { |
1043 | pr_debug("failed to create perf header attribute\n"); | 1009 | pr_debug("failed to create perf header attribute\n"); |
1044 | return err; | 1010 | return err; |
@@ -1048,29 +1014,39 @@ int event__synthesize_attrs(struct perf_header *self, event__handler_t process, | |||
1048 | return err; | 1014 | return err; |
1049 | } | 1015 | } |
1050 | 1016 | ||
1051 | int event__process_attr(event_t *self, struct perf_session *session) | 1017 | int perf_event__process_attr(union perf_event *event, |
1018 | struct perf_session *session) | ||
1052 | { | 1019 | { |
1053 | struct perf_header_attr *attr; | ||
1054 | unsigned int i, ids, n_ids; | 1020 | unsigned int i, ids, n_ids; |
1021 | struct perf_evsel *evsel; | ||
1055 | 1022 | ||
1056 | attr = perf_header_attr__new(&self->attr.attr); | 1023 | if (session->evlist == NULL) { |
1057 | if (attr == NULL) | 1024 | session->evlist = perf_evlist__new(NULL, NULL); |
1025 | if (session->evlist == NULL) | ||
1026 | return -ENOMEM; | ||
1027 | } | ||
1028 | |||
1029 | evsel = perf_evsel__new(&event->attr.attr, | ||
1030 | session->evlist->nr_entries); | ||
1031 | if (evsel == NULL) | ||
1058 | return -ENOMEM; | 1032 | return -ENOMEM; |
1059 | 1033 | ||
1060 | ids = self->header.size; | 1034 | perf_evlist__add(session->evlist, evsel); |
1061 | ids -= (void *)&self->attr.id - (void *)self; | 1035 | |
1036 | ids = event->header.size; | ||
1037 | ids -= (void *)&event->attr.id - (void *)event; | ||
1062 | n_ids = ids / sizeof(u64); | 1038 | n_ids = ids / sizeof(u64); |
1039 | /* | ||
1040 | * We don't have the cpu and thread maps on the header, so | ||
1041 | * for allocating the perf_sample_id table we fake 1 cpu and | ||
1042 | * hattr->ids threads. | ||
1043 | */ | ||
1044 | if (perf_evsel__alloc_id(evsel, 1, n_ids)) | ||
1045 | return -ENOMEM; | ||
1063 | 1046 | ||
1064 | for (i = 0; i < n_ids; i++) { | 1047 | for (i = 0; i < n_ids; i++) { |
1065 | if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { | 1048 | perf_evlist__id_add(session->evlist, evsel, 0, i, |
1066 | perf_header_attr__delete(attr); | 1049 | event->attr.id[i]); |
1067 | return -ENOMEM; | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | if (perf_header__add_attr(&session->header, attr) < 0) { | ||
1072 | perf_header_attr__delete(attr); | ||
1073 | return -ENOMEM; | ||
1074 | } | 1050 | } |
1075 | 1051 | ||
1076 | perf_session__update_sample_type(session); | 1052 | perf_session__update_sample_type(session); |
@@ -1078,11 +1054,11 @@ int event__process_attr(event_t *self, struct perf_session *session) | |||
1078 | return 0; | 1054 | return 0; |
1079 | } | 1055 | } |
1080 | 1056 | ||
1081 | int event__synthesize_event_type(u64 event_id, char *name, | 1057 | int perf_event__synthesize_event_type(u64 event_id, char *name, |
1082 | event__handler_t process, | 1058 | perf_event__handler_t process, |
1083 | struct perf_session *session) | 1059 | struct perf_session *session) |
1084 | { | 1060 | { |
1085 | event_t ev; | 1061 | union perf_event ev; |
1086 | size_t size = 0; | 1062 | size_t size = 0; |
1087 | int err = 0; | 1063 | int err = 0; |
1088 | 1064 | ||
@@ -1103,8 +1079,8 @@ int event__synthesize_event_type(u64 event_id, char *name, | |||
1103 | return err; | 1079 | return err; |
1104 | } | 1080 | } |
1105 | 1081 | ||
1106 | int event__synthesize_event_types(event__handler_t process, | 1082 | int perf_event__synthesize_event_types(perf_event__handler_t process, |
1107 | struct perf_session *session) | 1083 | struct perf_session *session) |
1108 | { | 1084 | { |
1109 | struct perf_trace_event_type *type; | 1085 | struct perf_trace_event_type *type; |
1110 | int i, err = 0; | 1086 | int i, err = 0; |
@@ -1112,8 +1088,9 @@ int event__synthesize_event_types(event__handler_t process, | |||
1112 | for (i = 0; i < event_count; i++) { | 1088 | for (i = 0; i < event_count; i++) { |
1113 | type = &events[i]; | 1089 | type = &events[i]; |
1114 | 1090 | ||
1115 | err = event__synthesize_event_type(type->event_id, type->name, | 1091 | err = perf_event__synthesize_event_type(type->event_id, |
1116 | process, session); | 1092 | type->name, process, |
1093 | session); | ||
1117 | if (err) { | 1094 | if (err) { |
1118 | pr_debug("failed to create perf header event type\n"); | 1095 | pr_debug("failed to create perf header event type\n"); |
1119 | return err; | 1096 | return err; |
@@ -1123,28 +1100,28 @@ int event__synthesize_event_types(event__handler_t process, | |||
1123 | return err; | 1100 | return err; |
1124 | } | 1101 | } |
1125 | 1102 | ||
1126 | int event__process_event_type(event_t *self, | 1103 | int perf_event__process_event_type(union perf_event *event, |
1127 | struct perf_session *session __unused) | 1104 | struct perf_session *session __unused) |
1128 | { | 1105 | { |
1129 | if (perf_header__push_event(self->event_type.event_type.event_id, | 1106 | if (perf_header__push_event(event->event_type.event_type.event_id, |
1130 | self->event_type.event_type.name) < 0) | 1107 | event->event_type.event_type.name) < 0) |
1131 | return -ENOMEM; | 1108 | return -ENOMEM; |
1132 | 1109 | ||
1133 | return 0; | 1110 | return 0; |
1134 | } | 1111 | } |
1135 | 1112 | ||
1136 | int event__synthesize_tracing_data(int fd, struct list_head *pattrs, | 1113 | int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, |
1137 | event__handler_t process, | 1114 | perf_event__handler_t process, |
1138 | struct perf_session *session __unused) | 1115 | struct perf_session *session __unused) |
1139 | { | 1116 | { |
1140 | event_t ev; | 1117 | union perf_event ev; |
1141 | ssize_t size = 0, aligned_size = 0, padding; | 1118 | ssize_t size = 0, aligned_size = 0, padding; |
1142 | int err = 0; | 1119 | int err __used = 0; |
1143 | 1120 | ||
1144 | memset(&ev, 0, sizeof(ev)); | 1121 | memset(&ev, 0, sizeof(ev)); |
1145 | 1122 | ||
1146 | ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; | 1123 | ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; |
1147 | size = read_tracing_data_size(fd, pattrs); | 1124 | size = read_tracing_data_size(fd, &evlist->entries); |
1148 | if (size <= 0) | 1125 | if (size <= 0) |
1149 | return size; | 1126 | return size; |
1150 | aligned_size = ALIGN(size, sizeof(u64)); | 1127 | aligned_size = ALIGN(size, sizeof(u64)); |
@@ -1154,16 +1131,16 @@ int event__synthesize_tracing_data(int fd, struct list_head *pattrs, | |||
1154 | 1131 | ||
1155 | process(&ev, NULL, session); | 1132 | process(&ev, NULL, session); |
1156 | 1133 | ||
1157 | err = read_tracing_data(fd, pattrs); | 1134 | err = read_tracing_data(fd, &evlist->entries); |
1158 | write_padded(fd, NULL, 0, padding); | 1135 | write_padded(fd, NULL, 0, padding); |
1159 | 1136 | ||
1160 | return aligned_size; | 1137 | return aligned_size; |
1161 | } | 1138 | } |
1162 | 1139 | ||
1163 | int event__process_tracing_data(event_t *self, | 1140 | int perf_event__process_tracing_data(union perf_event *event, |
1164 | struct perf_session *session) | 1141 | struct perf_session *session) |
1165 | { | 1142 | { |
1166 | ssize_t size_read, padding, size = self->tracing_data.size; | 1143 | ssize_t size_read, padding, size = event->tracing_data.size; |
1167 | off_t offset = lseek(session->fd, 0, SEEK_CUR); | 1144 | off_t offset = lseek(session->fd, 0, SEEK_CUR); |
1168 | char buf[BUFSIZ]; | 1145 | char buf[BUFSIZ]; |
1169 | 1146 | ||
@@ -1189,12 +1166,12 @@ int event__process_tracing_data(event_t *self, | |||
1189 | return size_read + padding; | 1166 | return size_read + padding; |
1190 | } | 1167 | } |
1191 | 1168 | ||
1192 | int event__synthesize_build_id(struct dso *pos, u16 misc, | 1169 | int perf_event__synthesize_build_id(struct dso *pos, u16 misc, |
1193 | event__handler_t process, | 1170 | perf_event__handler_t process, |
1194 | struct machine *machine, | 1171 | struct machine *machine, |
1195 | struct perf_session *session) | 1172 | struct perf_session *session) |
1196 | { | 1173 | { |
1197 | event_t ev; | 1174 | union perf_event ev; |
1198 | size_t len; | 1175 | size_t len; |
1199 | int err = 0; | 1176 | int err = 0; |
1200 | 1177 | ||
@@ -1217,11 +1194,11 @@ int event__synthesize_build_id(struct dso *pos, u16 misc, | |||
1217 | return err; | 1194 | return err; |
1218 | } | 1195 | } |
1219 | 1196 | ||
1220 | int event__process_build_id(event_t *self, | 1197 | int perf_event__process_build_id(union perf_event *event, |
1221 | struct perf_session *session) | 1198 | struct perf_session *session) |
1222 | { | 1199 | { |
1223 | __event_process_build_id(&self->build_id, | 1200 | __event_process_build_id(&event->build_id, |
1224 | self->build_id.filename, | 1201 | event->build_id.filename, |
1225 | session); | 1202 | session); |
1226 | return 0; | 1203 | return 0; |
1227 | } | 1204 | } |