diff options
-rw-r--r-- | tools/perf/builtin-inject.c | 15 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 15 | ||||
-rw-r--r-- | tools/perf/util/auxtrace.c | 215 | ||||
-rw-r--r-- | tools/perf/util/auxtrace.h | 35 | ||||
-rw-r--r-- | tools/perf/util/header.c | 31 | ||||
-rw-r--r-- | tools/perf/util/session.c | 2 | ||||
-rw-r--r-- | tools/perf/util/session.h | 1 |
7 files changed, 310 insertions, 4 deletions
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index c5f6515f0723..6d4bbde066fd 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -122,6 +122,18 @@ static s64 perf_event__repipe_auxtrace(struct perf_tool *tool, | |||
122 | tool); | 122 | tool); |
123 | int ret; | 123 | int ret; |
124 | 124 | ||
125 | if (!inject->output.is_pipe) { | ||
126 | off_t offset; | ||
127 | |||
128 | offset = lseek(inject->output.fd, 0, SEEK_CUR); | ||
129 | if (offset == -1) | ||
130 | return -errno; | ||
131 | ret = auxtrace_index__auxtrace_event(&session->auxtrace_index, | ||
132 | event, offset); | ||
133 | if (ret < 0) | ||
134 | return ret; | ||
135 | } | ||
136 | |||
125 | if (perf_data_file__is_pipe(session->file) || !session->one_mmap) { | 137 | if (perf_data_file__is_pipe(session->file) || !session->one_mmap) { |
126 | ret = output_bytes(inject, event, event->header.size); | 138 | ret = output_bytes(inject, event, event->header.size); |
127 | if (ret < 0) | 139 | if (ret < 0) |
@@ -487,6 +499,9 @@ static int __cmd_inject(struct perf_inject *inject) | |||
487 | output_data_offset = 4096; | 499 | output_data_offset = 4096; |
488 | } | 500 | } |
489 | 501 | ||
502 | if (!inject->itrace_synth_opts.set) | ||
503 | auxtrace_index__free(&session->auxtrace_index); | ||
504 | |||
490 | if (!file_out->is_pipe) | 505 | if (!file_out->is_pipe) |
491 | lseek(fd, output_data_offset, SEEK_SET); | 506 | lseek(fd, output_data_offset, SEEK_SET); |
492 | 507 | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4c9aaa1f688a..c8c784c430b6 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -117,9 +117,24 @@ static int record__process_auxtrace(struct perf_tool *tool, | |||
117 | size_t len1, void *data2, size_t len2) | 117 | size_t len1, void *data2, size_t len2) |
118 | { | 118 | { |
119 | struct record *rec = container_of(tool, struct record, tool); | 119 | struct record *rec = container_of(tool, struct record, tool); |
120 | struct perf_data_file *file = &rec->file; | ||
120 | size_t padding; | 121 | size_t padding; |
121 | u8 pad[8] = {0}; | 122 | u8 pad[8] = {0}; |
122 | 123 | ||
124 | if (!perf_data_file__is_pipe(file)) { | ||
125 | off_t file_offset; | ||
126 | int fd = perf_data_file__fd(file); | ||
127 | int err; | ||
128 | |||
129 | file_offset = lseek(fd, 0, SEEK_CUR); | ||
130 | if (file_offset == -1) | ||
131 | return -1; | ||
132 | err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index, | ||
133 | event, file_offset); | ||
134 | if (err) | ||
135 | return err; | ||
136 | } | ||
137 | |||
123 | /* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */ | 138 | /* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */ |
124 | padding = (len1 + len2) & 7; | 139 | padding = (len1 + len2) & 7; |
125 | if (padding) | 140 | if (padding) |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 3cd89eca1e88..28ce134a61ad 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -344,6 +344,33 @@ out_err: | |||
344 | return err; | 344 | return err; |
345 | } | 345 | } |
346 | 346 | ||
347 | static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, | ||
348 | struct perf_session *session, | ||
349 | off_t file_offset, size_t sz) | ||
350 | { | ||
351 | union perf_event *event; | ||
352 | int err; | ||
353 | char buf[PERF_SAMPLE_MAX_SIZE]; | ||
354 | |||
355 | err = perf_session__peek_event(session, file_offset, buf, | ||
356 | PERF_SAMPLE_MAX_SIZE, &event, NULL); | ||
357 | if (err) | ||
358 | return err; | ||
359 | |||
360 | if (event->header.type == PERF_RECORD_AUXTRACE) { | ||
361 | if (event->header.size < sizeof(struct auxtrace_event) || | ||
362 | event->header.size != sz) { | ||
363 | err = -EINVAL; | ||
364 | goto out; | ||
365 | } | ||
366 | file_offset += event->header.size; | ||
367 | err = auxtrace_queues__add_event(queues, session, event, | ||
368 | file_offset, NULL); | ||
369 | } | ||
370 | out: | ||
371 | return err; | ||
372 | } | ||
373 | |||
347 | void auxtrace_queues__free(struct auxtrace_queues *queues) | 374 | void auxtrace_queues__free(struct auxtrace_queues *queues) |
348 | { | 375 | { |
349 | unsigned int i; | 376 | unsigned int i; |
@@ -500,6 +527,194 @@ auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) | |||
500 | return NULL; | 527 | return NULL; |
501 | } | 528 | } |
502 | 529 | ||
530 | static int auxtrace_index__alloc(struct list_head *head) | ||
531 | { | ||
532 | struct auxtrace_index *auxtrace_index; | ||
533 | |||
534 | auxtrace_index = malloc(sizeof(struct auxtrace_index)); | ||
535 | if (!auxtrace_index) | ||
536 | return -ENOMEM; | ||
537 | |||
538 | auxtrace_index->nr = 0; | ||
539 | INIT_LIST_HEAD(&auxtrace_index->list); | ||
540 | |||
541 | list_add_tail(&auxtrace_index->list, head); | ||
542 | |||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | void auxtrace_index__free(struct list_head *head) | ||
547 | { | ||
548 | struct auxtrace_index *auxtrace_index, *n; | ||
549 | |||
550 | list_for_each_entry_safe(auxtrace_index, n, head, list) { | ||
551 | list_del(&auxtrace_index->list); | ||
552 | free(auxtrace_index); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | static struct auxtrace_index *auxtrace_index__last(struct list_head *head) | ||
557 | { | ||
558 | struct auxtrace_index *auxtrace_index; | ||
559 | int err; | ||
560 | |||
561 | if (list_empty(head)) { | ||
562 | err = auxtrace_index__alloc(head); | ||
563 | if (err) | ||
564 | return NULL; | ||
565 | } | ||
566 | |||
567 | auxtrace_index = list_entry(head->prev, struct auxtrace_index, list); | ||
568 | |||
569 | if (auxtrace_index->nr >= PERF_AUXTRACE_INDEX_ENTRY_COUNT) { | ||
570 | err = auxtrace_index__alloc(head); | ||
571 | if (err) | ||
572 | return NULL; | ||
573 | auxtrace_index = list_entry(head->prev, struct auxtrace_index, | ||
574 | list); | ||
575 | } | ||
576 | |||
577 | return auxtrace_index; | ||
578 | } | ||
579 | |||
580 | int auxtrace_index__auxtrace_event(struct list_head *head, | ||
581 | union perf_event *event, off_t file_offset) | ||
582 | { | ||
583 | struct auxtrace_index *auxtrace_index; | ||
584 | size_t nr; | ||
585 | |||
586 | auxtrace_index = auxtrace_index__last(head); | ||
587 | if (!auxtrace_index) | ||
588 | return -ENOMEM; | ||
589 | |||
590 | nr = auxtrace_index->nr; | ||
591 | auxtrace_index->entries[nr].file_offset = file_offset; | ||
592 | auxtrace_index->entries[nr].sz = event->header.size; | ||
593 | auxtrace_index->nr += 1; | ||
594 | |||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static int auxtrace_index__do_write(int fd, | ||
599 | struct auxtrace_index *auxtrace_index) | ||
600 | { | ||
601 | struct auxtrace_index_entry ent; | ||
602 | size_t i; | ||
603 | |||
604 | for (i = 0; i < auxtrace_index->nr; i++) { | ||
605 | ent.file_offset = auxtrace_index->entries[i].file_offset; | ||
606 | ent.sz = auxtrace_index->entries[i].sz; | ||
607 | if (writen(fd, &ent, sizeof(ent)) != sizeof(ent)) | ||
608 | return -errno; | ||
609 | } | ||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | int auxtrace_index__write(int fd, struct list_head *head) | ||
614 | { | ||
615 | struct auxtrace_index *auxtrace_index; | ||
616 | u64 total = 0; | ||
617 | int err; | ||
618 | |||
619 | list_for_each_entry(auxtrace_index, head, list) | ||
620 | total += auxtrace_index->nr; | ||
621 | |||
622 | if (writen(fd, &total, sizeof(total)) != sizeof(total)) | ||
623 | return -errno; | ||
624 | |||
625 | list_for_each_entry(auxtrace_index, head, list) { | ||
626 | err = auxtrace_index__do_write(fd, auxtrace_index); | ||
627 | if (err) | ||
628 | return err; | ||
629 | } | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static int auxtrace_index__process_entry(int fd, struct list_head *head, | ||
635 | bool needs_swap) | ||
636 | { | ||
637 | struct auxtrace_index *auxtrace_index; | ||
638 | struct auxtrace_index_entry ent; | ||
639 | size_t nr; | ||
640 | |||
641 | if (readn(fd, &ent, sizeof(ent)) != sizeof(ent)) | ||
642 | return -1; | ||
643 | |||
644 | auxtrace_index = auxtrace_index__last(head); | ||
645 | if (!auxtrace_index) | ||
646 | return -1; | ||
647 | |||
648 | nr = auxtrace_index->nr; | ||
649 | if (needs_swap) { | ||
650 | auxtrace_index->entries[nr].file_offset = | ||
651 | bswap_64(ent.file_offset); | ||
652 | auxtrace_index->entries[nr].sz = bswap_64(ent.sz); | ||
653 | } else { | ||
654 | auxtrace_index->entries[nr].file_offset = ent.file_offset; | ||
655 | auxtrace_index->entries[nr].sz = ent.sz; | ||
656 | } | ||
657 | |||
658 | auxtrace_index->nr = nr + 1; | ||
659 | |||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | int auxtrace_index__process(int fd, u64 size, struct perf_session *session, | ||
664 | bool needs_swap) | ||
665 | { | ||
666 | struct list_head *head = &session->auxtrace_index; | ||
667 | u64 nr; | ||
668 | |||
669 | if (readn(fd, &nr, sizeof(u64)) != sizeof(u64)) | ||
670 | return -1; | ||
671 | |||
672 | if (needs_swap) | ||
673 | nr = bswap_64(nr); | ||
674 | |||
675 | if (sizeof(u64) + nr * sizeof(struct auxtrace_index_entry) > size) | ||
676 | return -1; | ||
677 | |||
678 | while (nr--) { | ||
679 | int err; | ||
680 | |||
681 | err = auxtrace_index__process_entry(fd, head, needs_swap); | ||
682 | if (err) | ||
683 | return -1; | ||
684 | } | ||
685 | |||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | static int auxtrace_queues__process_index_entry(struct auxtrace_queues *queues, | ||
690 | struct perf_session *session, | ||
691 | struct auxtrace_index_entry *ent) | ||
692 | { | ||
693 | return auxtrace_queues__add_indexed_event(queues, session, | ||
694 | ent->file_offset, ent->sz); | ||
695 | } | ||
696 | |||
697 | int auxtrace_queues__process_index(struct auxtrace_queues *queues, | ||
698 | struct perf_session *session) | ||
699 | { | ||
700 | struct auxtrace_index *auxtrace_index; | ||
701 | struct auxtrace_index_entry *ent; | ||
702 | size_t i; | ||
703 | int err; | ||
704 | |||
705 | list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) { | ||
706 | for (i = 0; i < auxtrace_index->nr; i++) { | ||
707 | ent = &auxtrace_index->entries[i]; | ||
708 | err = auxtrace_queues__process_index_entry(queues, | ||
709 | session, | ||
710 | ent); | ||
711 | if (err) | ||
712 | return err; | ||
713 | } | ||
714 | } | ||
715 | return 0; | ||
716 | } | ||
717 | |||
503 | struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, | 718 | struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, |
504 | struct auxtrace_buffer *buffer) | 719 | struct auxtrace_buffer *buffer) |
505 | { | 720 | { |
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 53b60a64a693..b9e4b9d66f5e 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
@@ -80,6 +80,32 @@ struct itrace_synth_opts { | |||
80 | }; | 80 | }; |
81 | 81 | ||
82 | /** | 82 | /** |
83 | * struct auxtrace_index_entry - indexes a AUX area tracing event within a | ||
84 | * perf.data file. | ||
85 | * @file_offset: offset within the perf.data file | ||
86 | * @sz: size of the event | ||
87 | */ | ||
88 | struct auxtrace_index_entry { | ||
89 | u64 file_offset; | ||
90 | u64 sz; | ||
91 | }; | ||
92 | |||
93 | #define PERF_AUXTRACE_INDEX_ENTRY_COUNT 256 | ||
94 | |||
95 | /** | ||
96 | * struct auxtrace_index - index of AUX area tracing events within a perf.data | ||
97 | * file. | ||
98 | * @list: linking a number of arrays of entries | ||
99 | * @nr: number of entries | ||
100 | * @entries: array of entries | ||
101 | */ | ||
102 | struct auxtrace_index { | ||
103 | struct list_head list; | ||
104 | size_t nr; | ||
105 | struct auxtrace_index_entry entries[PERF_AUXTRACE_INDEX_ENTRY_COUNT]; | ||
106 | }; | ||
107 | |||
108 | /** | ||
83 | * struct auxtrace - session callbacks to allow AUX area data decoding. | 109 | * struct auxtrace - session callbacks to allow AUX area data decoding. |
84 | * @process_event: lets the decoder see all session events | 110 | * @process_event: lets the decoder see all session events |
85 | * @flush_events: process any remaining data | 111 | * @flush_events: process any remaining data |
@@ -321,6 +347,8 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues, | |||
321 | union perf_event *event, off_t data_offset, | 347 | union perf_event *event, off_t data_offset, |
322 | struct auxtrace_buffer **buffer_ptr); | 348 | struct auxtrace_buffer **buffer_ptr); |
323 | void auxtrace_queues__free(struct auxtrace_queues *queues); | 349 | void auxtrace_queues__free(struct auxtrace_queues *queues); |
350 | int auxtrace_queues__process_index(struct auxtrace_queues *queues, | ||
351 | struct perf_session *session); | ||
324 | struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, | 352 | struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, |
325 | struct auxtrace_buffer *buffer); | 353 | struct auxtrace_buffer *buffer); |
326 | void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd); | 354 | void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd); |
@@ -361,6 +389,13 @@ int auxtrace_record__info_fill(struct auxtrace_record *itr, | |||
361 | void auxtrace_record__free(struct auxtrace_record *itr); | 389 | void auxtrace_record__free(struct auxtrace_record *itr); |
362 | u64 auxtrace_record__reference(struct auxtrace_record *itr); | 390 | u64 auxtrace_record__reference(struct auxtrace_record *itr); |
363 | 391 | ||
392 | int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event, | ||
393 | off_t file_offset); | ||
394 | int auxtrace_index__write(int fd, struct list_head *head); | ||
395 | int auxtrace_index__process(int fd, u64 size, struct perf_session *session, | ||
396 | bool needs_swap); | ||
397 | void auxtrace_index__free(struct list_head *head); | ||
398 | |||
364 | void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, | 399 | void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, |
365 | int code, int cpu, pid_t pid, pid_t tid, u64 ip, | 400 | int code, int cpu, pid_t pid, pid_t tid, u64 ip, |
366 | const char *msg); | 401 | const char *msg); |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 589c28028379..3f0d809d853a 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -869,11 +869,18 @@ static int write_branch_stack(int fd __maybe_unused, | |||
869 | return 0; | 869 | return 0; |
870 | } | 870 | } |
871 | 871 | ||
872 | static int write_auxtrace(int fd __maybe_unused, | 872 | static int write_auxtrace(int fd, struct perf_header *h, |
873 | struct perf_header *h __maybe_unused, | ||
874 | struct perf_evlist *evlist __maybe_unused) | 873 | struct perf_evlist *evlist __maybe_unused) |
875 | { | 874 | { |
876 | return 0; | 875 | struct perf_session *session; |
876 | int err; | ||
877 | |||
878 | session = container_of(h, struct perf_session, header); | ||
879 | |||
880 | err = auxtrace_index__write(fd, &session->auxtrace_index); | ||
881 | if (err < 0) | ||
882 | pr_err("Failed to write auxtrace index\n"); | ||
883 | return err; | ||
877 | } | 884 | } |
878 | 885 | ||
879 | static void print_hostname(struct perf_header *ph, int fd __maybe_unused, | 886 | static void print_hostname(struct perf_header *ph, int fd __maybe_unused, |
@@ -1834,6 +1841,22 @@ out_free: | |||
1834 | return ret; | 1841 | return ret; |
1835 | } | 1842 | } |
1836 | 1843 | ||
1844 | static int process_auxtrace(struct perf_file_section *section, | ||
1845 | struct perf_header *ph, int fd, | ||
1846 | void *data __maybe_unused) | ||
1847 | { | ||
1848 | struct perf_session *session; | ||
1849 | int err; | ||
1850 | |||
1851 | session = container_of(ph, struct perf_session, header); | ||
1852 | |||
1853 | err = auxtrace_index__process(fd, section->size, session, | ||
1854 | ph->needs_swap); | ||
1855 | if (err < 0) | ||
1856 | pr_err("Failed to process auxtrace index\n"); | ||
1857 | return err; | ||
1858 | } | ||
1859 | |||
1837 | struct feature_ops { | 1860 | struct feature_ops { |
1838 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); | 1861 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); |
1839 | void (*print)(struct perf_header *h, int fd, FILE *fp); | 1862 | void (*print)(struct perf_header *h, int fd, FILE *fp); |
@@ -1874,7 +1897,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { | |||
1874 | FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), | 1897 | FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), |
1875 | FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), | 1898 | FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), |
1876 | FEAT_OPP(HEADER_GROUP_DESC, group_desc), | 1899 | FEAT_OPP(HEADER_GROUP_DESC, group_desc), |
1877 | FEAT_OPA(HEADER_AUXTRACE, auxtrace), | 1900 | FEAT_OPP(HEADER_AUXTRACE, auxtrace), |
1878 | }; | 1901 | }; |
1879 | 1902 | ||
1880 | struct header_print_data { | 1903 | struct header_print_data { |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 90fa5674ccb4..b6972b118bc2 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -120,6 +120,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, | |||
120 | 120 | ||
121 | session->repipe = repipe; | 121 | session->repipe = repipe; |
122 | session->tool = tool; | 122 | session->tool = tool; |
123 | INIT_LIST_HEAD(&session->auxtrace_index); | ||
123 | machines__init(&session->machines); | 124 | machines__init(&session->machines); |
124 | ordered_events__init(&session->ordered_events, ordered_events__deliver_event); | 125 | ordered_events__init(&session->ordered_events, ordered_events__deliver_event); |
125 | 126 | ||
@@ -187,6 +188,7 @@ static void perf_session_env__delete(struct perf_session_env *env) | |||
187 | void perf_session__delete(struct perf_session *session) | 188 | void perf_session__delete(struct perf_session *session) |
188 | { | 189 | { |
189 | auxtrace__free(session); | 190 | auxtrace__free(session); |
191 | auxtrace_index__free(&session->auxtrace_index); | ||
190 | perf_session__destroy_kernel_maps(session); | 192 | perf_session__destroy_kernel_maps(session); |
191 | perf_session__delete_threads(session); | 193 | perf_session__delete_threads(session); |
192 | perf_session_env__delete(&session->header.env); | 194 | perf_session_env__delete(&session->header.env); |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 9ed51353a3d7..b44afc75d1cc 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -24,6 +24,7 @@ struct perf_session { | |||
24 | struct perf_evlist *evlist; | 24 | struct perf_evlist *evlist; |
25 | struct auxtrace *auxtrace; | 25 | struct auxtrace *auxtrace; |
26 | struct itrace_synth_opts *itrace_synth_opts; | 26 | struct itrace_synth_opts *itrace_synth_opts; |
27 | struct list_head auxtrace_index; | ||
27 | struct trace_event tevent; | 28 | struct trace_event tevent; |
28 | bool repipe; | 29 | bool repipe; |
29 | bool one_mmap; | 30 | bool one_mmap; |