aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2015-04-30 10:37:25 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-05-04 18:48:47 -0400
commit99fa298453495ee23801ab500a5fe0138c260edb (patch)
tree1bd00c1305dce664eef07a6557d83d98d4a98643
parent64a7e61f11a22de3571b7f43f231e9b3aab00f1e (diff)
perf tools: Add AUX area tracing index
Add an index of AUX area tracing events within a perf.data file. perf record uses a special user event PERF_RECORD_FINISHED_ROUND to enable sorting of events in chunks instead of having to sort all events altogether. AUX area tracing events contain data that can span back to the very beginning of the recording period. i.e. they do not obey the rules of PERF_RECORD_FINISHED_ROUND. By adding an index, AUX area tracing events can be found in advance and the PERF_RECORD_FINISHED_ROUND approach works as usual. The index is recorded with the auxtrace feature in the perf.data file. A session reads the index but does not process it. An AUX area decoder can queue all the AUX area data in advance using auxtrace_queues__process_index() or otherwise process the index in some custom manner. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1430404667-10593-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-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;