diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-18 11:19:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-18 11:19:03 -0400 |
commit | 4d7b4ac22fbec1a03206c6cde353f2fd6942f828 (patch) | |
tree | 2d96a9e9c28cf6fa628a278decc00ad55a8b043b /tools/perf/util/header.c | |
parent | 3aaf51ace5975050ab43c7d4d7e439e0ae7d13d7 (diff) | |
parent | 94f3ca95787ada3d64339a4ecb2754236ab563f6 (diff) |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (311 commits)
perf tools: Add mode to build without newt support
perf symbols: symbol inconsistency message should be done only at verbose=1
perf tui: Add explicit -lslang option
perf options: Type check all the remaining OPT_ variants
perf options: Type check OPT_BOOLEAN and fix the offenders
perf options: Check v type in OPT_U?INTEGER
perf options: Introduce OPT_UINTEGER
perf tui: Add workaround for slang < 2.1.4
perf record: Fix bug mismatch with -c option definition
perf options: Introduce OPT_U64
perf tui: Add help window to show key associations
perf tui: Make <- exit menus too
perf newt: Add single key shortcuts for zoom into DSO and threads
perf newt: Exit browser unconditionally when CTRL+C, q or Q is pressed
perf newt: Fix the 'A'/'a' shortcut for annotate
perf newt: Make <- exit the ui_browser
x86, perf: P4 PMU - fix counters management logic
perf newt: Make <- zoom out filters
perf report: Report number of events, not samples
perf hist: Clarify events_stats fields usage
...
Fix up trivial conflicts in kernel/fork.c and tools/perf/builtin-record.c
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 489 |
1 files changed, 447 insertions, 42 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 6c9aa16ee51f..8847bec64c54 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -99,13 +99,6 @@ int perf_header__add_attr(struct perf_header *self, | |||
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
101 | 101 | ||
102 | #define MAX_EVENT_NAME 64 | ||
103 | |||
104 | struct perf_trace_event_type { | ||
105 | u64 event_id; | ||
106 | char name[MAX_EVENT_NAME]; | ||
107 | }; | ||
108 | |||
109 | static int event_count; | 102 | static int event_count; |
110 | static struct perf_trace_event_type *events; | 103 | static struct perf_trace_event_type *events; |
111 | 104 | ||
@@ -197,7 +190,8 @@ static int write_padded(int fd, const void *bf, size_t count, | |||
197 | continue; \ | 190 | continue; \ |
198 | else | 191 | else |
199 | 192 | ||
200 | static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) | 193 | static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, |
194 | u16 misc, int fd) | ||
201 | { | 195 | { |
202 | struct dso *pos; | 196 | struct dso *pos; |
203 | 197 | ||
@@ -212,6 +206,7 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) | |||
212 | len = ALIGN(len, NAME_ALIGN); | 206 | len = ALIGN(len, NAME_ALIGN); |
213 | memset(&b, 0, sizeof(b)); | 207 | memset(&b, 0, sizeof(b)); |
214 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); | 208 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); |
209 | b.pid = pid; | ||
215 | b.header.misc = misc; | 210 | b.header.misc = misc; |
216 | b.header.size = sizeof(b) + len; | 211 | b.header.size = sizeof(b) + len; |
217 | err = do_write(fd, &b, sizeof(b)); | 212 | err = do_write(fd, &b, sizeof(b)); |
@@ -226,13 +221,32 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) | |||
226 | return 0; | 221 | return 0; |
227 | } | 222 | } |
228 | 223 | ||
229 | static int dsos__write_buildid_table(int fd) | 224 | static int dsos__write_buildid_table(struct perf_header *header, int fd) |
230 | { | 225 | { |
231 | int err = __dsos__write_buildid_table(&dsos__kernel, | 226 | struct perf_session *session = container_of(header, |
232 | PERF_RECORD_MISC_KERNEL, fd); | 227 | struct perf_session, header); |
233 | if (err == 0) | 228 | struct rb_node *nd; |
234 | err = __dsos__write_buildid_table(&dsos__user, | 229 | int err = 0; |
235 | PERF_RECORD_MISC_USER, fd); | 230 | u16 kmisc, umisc; |
231 | |||
232 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { | ||
233 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
234 | if (machine__is_host(pos)) { | ||
235 | kmisc = PERF_RECORD_MISC_KERNEL; | ||
236 | umisc = PERF_RECORD_MISC_USER; | ||
237 | } else { | ||
238 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; | ||
239 | umisc = PERF_RECORD_MISC_GUEST_USER; | ||
240 | } | ||
241 | |||
242 | err = __dsos__write_buildid_table(&pos->kernel_dsos, pos->pid, | ||
243 | kmisc, fd); | ||
244 | if (err == 0) | ||
245 | err = __dsos__write_buildid_table(&pos->user_dsos, | ||
246 | pos->pid, umisc, fd); | ||
247 | if (err) | ||
248 | break; | ||
249 | } | ||
236 | return err; | 250 | return err; |
237 | } | 251 | } |
238 | 252 | ||
@@ -349,9 +363,12 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | |||
349 | return err; | 363 | return err; |
350 | } | 364 | } |
351 | 365 | ||
352 | static int dsos__cache_build_ids(void) | 366 | static int dsos__cache_build_ids(struct perf_header *self) |
353 | { | 367 | { |
354 | int err_kernel, err_user; | 368 | struct perf_session *session = container_of(self, |
369 | struct perf_session, header); | ||
370 | struct rb_node *nd; | ||
371 | int ret = 0; | ||
355 | char debugdir[PATH_MAX]; | 372 | char debugdir[PATH_MAX]; |
356 | 373 | ||
357 | snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), | 374 | snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), |
@@ -360,9 +377,28 @@ static int dsos__cache_build_ids(void) | |||
360 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | 377 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) |
361 | return -1; | 378 | return -1; |
362 | 379 | ||
363 | err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir); | 380 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { |
364 | err_user = __dsos__cache_build_ids(&dsos__user, debugdir); | 381 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
365 | return err_kernel || err_user ? -1 : 0; | 382 | ret |= __dsos__cache_build_ids(&pos->kernel_dsos, debugdir); |
383 | ret |= __dsos__cache_build_ids(&pos->user_dsos, debugdir); | ||
384 | } | ||
385 | return ret ? -1 : 0; | ||
386 | } | ||
387 | |||
388 | static bool dsos__read_build_ids(struct perf_header *self, bool with_hits) | ||
389 | { | ||
390 | bool ret = false; | ||
391 | struct perf_session *session = container_of(self, | ||
392 | struct perf_session, header); | ||
393 | struct rb_node *nd; | ||
394 | |||
395 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { | ||
396 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
397 | ret |= __dsos__read_build_ids(&pos->kernel_dsos, with_hits); | ||
398 | ret |= __dsos__read_build_ids(&pos->user_dsos, with_hits); | ||
399 | } | ||
400 | |||
401 | return ret; | ||
366 | } | 402 | } |
367 | 403 | ||
368 | static int perf_header__adds_write(struct perf_header *self, int fd) | 404 | static int perf_header__adds_write(struct perf_header *self, int fd) |
@@ -373,7 +409,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
373 | u64 sec_start; | 409 | u64 sec_start; |
374 | int idx = 0, err; | 410 | int idx = 0, err; |
375 | 411 | ||
376 | if (dsos__read_build_ids(true)) | 412 | if (dsos__read_build_ids(self, true)) |
377 | perf_header__set_feat(self, HEADER_BUILD_ID); | 413 | perf_header__set_feat(self, HEADER_BUILD_ID); |
378 | 414 | ||
379 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 415 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); |
@@ -400,7 +436,6 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
400 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; | 436 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; |
401 | } | 437 | } |
402 | 438 | ||
403 | |||
404 | if (perf_header__has_feat(self, HEADER_BUILD_ID)) { | 439 | if (perf_header__has_feat(self, HEADER_BUILD_ID)) { |
405 | struct perf_file_section *buildid_sec; | 440 | struct perf_file_section *buildid_sec; |
406 | 441 | ||
@@ -408,14 +443,14 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
408 | 443 | ||
409 | /* Write build-ids */ | 444 | /* Write build-ids */ |
410 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); | 445 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); |
411 | err = dsos__write_buildid_table(fd); | 446 | err = dsos__write_buildid_table(self, fd); |
412 | if (err < 0) { | 447 | if (err < 0) { |
413 | pr_debug("failed to write buildid table\n"); | 448 | pr_debug("failed to write buildid table\n"); |
414 | goto out_free; | 449 | goto out_free; |
415 | } | 450 | } |
416 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - | 451 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - |
417 | buildid_sec->offset; | 452 | buildid_sec->offset; |
418 | dsos__cache_build_ids(); | 453 | dsos__cache_build_ids(self); |
419 | } | 454 | } |
420 | 455 | ||
421 | lseek(fd, sec_start, SEEK_SET); | 456 | lseek(fd, sec_start, SEEK_SET); |
@@ -427,6 +462,25 @@ out_free: | |||
427 | return err; | 462 | return err; |
428 | } | 463 | } |
429 | 464 | ||
465 | int perf_header__write_pipe(int fd) | ||
466 | { | ||
467 | struct perf_pipe_file_header f_header; | ||
468 | int err; | ||
469 | |||
470 | f_header = (struct perf_pipe_file_header){ | ||
471 | .magic = PERF_MAGIC, | ||
472 | .size = sizeof(f_header), | ||
473 | }; | ||
474 | |||
475 | err = do_write(fd, &f_header, sizeof(f_header)); | ||
476 | if (err < 0) { | ||
477 | pr_debug("failed to write perf pipe header\n"); | ||
478 | return err; | ||
479 | } | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | |||
430 | int perf_header__write(struct perf_header *self, int fd, bool at_exit) | 484 | int perf_header__write(struct perf_header *self, int fd, bool at_exit) |
431 | { | 485 | { |
432 | struct perf_file_header f_header; | 486 | struct perf_file_header f_header; |
@@ -518,25 +572,10 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) | |||
518 | return 0; | 572 | return 0; |
519 | } | 573 | } |
520 | 574 | ||
521 | static int do_read(int fd, void *buf, size_t size) | ||
522 | { | ||
523 | while (size) { | ||
524 | int ret = read(fd, buf, size); | ||
525 | |||
526 | if (ret <= 0) | ||
527 | return -1; | ||
528 | |||
529 | size -= ret; | ||
530 | buf += ret; | ||
531 | } | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static int perf_header__getbuffer64(struct perf_header *self, | 575 | static int perf_header__getbuffer64(struct perf_header *self, |
537 | int fd, void *buf, size_t size) | 576 | int fd, void *buf, size_t size) |
538 | { | 577 | { |
539 | if (do_read(fd, buf, size)) | 578 | if (do_read(fd, buf, size) <= 0) |
540 | return -1; | 579 | return -1; |
541 | 580 | ||
542 | if (self->needs_swap) | 581 | if (self->needs_swap) |
@@ -592,7 +631,7 @@ int perf_file_header__read(struct perf_file_header *self, | |||
592 | { | 631 | { |
593 | lseek(fd, 0, SEEK_SET); | 632 | lseek(fd, 0, SEEK_SET); |
594 | 633 | ||
595 | if (do_read(fd, self, sizeof(*self)) || | 634 | if (do_read(fd, self, sizeof(*self)) <= 0 || |
596 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | 635 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) |
597 | return -1; | 636 | return -1; |
598 | 637 | ||
@@ -636,6 +675,93 @@ int perf_file_header__read(struct perf_file_header *self, | |||
636 | return 0; | 675 | return 0; |
637 | } | 676 | } |
638 | 677 | ||
678 | static int __event_process_build_id(struct build_id_event *bev, | ||
679 | char *filename, | ||
680 | struct perf_session *session) | ||
681 | { | ||
682 | int err = -1; | ||
683 | struct list_head *head; | ||
684 | struct machine *machine; | ||
685 | u16 misc; | ||
686 | struct dso *dso; | ||
687 | enum dso_kernel_type dso_type; | ||
688 | |||
689 | machine = perf_session__findnew_machine(session, bev->pid); | ||
690 | if (!machine) | ||
691 | goto out; | ||
692 | |||
693 | misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
694 | |||
695 | switch (misc) { | ||
696 | case PERF_RECORD_MISC_KERNEL: | ||
697 | dso_type = DSO_TYPE_KERNEL; | ||
698 | head = &machine->kernel_dsos; | ||
699 | break; | ||
700 | case PERF_RECORD_MISC_GUEST_KERNEL: | ||
701 | dso_type = DSO_TYPE_GUEST_KERNEL; | ||
702 | head = &machine->kernel_dsos; | ||
703 | break; | ||
704 | case PERF_RECORD_MISC_USER: | ||
705 | case PERF_RECORD_MISC_GUEST_USER: | ||
706 | dso_type = DSO_TYPE_USER; | ||
707 | head = &machine->user_dsos; | ||
708 | break; | ||
709 | default: | ||
710 | goto out; | ||
711 | } | ||
712 | |||
713 | dso = __dsos__findnew(head, filename); | ||
714 | if (dso != NULL) { | ||
715 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
716 | |||
717 | dso__set_build_id(dso, &bev->build_id); | ||
718 | |||
719 | if (filename[0] == '[') | ||
720 | dso->kernel = dso_type; | ||
721 | |||
722 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), | ||
723 | sbuild_id); | ||
724 | pr_debug("build id event received for %s: %s\n", | ||
725 | dso->long_name, sbuild_id); | ||
726 | } | ||
727 | |||
728 | err = 0; | ||
729 | out: | ||
730 | return err; | ||
731 | } | ||
732 | |||
733 | static int perf_header__read_build_ids(struct perf_header *self, | ||
734 | int input, u64 offset, u64 size) | ||
735 | { | ||
736 | struct perf_session *session = container_of(self, | ||
737 | struct perf_session, header); | ||
738 | struct build_id_event bev; | ||
739 | char filename[PATH_MAX]; | ||
740 | u64 limit = offset + size; | ||
741 | int err = -1; | ||
742 | |||
743 | while (offset < limit) { | ||
744 | ssize_t len; | ||
745 | |||
746 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | ||
747 | goto out; | ||
748 | |||
749 | if (self->needs_swap) | ||
750 | perf_event_header__bswap(&bev.header); | ||
751 | |||
752 | len = bev.header.size - sizeof(bev); | ||
753 | if (read(input, filename, len) != len) | ||
754 | goto out; | ||
755 | |||
756 | __event_process_build_id(&bev, filename, session); | ||
757 | |||
758 | offset += bev.header.size; | ||
759 | } | ||
760 | err = 0; | ||
761 | out: | ||
762 | return err; | ||
763 | } | ||
764 | |||
639 | static int perf_file_section__process(struct perf_file_section *self, | 765 | static int perf_file_section__process(struct perf_file_section *self, |
640 | struct perf_header *ph, | 766 | struct perf_header *ph, |
641 | int feat, int fd) | 767 | int feat, int fd) |
@@ -648,7 +774,7 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
648 | 774 | ||
649 | switch (feat) { | 775 | switch (feat) { |
650 | case HEADER_TRACE_INFO: | 776 | case HEADER_TRACE_INFO: |
651 | trace_report(fd); | 777 | trace_report(fd, false); |
652 | break; | 778 | break; |
653 | 779 | ||
654 | case HEADER_BUILD_ID: | 780 | case HEADER_BUILD_ID: |
@@ -662,13 +788,56 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
662 | return 0; | 788 | return 0; |
663 | } | 789 | } |
664 | 790 | ||
665 | int perf_header__read(struct perf_header *self, int fd) | 791 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, |
792 | struct perf_header *ph, int fd, | ||
793 | bool repipe) | ||
794 | { | ||
795 | if (do_read(fd, self, sizeof(*self)) <= 0 || | ||
796 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | ||
797 | return -1; | ||
798 | |||
799 | if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0) | ||
800 | return -1; | ||
801 | |||
802 | if (self->size != sizeof(*self)) { | ||
803 | u64 size = bswap_64(self->size); | ||
804 | |||
805 | if (size != sizeof(*self)) | ||
806 | return -1; | ||
807 | |||
808 | ph->needs_swap = true; | ||
809 | } | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int perf_header__read_pipe(struct perf_session *session, int fd) | ||
666 | { | 815 | { |
816 | struct perf_header *self = &session->header; | ||
817 | struct perf_pipe_file_header f_header; | ||
818 | |||
819 | if (perf_file_header__read_pipe(&f_header, self, fd, | ||
820 | session->repipe) < 0) { | ||
821 | pr_debug("incompatible file format\n"); | ||
822 | return -EINVAL; | ||
823 | } | ||
824 | |||
825 | session->fd = fd; | ||
826 | |||
827 | return 0; | ||
828 | } | ||
829 | |||
830 | int perf_header__read(struct perf_session *session, int fd) | ||
831 | { | ||
832 | struct perf_header *self = &session->header; | ||
667 | struct perf_file_header f_header; | 833 | struct perf_file_header f_header; |
668 | struct perf_file_attr f_attr; | 834 | struct perf_file_attr f_attr; |
669 | u64 f_id; | 835 | u64 f_id; |
670 | int nr_attrs, nr_ids, i, j; | 836 | int nr_attrs, nr_ids, i, j; |
671 | 837 | ||
838 | if (session->fd_pipe) | ||
839 | return perf_header__read_pipe(session, fd); | ||
840 | |||
672 | if (perf_file_header__read(&f_header, self, fd) < 0) { | 841 | if (perf_file_header__read(&f_header, self, fd) < 0) { |
673 | pr_debug("incompatible file format\n"); | 842 | pr_debug("incompatible file format\n"); |
674 | return -EINVAL; | 843 | return -EINVAL; |
@@ -753,6 +922,14 @@ perf_header__find_attr(u64 id, struct perf_header *header) | |||
753 | { | 922 | { |
754 | int i; | 923 | int i; |
755 | 924 | ||
925 | /* | ||
926 | * We set id to -1 if the data file doesn't contain sample | ||
927 | * ids. Check for this and avoid walking through the entire | ||
928 | * list of ids which may be large. | ||
929 | */ | ||
930 | if (id == -1ULL) | ||
931 | return NULL; | ||
932 | |||
756 | for (i = 0; i < header->attrs; i++) { | 933 | for (i = 0; i < header->attrs; i++) { |
757 | struct perf_header_attr *attr = header->attr[i]; | 934 | struct perf_header_attr *attr = header->attr[i]; |
758 | int j; | 935 | int j; |
@@ -765,3 +942,231 @@ perf_header__find_attr(u64 id, struct perf_header *header) | |||
765 | 942 | ||
766 | return NULL; | 943 | return NULL; |
767 | } | 944 | } |
945 | |||
946 | int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | ||
947 | event__handler_t process, | ||
948 | struct perf_session *session) | ||
949 | { | ||
950 | event_t *ev; | ||
951 | size_t size; | ||
952 | int err; | ||
953 | |||
954 | size = sizeof(struct perf_event_attr); | ||
955 | size = ALIGN(size, sizeof(u64)); | ||
956 | size += sizeof(struct perf_event_header); | ||
957 | size += ids * sizeof(u64); | ||
958 | |||
959 | ev = malloc(size); | ||
960 | |||
961 | ev->attr.attr = *attr; | ||
962 | memcpy(ev->attr.id, id, ids * sizeof(u64)); | ||
963 | |||
964 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; | ||
965 | ev->attr.header.size = size; | ||
966 | |||
967 | err = process(ev, session); | ||
968 | |||
969 | free(ev); | ||
970 | |||
971 | return err; | ||
972 | } | ||
973 | |||
974 | int event__synthesize_attrs(struct perf_header *self, | ||
975 | event__handler_t process, | ||
976 | struct perf_session *session) | ||
977 | { | ||
978 | struct perf_header_attr *attr; | ||
979 | int i, err = 0; | ||
980 | |||
981 | for (i = 0; i < self->attrs; i++) { | ||
982 | attr = self->attr[i]; | ||
983 | |||
984 | err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, | ||
985 | process, session); | ||
986 | if (err) { | ||
987 | pr_debug("failed to create perf header attribute\n"); | ||
988 | return err; | ||
989 | } | ||
990 | } | ||
991 | |||
992 | return err; | ||
993 | } | ||
994 | |||
995 | int event__process_attr(event_t *self, struct perf_session *session) | ||
996 | { | ||
997 | struct perf_header_attr *attr; | ||
998 | unsigned int i, ids, n_ids; | ||
999 | |||
1000 | attr = perf_header_attr__new(&self->attr.attr); | ||
1001 | if (attr == NULL) | ||
1002 | return -ENOMEM; | ||
1003 | |||
1004 | ids = self->header.size; | ||
1005 | ids -= (void *)&self->attr.id - (void *)self; | ||
1006 | n_ids = ids / sizeof(u64); | ||
1007 | |||
1008 | for (i = 0; i < n_ids; i++) { | ||
1009 | if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { | ||
1010 | perf_header_attr__delete(attr); | ||
1011 | return -ENOMEM; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | if (perf_header__add_attr(&session->header, attr) < 0) { | ||
1016 | perf_header_attr__delete(attr); | ||
1017 | return -ENOMEM; | ||
1018 | } | ||
1019 | |||
1020 | perf_session__update_sample_type(session); | ||
1021 | |||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | int event__synthesize_event_type(u64 event_id, char *name, | ||
1026 | event__handler_t process, | ||
1027 | struct perf_session *session) | ||
1028 | { | ||
1029 | event_t ev; | ||
1030 | size_t size = 0; | ||
1031 | int err = 0; | ||
1032 | |||
1033 | memset(&ev, 0, sizeof(ev)); | ||
1034 | |||
1035 | ev.event_type.event_type.event_id = event_id; | ||
1036 | memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME); | ||
1037 | strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1); | ||
1038 | |||
1039 | ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE; | ||
1040 | size = strlen(name); | ||
1041 | size = ALIGN(size, sizeof(u64)); | ||
1042 | ev.event_type.header.size = sizeof(ev.event_type) - | ||
1043 | (sizeof(ev.event_type.event_type.name) - size); | ||
1044 | |||
1045 | err = process(&ev, session); | ||
1046 | |||
1047 | return err; | ||
1048 | } | ||
1049 | |||
1050 | int event__synthesize_event_types(event__handler_t process, | ||
1051 | struct perf_session *session) | ||
1052 | { | ||
1053 | struct perf_trace_event_type *type; | ||
1054 | int i, err = 0; | ||
1055 | |||
1056 | for (i = 0; i < event_count; i++) { | ||
1057 | type = &events[i]; | ||
1058 | |||
1059 | err = event__synthesize_event_type(type->event_id, type->name, | ||
1060 | process, session); | ||
1061 | if (err) { | ||
1062 | pr_debug("failed to create perf header event type\n"); | ||
1063 | return err; | ||
1064 | } | ||
1065 | } | ||
1066 | |||
1067 | return err; | ||
1068 | } | ||
1069 | |||
1070 | int event__process_event_type(event_t *self, | ||
1071 | struct perf_session *session __unused) | ||
1072 | { | ||
1073 | if (perf_header__push_event(self->event_type.event_type.event_id, | ||
1074 | self->event_type.event_type.name) < 0) | ||
1075 | return -ENOMEM; | ||
1076 | |||
1077 | return 0; | ||
1078 | } | ||
1079 | |||
1080 | int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, | ||
1081 | int nb_events, | ||
1082 | event__handler_t process, | ||
1083 | struct perf_session *session __unused) | ||
1084 | { | ||
1085 | event_t ev; | ||
1086 | ssize_t size = 0, aligned_size = 0, padding; | ||
1087 | int err = 0; | ||
1088 | |||
1089 | memset(&ev, 0, sizeof(ev)); | ||
1090 | |||
1091 | ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; | ||
1092 | size = read_tracing_data_size(fd, pattrs, nb_events); | ||
1093 | if (size <= 0) | ||
1094 | return size; | ||
1095 | aligned_size = ALIGN(size, sizeof(u64)); | ||
1096 | padding = aligned_size - size; | ||
1097 | ev.tracing_data.header.size = sizeof(ev.tracing_data); | ||
1098 | ev.tracing_data.size = aligned_size; | ||
1099 | |||
1100 | process(&ev, session); | ||
1101 | |||
1102 | err = read_tracing_data(fd, pattrs, nb_events); | ||
1103 | write_padded(fd, NULL, 0, padding); | ||
1104 | |||
1105 | return aligned_size; | ||
1106 | } | ||
1107 | |||
1108 | int event__process_tracing_data(event_t *self, | ||
1109 | struct perf_session *session) | ||
1110 | { | ||
1111 | ssize_t size_read, padding, size = self->tracing_data.size; | ||
1112 | off_t offset = lseek(session->fd, 0, SEEK_CUR); | ||
1113 | char buf[BUFSIZ]; | ||
1114 | |||
1115 | /* setup for reading amidst mmap */ | ||
1116 | lseek(session->fd, offset + sizeof(struct tracing_data_event), | ||
1117 | SEEK_SET); | ||
1118 | |||
1119 | size_read = trace_report(session->fd, session->repipe); | ||
1120 | |||
1121 | padding = ALIGN(size_read, sizeof(u64)) - size_read; | ||
1122 | |||
1123 | if (read(session->fd, buf, padding) < 0) | ||
1124 | die("reading input file"); | ||
1125 | if (session->repipe) { | ||
1126 | int retw = write(STDOUT_FILENO, buf, padding); | ||
1127 | if (retw <= 0 || retw != padding) | ||
1128 | die("repiping tracing data padding"); | ||
1129 | } | ||
1130 | |||
1131 | if (size_read + padding != size) | ||
1132 | die("tracing data size mismatch"); | ||
1133 | |||
1134 | return size_read + padding; | ||
1135 | } | ||
1136 | |||
1137 | int event__synthesize_build_id(struct dso *pos, u16 misc, | ||
1138 | event__handler_t process, | ||
1139 | struct machine *machine, | ||
1140 | struct perf_session *session) | ||
1141 | { | ||
1142 | event_t ev; | ||
1143 | size_t len; | ||
1144 | int err = 0; | ||
1145 | |||
1146 | if (!pos->hit) | ||
1147 | return err; | ||
1148 | |||
1149 | memset(&ev, 0, sizeof(ev)); | ||
1150 | |||
1151 | len = pos->long_name_len + 1; | ||
1152 | len = ALIGN(len, NAME_ALIGN); | ||
1153 | memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id)); | ||
1154 | ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; | ||
1155 | ev.build_id.header.misc = misc; | ||
1156 | ev.build_id.pid = machine->pid; | ||
1157 | ev.build_id.header.size = sizeof(ev.build_id) + len; | ||
1158 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); | ||
1159 | |||
1160 | err = process(&ev, session); | ||
1161 | |||
1162 | return err; | ||
1163 | } | ||
1164 | |||
1165 | int event__process_build_id(event_t *self, | ||
1166 | struct perf_session *session) | ||
1167 | { | ||
1168 | __event_process_build_id(&self->build_id, | ||
1169 | self->build_id.filename, | ||
1170 | session); | ||
1171 | return 0; | ||
1172 | } | ||