diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 422 |
1 files changed, 182 insertions, 240 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 108b0db7bbe..5a72d421e21 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
10 | 10 | ||
11 | #include "evlist.h" | 11 | #include "evlist.h" |
12 | #include "evsel.h" | ||
12 | #include "util.h" | 13 | #include "util.h" |
13 | #include "header.h" | 14 | #include "header.h" |
14 | #include "../perf.h" | 15 | #include "../perf.h" |
@@ -19,89 +20,6 @@ | |||
19 | 20 | ||
20 | static bool no_buildid_cache = false; | 21 | static bool no_buildid_cache = false; |
21 | 22 | ||
22 | /* | ||
23 | * Create new perf.data header attribute: | ||
24 | */ | ||
25 | struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) | ||
26 | { | ||
27 | struct perf_header_attr *self = malloc(sizeof(*self)); | ||
28 | |||
29 | if (self != NULL) { | ||
30 | self->attr = *attr; | ||
31 | self->ids = 0; | ||
32 | self->size = 1; | ||
33 | self->id = malloc(sizeof(u64)); | ||
34 | if (self->id == NULL) { | ||
35 | free(self); | ||
36 | self = NULL; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | return self; | ||
41 | } | ||
42 | |||
43 | void perf_header_attr__delete(struct perf_header_attr *self) | ||
44 | { | ||
45 | free(self->id); | ||
46 | free(self); | ||
47 | } | ||
48 | |||
49 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | ||
50 | { | ||
51 | int pos = self->ids; | ||
52 | |||
53 | self->ids++; | ||
54 | if (self->ids > self->size) { | ||
55 | int nsize = self->size * 2; | ||
56 | u64 *nid = realloc(self->id, nsize * sizeof(u64)); | ||
57 | |||
58 | if (nid == NULL) | ||
59 | return -1; | ||
60 | |||
61 | self->size = nsize; | ||
62 | self->id = nid; | ||
63 | } | ||
64 | self->id[pos] = id; | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | int perf_header__init(struct perf_header *self) | ||
69 | { | ||
70 | self->size = 1; | ||
71 | self->attr = malloc(sizeof(void *)); | ||
72 | return self->attr == NULL ? -ENOMEM : 0; | ||
73 | } | ||
74 | |||
75 | void perf_header__exit(struct perf_header *self) | ||
76 | { | ||
77 | int i; | ||
78 | for (i = 0; i < self->attrs; ++i) | ||
79 | perf_header_attr__delete(self->attr[i]); | ||
80 | free(self->attr); | ||
81 | } | ||
82 | |||
83 | int perf_header__add_attr(struct perf_header *self, | ||
84 | struct perf_header_attr *attr) | ||
85 | { | ||
86 | if (self->frozen) | ||
87 | return -1; | ||
88 | |||
89 | if (self->attrs == self->size) { | ||
90 | int nsize = self->size * 2; | ||
91 | struct perf_header_attr **nattr; | ||
92 | |||
93 | nattr = realloc(self->attr, nsize * sizeof(void *)); | ||
94 | if (nattr == NULL) | ||
95 | return -1; | ||
96 | |||
97 | self->size = nsize; | ||
98 | self->attr = nattr; | ||
99 | } | ||
100 | |||
101 | self->attr[self->attrs++] = attr; | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int event_count; | 23 | static int event_count; |
106 | static struct perf_trace_event_type *events; | 24 | static struct perf_trace_event_type *events; |
107 | 25 | ||
@@ -148,19 +66,19 @@ struct perf_file_attr { | |||
148 | struct perf_file_section ids; | 66 | struct perf_file_section ids; |
149 | }; | 67 | }; |
150 | 68 | ||
151 | void perf_header__set_feat(struct perf_header *self, int feat) | 69 | void perf_header__set_feat(struct perf_header *header, int feat) |
152 | { | 70 | { |
153 | set_bit(feat, self->adds_features); | 71 | set_bit(feat, header->adds_features); |
154 | } | 72 | } |
155 | 73 | ||
156 | void perf_header__clear_feat(struct perf_header *self, int feat) | 74 | void perf_header__clear_feat(struct perf_header *header, int feat) |
157 | { | 75 | { |
158 | clear_bit(feat, self->adds_features); | 76 | clear_bit(feat, header->adds_features); |
159 | } | 77 | } |
160 | 78 | ||
161 | 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) |
162 | { | 80 | { |
163 | return test_bit(feat, self->adds_features); | 81 | return test_bit(feat, header->adds_features); |
164 | } | 82 | } |
165 | 83 | ||
166 | 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) |
@@ -229,22 +147,22 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, | |||
229 | return 0; | 147 | return 0; |
230 | } | 148 | } |
231 | 149 | ||
232 | static int machine__write_buildid_table(struct machine *self, int fd) | 150 | static int machine__write_buildid_table(struct machine *machine, int fd) |
233 | { | 151 | { |
234 | int err; | 152 | int err; |
235 | u16 kmisc = PERF_RECORD_MISC_KERNEL, | 153 | u16 kmisc = PERF_RECORD_MISC_KERNEL, |
236 | umisc = PERF_RECORD_MISC_USER; | 154 | umisc = PERF_RECORD_MISC_USER; |
237 | 155 | ||
238 | if (!machine__is_host(self)) { | 156 | if (!machine__is_host(machine)) { |
239 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; | 157 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; |
240 | umisc = PERF_RECORD_MISC_GUEST_USER; | 158 | umisc = PERF_RECORD_MISC_GUEST_USER; |
241 | } | 159 | } |
242 | 160 | ||
243 | err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid, | 161 | err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, |
244 | kmisc, fd); | 162 | kmisc, fd); |
245 | if (err == 0) | 163 | if (err == 0) |
246 | err = __dsos__write_buildid_table(&self->user_dsos, | 164 | err = __dsos__write_buildid_table(&machine->user_dsos, |
247 | self->pid, umisc, fd); | 165 | machine->pid, umisc, fd); |
248 | return err; | 166 | return err; |
249 | } | 167 | } |
250 | 168 | ||
@@ -362,12 +280,12 @@ out_free: | |||
362 | return err; | 280 | return err; |
363 | } | 281 | } |
364 | 282 | ||
365 | static int dso__cache_build_id(struct dso *self, const char *debugdir) | 283 | static int dso__cache_build_id(struct dso *dso, const char *debugdir) |
366 | { | 284 | { |
367 | bool is_kallsyms = self->kernel && self->long_name[0] != '/'; | 285 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; |
368 | 286 | ||
369 | return build_id_cache__add_b(self->build_id, sizeof(self->build_id), | 287 | return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), |
370 | self->long_name, debugdir, is_kallsyms); | 288 | dso->long_name, debugdir, is_kallsyms); |
371 | } | 289 | } |
372 | 290 | ||
373 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | 291 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) |
@@ -382,14 +300,14 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | |||
382 | return err; | 300 | return err; |
383 | } | 301 | } |
384 | 302 | ||
385 | static int machine__cache_build_ids(struct machine *self, const char *debugdir) | 303 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) |
386 | { | 304 | { |
387 | int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir); | 305 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); |
388 | ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir); | 306 | ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); |
389 | return ret; | 307 | return ret; |
390 | } | 308 | } |
391 | 309 | ||
392 | static int perf_session__cache_build_ids(struct perf_session *self) | 310 | static int perf_session__cache_build_ids(struct perf_session *session) |
393 | { | 311 | { |
394 | struct rb_node *nd; | 312 | struct rb_node *nd; |
395 | int ret; | 313 | int ret; |
@@ -400,28 +318,28 @@ static int perf_session__cache_build_ids(struct perf_session *self) | |||
400 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | 318 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) |
401 | return -1; | 319 | return -1; |
402 | 320 | ||
403 | ret = machine__cache_build_ids(&self->host_machine, debugdir); | 321 | ret = machine__cache_build_ids(&session->host_machine, debugdir); |
404 | 322 | ||
405 | for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { | 323 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { |
406 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 324 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
407 | ret |= machine__cache_build_ids(pos, debugdir); | 325 | ret |= machine__cache_build_ids(pos, debugdir); |
408 | } | 326 | } |
409 | return ret ? -1 : 0; | 327 | return ret ? -1 : 0; |
410 | } | 328 | } |
411 | 329 | ||
412 | static bool machine__read_build_ids(struct machine *self, bool with_hits) | 330 | static bool machine__read_build_ids(struct machine *machine, bool with_hits) |
413 | { | 331 | { |
414 | bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits); | 332 | bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); |
415 | ret |= __dsos__read_build_ids(&self->user_dsos, with_hits); | 333 | ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); |
416 | return ret; | 334 | return ret; |
417 | } | 335 | } |
418 | 336 | ||
419 | static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits) | 337 | static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) |
420 | { | 338 | { |
421 | struct rb_node *nd; | 339 | struct rb_node *nd; |
422 | bool ret = machine__read_build_ids(&self->host_machine, with_hits); | 340 | bool ret = machine__read_build_ids(&session->host_machine, with_hits); |
423 | 341 | ||
424 | for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { | 342 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { |
425 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 343 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
426 | ret |= machine__read_build_ids(pos, with_hits); | 344 | ret |= machine__read_build_ids(pos, with_hits); |
427 | } | 345 | } |
@@ -429,7 +347,7 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi | |||
429 | return ret; | 347 | return ret; |
430 | } | 348 | } |
431 | 349 | ||
432 | static int perf_header__adds_write(struct perf_header *self, | 350 | static int perf_header__adds_write(struct perf_header *header, |
433 | struct perf_evlist *evlist, int fd) | 351 | struct perf_evlist *evlist, int fd) |
434 | { | 352 | { |
435 | int nr_sections; | 353 | int nr_sections; |
@@ -439,13 +357,13 @@ static int perf_header__adds_write(struct perf_header *self, | |||
439 | u64 sec_start; | 357 | u64 sec_start; |
440 | int idx = 0, err; | 358 | int idx = 0, err; |
441 | 359 | ||
442 | session = container_of(self, struct perf_session, header); | 360 | session = container_of(header, struct perf_session, header); |
443 | 361 | ||
444 | if (perf_header__has_feat(self, HEADER_BUILD_ID && | 362 | if (perf_header__has_feat(header, HEADER_BUILD_ID && |
445 | !perf_session__read_build_ids(session, true))) | 363 | !perf_session__read_build_ids(session, true))) |
446 | perf_header__clear_feat(self, HEADER_BUILD_ID); | 364 | perf_header__clear_feat(header, HEADER_BUILD_ID); |
447 | 365 | ||
448 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 366 | nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); |
449 | if (!nr_sections) | 367 | if (!nr_sections) |
450 | return 0; | 368 | return 0; |
451 | 369 | ||
@@ -455,10 +373,10 @@ static int perf_header__adds_write(struct perf_header *self, | |||
455 | 373 | ||
456 | sec_size = sizeof(*feat_sec) * nr_sections; | 374 | sec_size = sizeof(*feat_sec) * nr_sections; |
457 | 375 | ||
458 | sec_start = self->data_offset + self->data_size; | 376 | sec_start = header->data_offset + header->data_size; |
459 | lseek(fd, sec_start + sec_size, SEEK_SET); | 377 | lseek(fd, sec_start + sec_size, SEEK_SET); |
460 | 378 | ||
461 | if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { | 379 | if (perf_header__has_feat(header, HEADER_TRACE_INFO)) { |
462 | struct perf_file_section *trace_sec; | 380 | struct perf_file_section *trace_sec; |
463 | 381 | ||
464 | trace_sec = &feat_sec[idx++]; | 382 | trace_sec = &feat_sec[idx++]; |
@@ -469,14 +387,14 @@ static int perf_header__adds_write(struct perf_header *self, | |||
469 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; | 387 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; |
470 | } | 388 | } |
471 | 389 | ||
472 | if (perf_header__has_feat(self, HEADER_BUILD_ID)) { | 390 | if (perf_header__has_feat(header, HEADER_BUILD_ID)) { |
473 | struct perf_file_section *buildid_sec; | 391 | struct perf_file_section *buildid_sec; |
474 | 392 | ||
475 | buildid_sec = &feat_sec[idx++]; | 393 | buildid_sec = &feat_sec[idx++]; |
476 | 394 | ||
477 | /* Write build-ids */ | 395 | /* Write build-ids */ |
478 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); | 396 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); |
479 | err = dsos__write_buildid_table(self, fd); | 397 | err = dsos__write_buildid_table(header, fd); |
480 | if (err < 0) { | 398 | if (err < 0) { |
481 | pr_debug("failed to write buildid table\n"); | 399 | pr_debug("failed to write buildid table\n"); |
482 | goto out_free; | 400 | goto out_free; |
@@ -515,33 +433,41 @@ int perf_header__write_pipe(int fd) | |||
515 | return 0; | 433 | return 0; |
516 | } | 434 | } |
517 | 435 | ||
518 | int perf_header__write(struct perf_header *self, struct perf_evlist *evlist, | 436 | int perf_session__write_header(struct perf_session *session, |
519 | int fd, bool at_exit) | 437 | struct perf_evlist *evlist, |
438 | int fd, bool at_exit) | ||
520 | { | 439 | { |
521 | struct perf_file_header f_header; | 440 | struct perf_file_header f_header; |
522 | struct perf_file_attr f_attr; | 441 | struct perf_file_attr f_attr; |
523 | struct perf_header_attr *attr; | 442 | struct perf_header *header = &session->header; |
524 | int i, err; | 443 | struct perf_evsel *attr, *pair = NULL; |
444 | int err; | ||
525 | 445 | ||
526 | lseek(fd, sizeof(f_header), SEEK_SET); | 446 | lseek(fd, sizeof(f_header), SEEK_SET); |
527 | 447 | ||
528 | for (i = 0; i < self->attrs; i++) { | 448 | if (session->evlist != evlist) |
529 | attr = self->attr[i]; | 449 | pair = list_entry(session->evlist->entries.next, struct perf_evsel, node); |
530 | 450 | ||
451 | list_for_each_entry(attr, &evlist->entries, node) { | ||
531 | attr->id_offset = lseek(fd, 0, SEEK_CUR); | 452 | attr->id_offset = lseek(fd, 0, SEEK_CUR); |
532 | err = do_write(fd, attr->id, attr->ids * sizeof(u64)); | 453 | err = do_write(fd, attr->id, attr->ids * sizeof(u64)); |
533 | if (err < 0) { | 454 | if (err < 0) { |
455 | out_err_write: | ||
534 | pr_debug("failed to write perf header\n"); | 456 | pr_debug("failed to write perf header\n"); |
535 | return err; | 457 | return err; |
536 | } | 458 | } |
459 | if (session->evlist != evlist) { | ||
460 | err = do_write(fd, pair->id, pair->ids * sizeof(u64)); | ||
461 | if (err < 0) | ||
462 | goto out_err_write; | ||
463 | attr->ids += pair->ids; | ||
464 | pair = list_entry(pair->node.next, struct perf_evsel, node); | ||
465 | } | ||
537 | } | 466 | } |
538 | 467 | ||
468 | header->attr_offset = lseek(fd, 0, SEEK_CUR); | ||
539 | 469 | ||
540 | self->attr_offset = lseek(fd, 0, SEEK_CUR); | 470 | list_for_each_entry(attr, &evlist->entries, node) { |
541 | |||
542 | for (i = 0; i < self->attrs; i++) { | ||
543 | attr = self->attr[i]; | ||
544 | |||
545 | f_attr = (struct perf_file_attr){ | 471 | f_attr = (struct perf_file_attr){ |
546 | .attr = attr->attr, | 472 | .attr = attr->attr, |
547 | .ids = { | 473 | .ids = { |
@@ -556,20 +482,20 @@ int perf_header__write(struct perf_header *self, struct perf_evlist *evlist, | |||
556 | } | 482 | } |
557 | } | 483 | } |
558 | 484 | ||
559 | self->event_offset = lseek(fd, 0, SEEK_CUR); | 485 | header->event_offset = lseek(fd, 0, SEEK_CUR); |
560 | self->event_size = event_count * sizeof(struct perf_trace_event_type); | 486 | header->event_size = event_count * sizeof(struct perf_trace_event_type); |
561 | if (events) { | 487 | if (events) { |
562 | err = do_write(fd, events, self->event_size); | 488 | err = do_write(fd, events, header->event_size); |
563 | if (err < 0) { | 489 | if (err < 0) { |
564 | pr_debug("failed to write perf header events\n"); | 490 | pr_debug("failed to write perf header events\n"); |
565 | return err; | 491 | return err; |
566 | } | 492 | } |
567 | } | 493 | } |
568 | 494 | ||
569 | self->data_offset = lseek(fd, 0, SEEK_CUR); | 495 | header->data_offset = lseek(fd, 0, SEEK_CUR); |
570 | 496 | ||
571 | if (at_exit) { | 497 | if (at_exit) { |
572 | err = perf_header__adds_write(self, evlist, fd); | 498 | err = perf_header__adds_write(header, evlist, fd); |
573 | if (err < 0) | 499 | if (err < 0) |
574 | return err; | 500 | return err; |
575 | } | 501 | } |
@@ -579,20 +505,20 @@ int perf_header__write(struct perf_header *self, struct perf_evlist *evlist, | |||
579 | .size = sizeof(f_header), | 505 | .size = sizeof(f_header), |
580 | .attr_size = sizeof(f_attr), | 506 | .attr_size = sizeof(f_attr), |
581 | .attrs = { | 507 | .attrs = { |
582 | .offset = self->attr_offset, | 508 | .offset = header->attr_offset, |
583 | .size = self->attrs * sizeof(f_attr), | 509 | .size = evlist->nr_entries * sizeof(f_attr), |
584 | }, | 510 | }, |
585 | .data = { | 511 | .data = { |
586 | .offset = self->data_offset, | 512 | .offset = header->data_offset, |
587 | .size = self->data_size, | 513 | .size = header->data_size, |
588 | }, | 514 | }, |
589 | .event_types = { | 515 | .event_types = { |
590 | .offset = self->event_offset, | 516 | .offset = header->event_offset, |
591 | .size = self->event_size, | 517 | .size = header->event_size, |
592 | }, | 518 | }, |
593 | }; | 519 | }; |
594 | 520 | ||
595 | memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); | 521 | memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); |
596 | 522 | ||
597 | lseek(fd, 0, SEEK_SET); | 523 | lseek(fd, 0, SEEK_SET); |
598 | err = do_write(fd, &f_header, sizeof(f_header)); | 524 | err = do_write(fd, &f_header, sizeof(f_header)); |
@@ -600,26 +526,26 @@ int perf_header__write(struct perf_header *self, struct perf_evlist *evlist, | |||
600 | pr_debug("failed to write perf header\n"); | 526 | pr_debug("failed to write perf header\n"); |
601 | return err; | 527 | return err; |
602 | } | 528 | } |
603 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 529 | lseek(fd, header->data_offset + header->data_size, SEEK_SET); |
604 | 530 | ||
605 | self->frozen = 1; | 531 | header->frozen = 1; |
606 | return 0; | 532 | return 0; |
607 | } | 533 | } |
608 | 534 | ||
609 | static int perf_header__getbuffer64(struct perf_header *self, | 535 | static int perf_header__getbuffer64(struct perf_header *header, |
610 | int fd, void *buf, size_t size) | 536 | int fd, void *buf, size_t size) |
611 | { | 537 | { |
612 | if (readn(fd, buf, size) <= 0) | 538 | if (readn(fd, buf, size) <= 0) |
613 | return -1; | 539 | return -1; |
614 | 540 | ||
615 | if (self->needs_swap) | 541 | if (header->needs_swap) |
616 | mem_bswap_64(buf, size); | 542 | mem_bswap_64(buf, size); |
617 | 543 | ||
618 | return 0; | 544 | return 0; |
619 | } | 545 | } |
620 | 546 | ||
621 | int perf_header__process_sections(struct perf_header *self, int fd, | 547 | int perf_header__process_sections(struct perf_header *header, int fd, |
622 | int (*process)(struct perf_file_section *self, | 548 | int (*process)(struct perf_file_section *section, |
623 | struct perf_header *ph, | 549 | struct perf_header *ph, |
624 | int feat, int fd)) | 550 | int feat, int fd)) |
625 | { | 551 | { |
@@ -629,7 +555,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
629 | int idx = 0; | 555 | int idx = 0; |
630 | int err = -1, feat = 1; | 556 | int err = -1, feat = 1; |
631 | 557 | ||
632 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 558 | nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); |
633 | if (!nr_sections) | 559 | if (!nr_sections) |
634 | return 0; | 560 | return 0; |
635 | 561 | ||
@@ -639,17 +565,17 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
639 | 565 | ||
640 | sec_size = sizeof(*feat_sec) * nr_sections; | 566 | sec_size = sizeof(*feat_sec) * nr_sections; |
641 | 567 | ||
642 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 568 | lseek(fd, header->data_offset + header->data_size, SEEK_SET); |
643 | 569 | ||
644 | if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) | 570 | if (perf_header__getbuffer64(header, fd, feat_sec, sec_size)) |
645 | goto out_free; | 571 | goto out_free; |
646 | 572 | ||
647 | err = 0; | 573 | err = 0; |
648 | while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { | 574 | while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { |
649 | if (perf_header__has_feat(self, feat)) { | 575 | if (perf_header__has_feat(header, feat)) { |
650 | struct perf_file_section *sec = &feat_sec[idx++]; | 576 | struct perf_file_section *sec = &feat_sec[idx++]; |
651 | 577 | ||
652 | err = process(sec, self, feat, fd); | 578 | err = process(sec, header, feat, fd); |
653 | if (err < 0) | 579 | if (err < 0) |
654 | break; | 580 | break; |
655 | } | 581 | } |
@@ -660,35 +586,35 @@ out_free: | |||
660 | return err; | 586 | return err; |
661 | } | 587 | } |
662 | 588 | ||
663 | int perf_file_header__read(struct perf_file_header *self, | 589 | int perf_file_header__read(struct perf_file_header *header, |
664 | struct perf_header *ph, int fd) | 590 | struct perf_header *ph, int fd) |
665 | { | 591 | { |
666 | lseek(fd, 0, SEEK_SET); | 592 | lseek(fd, 0, SEEK_SET); |
667 | 593 | ||
668 | if (readn(fd, self, sizeof(*self)) <= 0 || | 594 | if (readn(fd, header, sizeof(*header)) <= 0 || |
669 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | 595 | memcmp(&header->magic, __perf_magic, sizeof(header->magic))) |
670 | return -1; | 596 | return -1; |
671 | 597 | ||
672 | if (self->attr_size != sizeof(struct perf_file_attr)) { | 598 | if (header->attr_size != sizeof(struct perf_file_attr)) { |
673 | u64 attr_size = bswap_64(self->attr_size); | 599 | u64 attr_size = bswap_64(header->attr_size); |
674 | 600 | ||
675 | if (attr_size != sizeof(struct perf_file_attr)) | 601 | if (attr_size != sizeof(struct perf_file_attr)) |
676 | return -1; | 602 | return -1; |
677 | 603 | ||
678 | mem_bswap_64(self, offsetof(struct perf_file_header, | 604 | mem_bswap_64(header, offsetof(struct perf_file_header, |
679 | adds_features)); | 605 | adds_features)); |
680 | ph->needs_swap = true; | 606 | ph->needs_swap = true; |
681 | } | 607 | } |
682 | 608 | ||
683 | if (self->size != sizeof(*self)) { | 609 | if (header->size != sizeof(*header)) { |
684 | /* Support the previous format */ | 610 | /* Support the previous format */ |
685 | if (self->size == offsetof(typeof(*self), adds_features)) | 611 | if (header->size == offsetof(typeof(*header), adds_features)) |
686 | bitmap_zero(self->adds_features, HEADER_FEAT_BITS); | 612 | bitmap_zero(header->adds_features, HEADER_FEAT_BITS); |
687 | else | 613 | else |
688 | return -1; | 614 | return -1; |
689 | } | 615 | } |
690 | 616 | ||
691 | memcpy(&ph->adds_features, &self->adds_features, | 617 | memcpy(&ph->adds_features, &header->adds_features, |
692 | sizeof(ph->adds_features)); | 618 | sizeof(ph->adds_features)); |
693 | /* | 619 | /* |
694 | * FIXME: hack that assumes that if we need swap the perf.data file | 620 | * FIXME: hack that assumes that if we need swap the perf.data file |
@@ -702,10 +628,10 @@ int perf_file_header__read(struct perf_file_header *self, | |||
702 | perf_header__set_feat(ph, HEADER_BUILD_ID); | 628 | perf_header__set_feat(ph, HEADER_BUILD_ID); |
703 | } | 629 | } |
704 | 630 | ||
705 | ph->event_offset = self->event_types.offset; | 631 | ph->event_offset = header->event_types.offset; |
706 | ph->event_size = self->event_types.size; | 632 | ph->event_size = header->event_types.size; |
707 | ph->data_offset = self->data.offset; | 633 | ph->data_offset = header->data.offset; |
708 | ph->data_size = self->data.size; | 634 | ph->data_size = header->data.size; |
709 | return 0; | 635 | return 0; |
710 | } | 636 | } |
711 | 637 | ||
@@ -764,11 +690,10 @@ out: | |||
764 | return err; | 690 | return err; |
765 | } | 691 | } |
766 | 692 | ||
767 | static int perf_header__read_build_ids(struct perf_header *self, | 693 | static int perf_header__read_build_ids(struct perf_header *header, |
768 | int input, u64 offset, u64 size) | 694 | int input, u64 offset, u64 size) |
769 | { | 695 | { |
770 | struct perf_session *session = container_of(self, | 696 | struct perf_session *session = container_of(header, struct perf_session, header); |
771 | struct perf_session, header); | ||
772 | struct build_id_event bev; | 697 | struct build_id_event bev; |
773 | char filename[PATH_MAX]; | 698 | char filename[PATH_MAX]; |
774 | u64 limit = offset + size; | 699 | u64 limit = offset + size; |
@@ -780,7 +705,7 @@ static int perf_header__read_build_ids(struct perf_header *self, | |||
780 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | 705 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) |
781 | goto out; | 706 | goto out; |
782 | 707 | ||
783 | if (self->needs_swap) | 708 | if (header->needs_swap) |
784 | perf_event_header__bswap(&bev.header); | 709 | perf_event_header__bswap(&bev.header); |
785 | 710 | ||
786 | len = bev.header.size - sizeof(bev); | 711 | len = bev.header.size - sizeof(bev); |
@@ -796,13 +721,13 @@ out: | |||
796 | return err; | 721 | return err; |
797 | } | 722 | } |
798 | 723 | ||
799 | static int perf_file_section__process(struct perf_file_section *self, | 724 | static int perf_file_section__process(struct perf_file_section *section, |
800 | struct perf_header *ph, | 725 | struct perf_header *ph, |
801 | int feat, int fd) | 726 | int feat, int fd) |
802 | { | 727 | { |
803 | if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) { | 728 | if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { |
804 | pr_debug("Failed to lseek to %" PRIu64 " offset for feature " | 729 | pr_debug("Failed to lseek to %" PRIu64 " offset for feature " |
805 | "%d, continuing...\n", self->offset, feat); | 730 | "%d, continuing...\n", section->offset, feat); |
806 | return 0; | 731 | return 0; |
807 | } | 732 | } |
808 | 733 | ||
@@ -812,7 +737,7 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
812 | break; | 737 | break; |
813 | 738 | ||
814 | case HEADER_BUILD_ID: | 739 | case HEADER_BUILD_ID: |
815 | if (perf_header__read_build_ids(ph, fd, self->offset, self->size)) | 740 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) |
816 | pr_debug("Failed to read buildids, continuing...\n"); | 741 | pr_debug("Failed to read buildids, continuing...\n"); |
817 | break; | 742 | break; |
818 | default: | 743 | default: |
@@ -822,21 +747,21 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
822 | return 0; | 747 | return 0; |
823 | } | 748 | } |
824 | 749 | ||
825 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, | 750 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, |
826 | struct perf_header *ph, int fd, | 751 | struct perf_header *ph, int fd, |
827 | bool repipe) | 752 | bool repipe) |
828 | { | 753 | { |
829 | if (readn(fd, self, sizeof(*self)) <= 0 || | 754 | if (readn(fd, header, sizeof(*header)) <= 0 || |
830 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | 755 | memcmp(&header->magic, __perf_magic, sizeof(header->magic))) |
831 | return -1; | 756 | return -1; |
832 | 757 | ||
833 | if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0) | 758 | if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) |
834 | return -1; | 759 | return -1; |
835 | 760 | ||
836 | if (self->size != sizeof(*self)) { | 761 | if (header->size != sizeof(*header)) { |
837 | u64 size = bswap_64(self->size); | 762 | u64 size = bswap_64(header->size); |
838 | 763 | ||
839 | if (size != sizeof(*self)) | 764 | if (size != sizeof(*header)) |
840 | return -1; | 765 | return -1; |
841 | 766 | ||
842 | ph->needs_swap = true; | 767 | ph->needs_swap = true; |
@@ -847,10 +772,10 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, | |||
847 | 772 | ||
848 | static int perf_header__read_pipe(struct perf_session *session, int fd) | 773 | static int perf_header__read_pipe(struct perf_session *session, int fd) |
849 | { | 774 | { |
850 | struct perf_header *self = &session->header; | 775 | struct perf_header *header = &session->header; |
851 | struct perf_pipe_file_header f_header; | 776 | struct perf_pipe_file_header f_header; |
852 | 777 | ||
853 | if (perf_file_header__read_pipe(&f_header, self, fd, | 778 | if (perf_file_header__read_pipe(&f_header, header, fd, |
854 | session->repipe) < 0) { | 779 | session->repipe) < 0) { |
855 | pr_debug("incompatible file format\n"); | 780 | pr_debug("incompatible file format\n"); |
856 | return -EINVAL; | 781 | return -EINVAL; |
@@ -861,18 +786,22 @@ static int perf_header__read_pipe(struct perf_session *session, int fd) | |||
861 | return 0; | 786 | return 0; |
862 | } | 787 | } |
863 | 788 | ||
864 | int perf_header__read(struct perf_session *session, int fd) | 789 | int perf_session__read_header(struct perf_session *session, int fd) |
865 | { | 790 | { |
866 | struct perf_header *self = &session->header; | 791 | struct perf_header *header = &session->header; |
867 | struct perf_file_header f_header; | 792 | struct perf_file_header f_header; |
868 | struct perf_file_attr f_attr; | 793 | struct perf_file_attr f_attr; |
869 | u64 f_id; | 794 | u64 f_id; |
870 | int nr_attrs, nr_ids, i, j; | 795 | int nr_attrs, nr_ids, i, j; |
871 | 796 | ||
797 | session->evlist = perf_evlist__new(NULL, NULL); | ||
798 | if (session->evlist == NULL) | ||
799 | return -ENOMEM; | ||
800 | |||
872 | if (session->fd_pipe) | 801 | if (session->fd_pipe) |
873 | return perf_header__read_pipe(session, fd); | 802 | return perf_header__read_pipe(session, fd); |
874 | 803 | ||
875 | if (perf_file_header__read(&f_header, self, fd) < 0) { | 804 | if (perf_file_header__read(&f_header, header, fd) < 0) { |
876 | pr_debug("incompatible file format\n"); | 805 | pr_debug("incompatible file format\n"); |
877 | return -EINVAL; | 806 | return -EINVAL; |
878 | } | 807 | } |
@@ -881,33 +810,39 @@ int perf_header__read(struct perf_session *session, int fd) | |||
881 | lseek(fd, f_header.attrs.offset, SEEK_SET); | 810 | lseek(fd, f_header.attrs.offset, SEEK_SET); |
882 | 811 | ||
883 | for (i = 0; i < nr_attrs; i++) { | 812 | for (i = 0; i < nr_attrs; i++) { |
884 | struct perf_header_attr *attr; | 813 | struct perf_evsel *evsel; |
885 | off_t tmp; | 814 | off_t tmp; |
886 | 815 | ||
887 | if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) | 816 | if (perf_header__getbuffer64(header, fd, &f_attr, sizeof(f_attr))) |
888 | goto out_errno; | 817 | goto out_errno; |
889 | 818 | ||
890 | tmp = lseek(fd, 0, SEEK_CUR); | 819 | tmp = lseek(fd, 0, SEEK_CUR); |
820 | evsel = perf_evsel__new(&f_attr.attr, i); | ||
891 | 821 | ||
892 | attr = perf_header_attr__new(&f_attr.attr); | 822 | if (evsel == NULL) |
893 | if (attr == NULL) | 823 | goto out_delete_evlist; |
894 | return -ENOMEM; | 824 | /* |
825 | * Do it before so that if perf_evsel__alloc_id fails, this | ||
826 | * entry gets purged too at perf_evlist__delete(). | ||
827 | */ | ||
828 | perf_evlist__add(session->evlist, evsel); | ||
895 | 829 | ||
896 | nr_ids = f_attr.ids.size / sizeof(u64); | 830 | nr_ids = f_attr.ids.size / sizeof(u64); |
831 | /* | ||
832 | * We don't have the cpu and thread maps on the header, so | ||
833 | * for allocating the perf_sample_id table we fake 1 cpu and | ||
834 | * hattr->ids threads. | ||
835 | */ | ||
836 | if (perf_evsel__alloc_id(evsel, 1, nr_ids)) | ||
837 | goto out_delete_evlist; | ||
838 | |||
897 | lseek(fd, f_attr.ids.offset, SEEK_SET); | 839 | lseek(fd, f_attr.ids.offset, SEEK_SET); |
898 | 840 | ||
899 | for (j = 0; j < nr_ids; j++) { | 841 | for (j = 0; j < nr_ids; j++) { |
900 | if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) | 842 | if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id))) |
901 | goto out_errno; | 843 | goto out_errno; |
902 | 844 | ||
903 | if (perf_header_attr__add_id(attr, f_id) < 0) { | 845 | perf_evlist__id_add(session->evlist, evsel, 0, j, f_id); |
904 | perf_header_attr__delete(attr); | ||
905 | return -ENOMEM; | ||
906 | } | ||
907 | } | ||
908 | if (perf_header__add_attr(self, attr) < 0) { | ||
909 | perf_header_attr__delete(attr); | ||
910 | return -ENOMEM; | ||
911 | } | 846 | } |
912 | 847 | ||
913 | lseek(fd, tmp, SEEK_SET); | 848 | lseek(fd, tmp, SEEK_SET); |
@@ -918,51 +853,52 @@ int perf_header__read(struct perf_session *session, int fd) | |||
918 | events = malloc(f_header.event_types.size); | 853 | events = malloc(f_header.event_types.size); |
919 | if (events == NULL) | 854 | if (events == NULL) |
920 | return -ENOMEM; | 855 | return -ENOMEM; |
921 | if (perf_header__getbuffer64(self, fd, events, | 856 | if (perf_header__getbuffer64(header, fd, events, |
922 | f_header.event_types.size)) | 857 | f_header.event_types.size)) |
923 | goto out_errno; | 858 | goto out_errno; |
924 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | 859 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); |
925 | } | 860 | } |
926 | 861 | ||
927 | perf_header__process_sections(self, fd, perf_file_section__process); | 862 | perf_header__process_sections(header, fd, perf_file_section__process); |
928 | 863 | ||
929 | lseek(fd, self->data_offset, SEEK_SET); | 864 | lseek(fd, header->data_offset, SEEK_SET); |
930 | 865 | ||
931 | self->frozen = 1; | 866 | header->frozen = 1; |
932 | return 0; | 867 | return 0; |
933 | out_errno: | 868 | out_errno: |
934 | return -errno; | 869 | return -errno; |
870 | |||
871 | out_delete_evlist: | ||
872 | perf_evlist__delete(session->evlist); | ||
873 | session->evlist = NULL; | ||
874 | return -ENOMEM; | ||
935 | } | 875 | } |
936 | 876 | ||
937 | u64 perf_header__sample_type(struct perf_header *header) | 877 | u64 perf_evlist__sample_type(struct perf_evlist *evlist) |
938 | { | 878 | { |
879 | struct perf_evsel *pos; | ||
939 | u64 type = 0; | 880 | u64 type = 0; |
940 | int i; | ||
941 | |||
942 | for (i = 0; i < header->attrs; i++) { | ||
943 | struct perf_header_attr *attr = header->attr[i]; | ||
944 | 881 | ||
882 | list_for_each_entry(pos, &evlist->entries, node) { | ||
945 | if (!type) | 883 | if (!type) |
946 | type = attr->attr.sample_type; | 884 | type = pos->attr.sample_type; |
947 | else if (type != attr->attr.sample_type) | 885 | else if (type != pos->attr.sample_type) |
948 | die("non matching sample_type"); | 886 | die("non matching sample_type"); |
949 | } | 887 | } |
950 | 888 | ||
951 | return type; | 889 | return type; |
952 | } | 890 | } |
953 | 891 | ||
954 | bool perf_header__sample_id_all(const struct perf_header *header) | 892 | bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) |
955 | { | 893 | { |
956 | bool value = false, first = true; | 894 | bool value = false, first = true; |
957 | int i; | 895 | struct perf_evsel *pos; |
958 | |||
959 | for (i = 0; i < header->attrs; i++) { | ||
960 | struct perf_header_attr *attr = header->attr[i]; | ||
961 | 896 | ||
897 | list_for_each_entry(pos, &evlist->entries, node) { | ||
962 | if (first) { | 898 | if (first) { |
963 | value = attr->attr.sample_id_all; | 899 | value = pos->attr.sample_id_all; |
964 | first = false; | 900 | first = false; |
965 | } else if (value != attr->attr.sample_id_all) | 901 | } else if (value != pos->attr.sample_id_all) |
966 | die("non matching sample_id_all"); | 902 | die("non matching sample_id_all"); |
967 | } | 903 | } |
968 | 904 | ||
@@ -1000,16 +936,13 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | |||
1000 | return err; | 936 | return err; |
1001 | } | 937 | } |
1002 | 938 | ||
1003 | int perf_event__synthesize_attrs(struct perf_header *self, | 939 | int perf_session__synthesize_attrs(struct perf_session *session, |
1004 | perf_event__handler_t process, | 940 | perf_event__handler_t process) |
1005 | struct perf_session *session) | ||
1006 | { | 941 | { |
1007 | struct perf_header_attr *attr; | 942 | struct perf_evsel *attr; |
1008 | int i, err = 0; | 943 | int err = 0; |
1009 | |||
1010 | for (i = 0; i < self->attrs; i++) { | ||
1011 | attr = self->attr[i]; | ||
1012 | 944 | ||
945 | list_for_each_entry(attr, &session->evlist->entries, node) { | ||
1013 | err = perf_event__synthesize_attr(&attr->attr, attr->ids, | 946 | err = perf_event__synthesize_attr(&attr->attr, attr->ids, |
1014 | attr->id, process, session); | 947 | attr->id, process, session); |
1015 | if (err) { | 948 | if (err) { |
@@ -1024,27 +957,36 @@ int perf_event__synthesize_attrs(struct perf_header *self, | |||
1024 | int perf_event__process_attr(union perf_event *event, | 957 | int perf_event__process_attr(union perf_event *event, |
1025 | struct perf_session *session) | 958 | struct perf_session *session) |
1026 | { | 959 | { |
1027 | struct perf_header_attr *attr; | ||
1028 | unsigned int i, ids, n_ids; | 960 | unsigned int i, ids, n_ids; |
961 | struct perf_evsel *evsel; | ||
1029 | 962 | ||
1030 | attr = perf_header_attr__new(&event->attr.attr); | 963 | if (session->evlist == NULL) { |
1031 | if (attr == NULL) | 964 | session->evlist = perf_evlist__new(NULL, NULL); |
965 | if (session->evlist == NULL) | ||
966 | return -ENOMEM; | ||
967 | } | ||
968 | |||
969 | evsel = perf_evsel__new(&event->attr.attr, | ||
970 | session->evlist->nr_entries); | ||
971 | if (evsel == NULL) | ||
1032 | return -ENOMEM; | 972 | return -ENOMEM; |
1033 | 973 | ||
974 | perf_evlist__add(session->evlist, evsel); | ||
975 | |||
1034 | ids = event->header.size; | 976 | ids = event->header.size; |
1035 | ids -= (void *)&event->attr.id - (void *)event; | 977 | ids -= (void *)&event->attr.id - (void *)event; |
1036 | n_ids = ids / sizeof(u64); | 978 | n_ids = ids / sizeof(u64); |
979 | /* | ||
980 | * We don't have the cpu and thread maps on the header, so | ||
981 | * for allocating the perf_sample_id table we fake 1 cpu and | ||
982 | * hattr->ids threads. | ||
983 | */ | ||
984 | if (perf_evsel__alloc_id(evsel, 1, n_ids)) | ||
985 | return -ENOMEM; | ||
1037 | 986 | ||
1038 | for (i = 0; i < n_ids; i++) { | 987 | for (i = 0; i < n_ids; i++) { |
1039 | if (perf_header_attr__add_id(attr, event->attr.id[i]) < 0) { | 988 | perf_evlist__id_add(session->evlist, evsel, 0, i, |
1040 | perf_header_attr__delete(attr); | 989 | event->attr.id[i]); |
1041 | return -ENOMEM; | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | if (perf_header__add_attr(&session->header, attr) < 0) { | ||
1046 | perf_header_attr__delete(attr); | ||
1047 | return -ENOMEM; | ||
1048 | } | 990 | } |
1049 | 991 | ||
1050 | perf_session__update_sample_type(session); | 992 | perf_session__update_sample_type(session); |