Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
99fa2984 64a7e61f

+310 -4
+15
tools/perf/builtin-inject.c
··· 122 122 tool); 123 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 137 if (perf_data_file__is_pipe(session->file) || !session->one_mmap) { 126 138 ret = output_bytes(inject, event, event->header.size); 127 139 if (ret < 0) ··· 498 486 /* Allow space in the header for new attributes */ 499 487 output_data_offset = 4096; 500 488 } 489 + 490 + if (!inject->itrace_synth_opts.set) 491 + auxtrace_index__free(&session->auxtrace_index); 501 492 502 493 if (!file_out->is_pipe) 503 494 lseek(fd, output_data_offset, SEEK_SET);
+15
tools/perf/builtin-record.c
··· 117 117 size_t len1, void *data2, size_t len2) 118 118 { 119 119 struct record *rec = container_of(tool, struct record, tool); 120 + struct perf_data_file *file = &rec->file; 120 121 size_t padding; 121 122 u8 pad[8] = {0}; 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 + } 122 137 123 138 /* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */ 124 139 padding = (len1 + len2) & 7;
+215
tools/perf/util/auxtrace.c
··· 344 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 374 void auxtrace_queues__free(struct auxtrace_queues *queues) 348 375 { 349 376 unsigned int i; ··· 525 498 { 526 499 *err = 0; 527 500 return NULL; 501 + } 502 + 503 + static int auxtrace_index__alloc(struct list_head *head) 504 + { 505 + struct auxtrace_index *auxtrace_index; 506 + 507 + auxtrace_index = malloc(sizeof(struct auxtrace_index)); 508 + if (!auxtrace_index) 509 + return -ENOMEM; 510 + 511 + auxtrace_index->nr = 0; 512 + INIT_LIST_HEAD(&auxtrace_index->list); 513 + 514 + list_add_tail(&auxtrace_index->list, head); 515 + 516 + return 0; 517 + } 518 + 519 + void auxtrace_index__free(struct list_head *head) 520 + { 521 + struct auxtrace_index *auxtrace_index, *n; 522 + 523 + list_for_each_entry_safe(auxtrace_index, n, head, list) { 524 + list_del(&auxtrace_index->list); 525 + free(auxtrace_index); 526 + } 527 + } 528 + 529 + static struct auxtrace_index *auxtrace_index__last(struct list_head *head) 530 + { 531 + struct auxtrace_index *auxtrace_index; 532 + int err; 533 + 534 + if (list_empty(head)) { 535 + err = auxtrace_index__alloc(head); 536 + if (err) 537 + return NULL; 538 + } 539 + 540 + auxtrace_index = list_entry(head->prev, struct auxtrace_index, list); 541 + 542 + if (auxtrace_index->nr >= PERF_AUXTRACE_INDEX_ENTRY_COUNT) { 543 + err = auxtrace_index__alloc(head); 544 + if (err) 545 + return NULL; 546 + auxtrace_index = list_entry(head->prev, struct auxtrace_index, 547 + list); 548 + } 549 + 550 + return auxtrace_index; 551 + } 552 + 553 + int auxtrace_index__auxtrace_event(struct list_head *head, 554 + union perf_event *event, off_t file_offset) 555 + { 556 + struct auxtrace_index *auxtrace_index; 557 + size_t nr; 558 + 559 + auxtrace_index = auxtrace_index__last(head); 560 + if (!auxtrace_index) 561 + return -ENOMEM; 562 + 563 + nr = auxtrace_index->nr; 564 + auxtrace_index->entries[nr].file_offset = file_offset; 565 + auxtrace_index->entries[nr].sz = event->header.size; 566 + auxtrace_index->nr += 1; 567 + 568 + return 0; 569 + } 570 + 571 + static int auxtrace_index__do_write(int fd, 572 + struct auxtrace_index *auxtrace_index) 573 + { 574 + struct auxtrace_index_entry ent; 575 + size_t i; 576 + 577 + for (i = 0; i < auxtrace_index->nr; i++) { 578 + ent.file_offset = auxtrace_index->entries[i].file_offset; 579 + ent.sz = auxtrace_index->entries[i].sz; 580 + if (writen(fd, &ent, sizeof(ent)) != sizeof(ent)) 581 + return -errno; 582 + } 583 + return 0; 584 + } 585 + 586 + int auxtrace_index__write(int fd, struct list_head *head) 587 + { 588 + struct auxtrace_index *auxtrace_index; 589 + u64 total = 0; 590 + int err; 591 + 592 + list_for_each_entry(auxtrace_index, head, list) 593 + total += auxtrace_index->nr; 594 + 595 + if (writen(fd, &total, sizeof(total)) != sizeof(total)) 596 + return -errno; 597 + 598 + list_for_each_entry(auxtrace_index, head, list) { 599 + err = auxtrace_index__do_write(fd, auxtrace_index); 600 + if (err) 601 + return err; 602 + } 603 + 604 + return 0; 605 + } 606 + 607 + static int auxtrace_index__process_entry(int fd, struct list_head *head, 608 + bool needs_swap) 609 + { 610 + struct auxtrace_index *auxtrace_index; 611 + struct auxtrace_index_entry ent; 612 + size_t nr; 613 + 614 + if (readn(fd, &ent, sizeof(ent)) != sizeof(ent)) 615 + return -1; 616 + 617 + auxtrace_index = auxtrace_index__last(head); 618 + if (!auxtrace_index) 619 + return -1; 620 + 621 + nr = auxtrace_index->nr; 622 + if (needs_swap) { 623 + auxtrace_index->entries[nr].file_offset = 624 + bswap_64(ent.file_offset); 625 + auxtrace_index->entries[nr].sz = bswap_64(ent.sz); 626 + } else { 627 + auxtrace_index->entries[nr].file_offset = ent.file_offset; 628 + auxtrace_index->entries[nr].sz = ent.sz; 629 + } 630 + 631 + auxtrace_index->nr = nr + 1; 632 + 633 + return 0; 634 + } 635 + 636 + int auxtrace_index__process(int fd, u64 size, struct perf_session *session, 637 + bool needs_swap) 638 + { 639 + struct list_head *head = &session->auxtrace_index; 640 + u64 nr; 641 + 642 + if (readn(fd, &nr, sizeof(u64)) != sizeof(u64)) 643 + return -1; 644 + 645 + if (needs_swap) 646 + nr = bswap_64(nr); 647 + 648 + if (sizeof(u64) + nr * sizeof(struct auxtrace_index_entry) > size) 649 + return -1; 650 + 651 + while (nr--) { 652 + int err; 653 + 654 + err = auxtrace_index__process_entry(fd, head, needs_swap); 655 + if (err) 656 + return -1; 657 + } 658 + 659 + return 0; 660 + } 661 + 662 + static int auxtrace_queues__process_index_entry(struct auxtrace_queues *queues, 663 + struct perf_session *session, 664 + struct auxtrace_index_entry *ent) 665 + { 666 + return auxtrace_queues__add_indexed_event(queues, session, 667 + ent->file_offset, ent->sz); 668 + } 669 + 670 + int auxtrace_queues__process_index(struct auxtrace_queues *queues, 671 + struct perf_session *session) 672 + { 673 + struct auxtrace_index *auxtrace_index; 674 + struct auxtrace_index_entry *ent; 675 + size_t i; 676 + int err; 677 + 678 + list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) { 679 + for (i = 0; i < auxtrace_index->nr; i++) { 680 + ent = &auxtrace_index->entries[i]; 681 + err = auxtrace_queues__process_index_entry(queues, 682 + session, 683 + ent); 684 + if (err) 685 + return err; 686 + } 687 + } 688 + return 0; 528 689 } 529 690 530 691 struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue,
+35
tools/perf/util/auxtrace.h
··· 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 109 * struct auxtrace - session callbacks to allow AUX area data decoding. 84 110 * @process_event: lets the decoder see all session events 85 111 * @flush_events: process any remaining data ··· 347 321 union perf_event *event, off_t data_offset, 348 322 struct auxtrace_buffer **buffer_ptr); 349 323 void auxtrace_queues__free(struct auxtrace_queues *queues); 324 + int auxtrace_queues__process_index(struct auxtrace_queues *queues, 325 + struct perf_session *session); 350 326 struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, 351 327 struct auxtrace_buffer *buffer); 352 328 void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd); ··· 388 360 size_t priv_size); 389 361 void auxtrace_record__free(struct auxtrace_record *itr); 390 362 u64 auxtrace_record__reference(struct auxtrace_record *itr); 363 + 364 + int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event, 365 + off_t file_offset); 366 + int auxtrace_index__write(int fd, struct list_head *head); 367 + int auxtrace_index__process(int fd, u64 size, struct perf_session *session, 368 + bool needs_swap); 369 + void auxtrace_index__free(struct list_head *head); 391 370 392 371 void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, 393 372 int code, int cpu, pid_t pid, pid_t tid, u64 ip,
+27 -4
tools/perf/util/header.c
··· 869 869 return 0; 870 870 } 871 871 872 - static int write_auxtrace(int fd __maybe_unused, 873 - struct perf_header *h __maybe_unused, 872 + static int write_auxtrace(int fd, struct perf_header *h, 874 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 886 static void print_hostname(struct perf_header *ph, int fd __maybe_unused, ··· 1841 1834 return ret; 1842 1835 } 1843 1836 1837 + static int process_auxtrace(struct perf_file_section *section, 1838 + struct perf_header *ph, int fd, 1839 + void *data __maybe_unused) 1840 + { 1841 + struct perf_session *session; 1842 + int err; 1843 + 1844 + session = container_of(ph, struct perf_session, header); 1845 + 1846 + err = auxtrace_index__process(fd, section->size, session, 1847 + ph->needs_swap); 1848 + if (err < 0) 1849 + pr_err("Failed to process auxtrace index\n"); 1850 + return err; 1851 + } 1852 + 1844 1853 struct feature_ops { 1845 1854 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 1846 1855 void (*print)(struct perf_header *h, int fd, FILE *fp); ··· 1897 1874 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), 1898 1875 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), 1899 1876 FEAT_OPP(HEADER_GROUP_DESC, group_desc), 1900 - FEAT_OPA(HEADER_AUXTRACE, auxtrace), 1877 + FEAT_OPP(HEADER_AUXTRACE, auxtrace), 1901 1878 }; 1902 1879 1903 1880 struct header_print_data {
+2
tools/perf/util/session.c
··· 120 120 121 121 session->repipe = repipe; 122 122 session->tool = tool; 123 + INIT_LIST_HEAD(&session->auxtrace_index); 123 124 machines__init(&session->machines); 124 125 ordered_events__init(&session->ordered_events, ordered_events__deliver_event); 125 126 ··· 188 187 void perf_session__delete(struct perf_session *session) 189 188 { 190 189 auxtrace__free(session); 190 + auxtrace_index__free(&session->auxtrace_index); 191 191 perf_session__destroy_kernel_maps(session); 192 192 perf_session__delete_threads(session); 193 193 perf_session_env__delete(&session->header.env);
+1
tools/perf/util/session.h
··· 24 24 struct perf_evlist *evlist; 25 25 struct auxtrace *auxtrace; 26 26 struct itrace_synth_opts *itrace_synth_opts; 27 + struct list_head auxtrace_index; 27 28 struct trace_event tevent; 28 29 bool repipe; 29 30 bool one_mmap;