aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-inject.c15
-rw-r--r--tools/perf/builtin-record.c15
-rw-r--r--tools/perf/util/auxtrace.c215
-rw-r--r--tools/perf/util/auxtrace.h35
-rw-r--r--tools/perf/util/header.c31
-rw-r--r--tools/perf/util/session.c2
-rw-r--r--tools/perf/util/session.h1
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
347static 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 }
370out:
371 return err;
372}
373
347void auxtrace_queues__free(struct auxtrace_queues *queues) 374void 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
530static 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
546void 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
556static 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
580int 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
598static 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
613int 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
634static 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
663int 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
689static 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
697int 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
503struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, 718struct 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 */
88struct 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 */
102struct 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);
323void auxtrace_queues__free(struct auxtrace_queues *queues); 349void auxtrace_queues__free(struct auxtrace_queues *queues);
350int auxtrace_queues__process_index(struct auxtrace_queues *queues,
351 struct perf_session *session);
324struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, 352struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue,
325 struct auxtrace_buffer *buffer); 353 struct auxtrace_buffer *buffer);
326void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd); 354void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd);
@@ -361,6 +389,13 @@ int auxtrace_record__info_fill(struct auxtrace_record *itr,
361void auxtrace_record__free(struct auxtrace_record *itr); 389void auxtrace_record__free(struct auxtrace_record *itr);
362u64 auxtrace_record__reference(struct auxtrace_record *itr); 390u64 auxtrace_record__reference(struct auxtrace_record *itr);
363 391
392int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event,
393 off_t file_offset);
394int auxtrace_index__write(int fd, struct list_head *head);
395int auxtrace_index__process(int fd, u64 size, struct perf_session *session,
396 bool needs_swap);
397void auxtrace_index__free(struct list_head *head);
398
364void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, 399void 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
872static int write_auxtrace(int fd __maybe_unused, 872static 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
879static void print_hostname(struct perf_header *ph, int fd __maybe_unused, 886static 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
1844static 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
1837struct feature_ops { 1860struct 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
1880struct header_print_data { 1903struct 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)
187void perf_session__delete(struct perf_session *session) 188void 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;