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

perf tools: Add time conversion event

Intel PT uses the time members from the perf_event_mmap_page to convert
between TSC and perf time.

Due to a lack of foresight when Intel PT was implemented, those time
members were recorded in the (implementation dependent) AUXTRACE_INFO
event, the structure of which is generally inaccessible outside of the
Intel PT decoder. However now the conversion between TSC and perf time
is needed when processing a jitdump file when Intel PT has been used for
tracing.

So add a user event to record the time members. 'perf record' will
synthesize the event if the information is available. And session
processing will put a copy of the event on the session so that tools
like 'perf inject' can easily access it.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1457426324-30158-1-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
46bc29b9 39878d49

+75
+31
tools/perf/arch/x86/util/tsc.c
··· 46 46 47 47 return low | ((u64)high) << 32; 48 48 } 49 + 50 + int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, 51 + struct perf_tool *tool, 52 + perf_event__handler_t process, 53 + struct machine *machine) 54 + { 55 + union perf_event event = { 56 + .time_conv = { 57 + .header = { 58 + .type = PERF_RECORD_TIME_CONV, 59 + .size = sizeof(struct time_conv_event), 60 + }, 61 + }, 62 + }; 63 + struct perf_tsc_conversion tc; 64 + int err; 65 + 66 + err = perf_read_tsc_conversion(pc, &tc); 67 + if (err == -EOPNOTSUPP) 68 + return 0; 69 + if (err) 70 + return err; 71 + 72 + pr_debug2("Synthesizing TSC conversion information\n"); 73 + 74 + event.time_conv.time_mult = tc.time_mult; 75 + event.time_conv.time_shift = tc.time_shift; 76 + event.time_conv.time_zero = tc.time_zero; 77 + 78 + return process(tool, &event, NULL, machine); 79 + }
+1
tools/perf/builtin-inject.c
··· 748 748 .auxtrace_info = perf_event__repipe_op2_synth, 749 749 .auxtrace = perf_event__repipe_auxtrace, 750 750 .auxtrace_error = perf_event__repipe_op2_synth, 751 + .time_conv = perf_event__repipe_op2_synth, 751 752 .finished_round = perf_event__repipe_oe_synth, 752 753 .build_id = perf_event__repipe_op2_synth, 753 754 .id_index = perf_event__repipe_op2_synth,
+15
tools/perf/builtin-record.c
··· 29 29 #include "util/data.h" 30 30 #include "util/perf_regs.h" 31 31 #include "util/auxtrace.h" 32 + #include "util/tsc.h" 32 33 #include "util/parse-branch-options.h" 33 34 #include "util/parse-regs-options.h" 34 35 #include "util/llvm-utils.h" ··· 513 512 514 513 static void snapshot_sig_handler(int sig); 515 514 515 + int __weak 516 + perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused, 517 + struct perf_tool *tool __maybe_unused, 518 + perf_event__handler_t process __maybe_unused, 519 + struct machine *machine __maybe_unused) 520 + { 521 + return 0; 522 + } 523 + 516 524 static int record__synthesize(struct record *rec) 517 525 { 518 526 struct perf_session *session = rec->session; ··· 558 548 rec->bytes_written += err; 559 549 } 560 550 } 551 + 552 + err = perf_event__synth_time_conv(rec->evlist->mmap[0].base, tool, 553 + process_synthesized_event, machine); 554 + if (err) 555 + goto out; 561 556 562 557 if (rec->opts.full_auxtrace) { 563 558 err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
+1
tools/perf/util/event.c
··· 45 45 [PERF_RECORD_STAT] = "STAT", 46 46 [PERF_RECORD_STAT_ROUND] = "STAT_ROUND", 47 47 [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", 48 + [PERF_RECORD_TIME_CONV] = "TIME_CONV", 48 49 }; 49 50 50 51 const char *perf_event__name(unsigned int id)
+9
tools/perf/util/event.h
··· 233 233 PERF_RECORD_STAT = 76, 234 234 PERF_RECORD_STAT_ROUND = 77, 235 235 PERF_RECORD_EVENT_UPDATE = 78, 236 + PERF_RECORD_TIME_CONV = 79, 236 237 PERF_RECORD_HEADER_MAX 237 238 }; 238 239 ··· 470 469 u64 time; 471 470 }; 472 471 472 + struct time_conv_event { 473 + struct perf_event_header header; 474 + u64 time_shift; 475 + u64 time_mult; 476 + u64 time_zero; 477 + }; 478 + 473 479 union perf_event { 474 480 struct perf_event_header header; 475 481 struct mmap_event mmap; ··· 505 497 struct stat_config_event stat_config; 506 498 struct stat_event stat; 507 499 struct stat_round_event stat_round; 500 + struct time_conv_event time_conv; 508 501 }; 509 502 510 503 void perf_event__print_totals(void);
+6
tools/perf/util/session.c
··· 409 409 tool->stat = process_stat_stub; 410 410 if (tool->stat_round == NULL) 411 411 tool->stat_round = process_stat_round_stub; 412 + if (tool->time_conv == NULL) 413 + tool->time_conv = process_event_op2_stub; 412 414 } 413 415 414 416 static void swap_sample_id_all(union perf_event *event, void *data) ··· 796 794 [PERF_RECORD_STAT] = perf_event__stat_swap, 797 795 [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap, 798 796 [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap, 797 + [PERF_RECORD_TIME_CONV] = perf_event__all64_swap, 799 798 [PERF_RECORD_HEADER_MAX] = NULL, 800 799 }; 801 800 ··· 1344 1341 return tool->stat(tool, event, session); 1345 1342 case PERF_RECORD_STAT_ROUND: 1346 1343 return tool->stat_round(tool, event, session); 1344 + case PERF_RECORD_TIME_CONV: 1345 + session->time_conv = event->time_conv; 1346 + return tool->time_conv(tool, event, session); 1347 1347 default: 1348 1348 return -EINVAL; 1349 1349 }
+1
tools/perf/util/session.h
··· 26 26 struct itrace_synth_opts *itrace_synth_opts; 27 27 struct list_head auxtrace_index; 28 28 struct trace_event tevent; 29 + struct time_conv_event time_conv; 29 30 bool repipe; 30 31 bool one_mmap; 31 32 void *one_mmap_addr;
+1
tools/perf/util/tool.h
··· 57 57 id_index, 58 58 auxtrace_info, 59 59 auxtrace_error, 60 + time_conv, 60 61 thread_map, 61 62 cpu_map, 62 63 stat_config,
+10
tools/perf/util/tsc.h
··· 3 3 4 4 #include <linux/types.h> 5 5 6 + #include "event.h" 6 7 #include "../arch/x86/util/tsc.h" 7 8 8 9 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); 9 10 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); 10 11 u64 rdtsc(void); 12 + 13 + struct perf_event_mmap_page; 14 + struct perf_tool; 15 + struct machine; 16 + 17 + int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, 18 + struct perf_tool *tool, 19 + perf_event__handler_t process, 20 + struct machine *machine); 11 21 12 22 #endif