aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-04-06 02:46:23 -0400
committerIngo Molnar <mingo@kernel.org>2016-04-06 02:46:23 -0400
commitdad38ca64a252144b4ccdfe9730a3fe2b7c61957 (patch)
tree5eccdc35d45e9d05a088512a68418fc4fa0612aa
parentd1b26c70246bc72922ae61d9f972d5c2588409e7 (diff)
parentd37ba880598654fda10b312331377cdca3edd574 (diff)
Merge tag 'perf-core-for-mingo-20160401' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Do not use events that don't have timestamps when setting 'perf trace's base timestamp, fixing up the timestamp column for syscalls (Arnaldo Carvalho de Melo) - Make the 'bpf-output' sample_type be the same as tracepoint's, fixing up 'perf trace's timestamp column for bpf events (Wang Nan) - Fix PMU term format max value calculation (Kan Liang) - Pretty print 'seccomp', 'getrandom' syscalls in 'perf trace' (Arnaldo Carvalho de Melo) Infrastructure changes: - Add support for using TSC as an ARCH timestamp when synthesizing JIT records (Adrian Hunter) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/perf/arch/x86/util/intel-bts.c5
-rw-r--r--tools/perf/arch/x86/util/intel-pt.c5
-rw-r--r--tools/perf/arch/x86/util/tsc.c32
-rw-r--r--tools/perf/arch/x86/util/tsc.h17
-rw-r--r--tools/perf/builtin-inject.c1
-rw-r--r--tools/perf/builtin-record.c15
-rw-r--r--tools/perf/builtin-trace.c99
-rw-r--r--tools/perf/jvmti/jvmti_agent.c43
-rw-r--r--tools/perf/util/Build3
-rw-r--r--tools/perf/util/event.c1
-rw-r--r--tools/perf/util/event.h9
-rw-r--r--tools/perf/util/evsel.c3
-rw-r--r--tools/perf/util/jitdump.c37
-rw-r--r--tools/perf/util/jitdump.h3
-rw-r--r--tools/perf/util/pmu.c13
-rw-r--r--tools/perf/util/session.c6
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/tool.h1
-rw-r--r--tools/perf/util/tsc.h21
19 files changed, 274 insertions, 41 deletions
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index d66f9ad4df2e..7dc30637cf66 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -438,6 +438,11 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
438 if (!intel_bts_pmu) 438 if (!intel_bts_pmu)
439 return NULL; 439 return NULL;
440 440
441 if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) {
442 *err = -errno;
443 return NULL;
444 }
445
441 btsr = zalloc(sizeof(struct intel_bts_recording)); 446 btsr = zalloc(sizeof(struct intel_bts_recording));
442 if (!btsr) { 447 if (!btsr) {
443 *err = -ENOMEM; 448 *err = -ENOMEM;
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index a3395179c9ee..a07b9605e93b 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -1027,6 +1027,11 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
1027 if (!intel_pt_pmu) 1027 if (!intel_pt_pmu)
1028 return NULL; 1028 return NULL;
1029 1029
1030 if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) {
1031 *err = -errno;
1032 return NULL;
1033 }
1034
1030 ptr = zalloc(sizeof(struct intel_pt_recording)); 1035 ptr = zalloc(sizeof(struct intel_pt_recording));
1031 if (!ptr) { 1036 if (!ptr) {
1032 *err = -ENOMEM; 1037 *err = -ENOMEM;
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
index fd2868490d00..357f1b13b5ae 100644
--- a/tools/perf/arch/x86/util/tsc.c
+++ b/tools/perf/arch/x86/util/tsc.c
@@ -7,7 +7,6 @@
7#include <linux/types.h> 7#include <linux/types.h>
8#include "../../util/debug.h" 8#include "../../util/debug.h"
9#include "../../util/tsc.h" 9#include "../../util/tsc.h"
10#include "tsc.h"
11 10
12int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, 11int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
13 struct perf_tsc_conversion *tc) 12 struct perf_tsc_conversion *tc)
@@ -46,3 +45,34 @@ u64 rdtsc(void)
46 45
47 return low | ((u64)high) << 32; 46 return low | ((u64)high) << 32;
48} 47}
48
49int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc,
50 struct perf_tool *tool,
51 perf_event__handler_t process,
52 struct machine *machine)
53{
54 union perf_event event = {
55 .time_conv = {
56 .header = {
57 .type = PERF_RECORD_TIME_CONV,
58 .size = sizeof(struct time_conv_event),
59 },
60 },
61 };
62 struct perf_tsc_conversion tc;
63 int err;
64
65 err = perf_read_tsc_conversion(pc, &tc);
66 if (err == -EOPNOTSUPP)
67 return 0;
68 if (err)
69 return err;
70
71 pr_debug2("Synthesizing TSC conversion information\n");
72
73 event.time_conv.time_mult = tc.time_mult;
74 event.time_conv.time_shift = tc.time_shift;
75 event.time_conv.time_zero = tc.time_zero;
76
77 return process(tool, &event, NULL, machine);
78}
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h
deleted file mode 100644
index 2edc4d31065c..000000000000
--- a/tools/perf/arch/x86/util/tsc.h
+++ /dev/null
@@ -1,17 +0,0 @@
1#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
2#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
3
4#include <linux/types.h>
5
6struct perf_tsc_conversion {
7 u16 time_shift;
8 u32 time_mult;
9 u64 time_zero;
10};
11
12struct perf_event_mmap_page;
13
14int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
15 struct perf_tsc_conversion *tc);
16
17#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index d1a2d104f2bc..e5afa8fe1bf1 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -748,6 +748,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
748 .auxtrace_info = perf_event__repipe_op2_synth, 748 .auxtrace_info = perf_event__repipe_op2_synth,
749 .auxtrace = perf_event__repipe_auxtrace, 749 .auxtrace = perf_event__repipe_auxtrace,
750 .auxtrace_error = perf_event__repipe_op2_synth, 750 .auxtrace_error = perf_event__repipe_op2_synth,
751 .time_conv = perf_event__repipe_op2_synth,
751 .finished_round = perf_event__repipe_oe_synth, 752 .finished_round = perf_event__repipe_oe_synth,
752 .build_id = perf_event__repipe_op2_synth, 753 .build_id = perf_event__repipe_op2_synth,
753 .id_index = perf_event__repipe_op2_synth, 754 .id_index = perf_event__repipe_op2_synth,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 515510ecc76a..410035c6e300 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -29,6 +29,7 @@
29#include "util/data.h" 29#include "util/data.h"
30#include "util/perf_regs.h" 30#include "util/perf_regs.h"
31#include "util/auxtrace.h" 31#include "util/auxtrace.h"
32#include "util/tsc.h"
32#include "util/parse-branch-options.h" 33#include "util/parse-branch-options.h"
33#include "util/parse-regs-options.h" 34#include "util/parse-regs-options.h"
34#include "util/llvm-utils.h" 35#include "util/llvm-utils.h"
@@ -512,6 +513,15 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
512 513
513static void snapshot_sig_handler(int sig); 514static void snapshot_sig_handler(int sig);
514 515
516int __weak
517perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused,
518 struct perf_tool *tool __maybe_unused,
519 perf_event__handler_t process __maybe_unused,
520 struct machine *machine __maybe_unused)
521{
522 return 0;
523}
524
515static int record__synthesize(struct record *rec) 525static int record__synthesize(struct record *rec)
516{ 526{
517 struct perf_session *session = rec->session; 527 struct perf_session *session = rec->session;
@@ -549,6 +559,11 @@ static int record__synthesize(struct record *rec)
549 } 559 }
550 } 560 }
551 561
562 err = perf_event__synth_time_conv(rec->evlist->mmap[0].base, tool,
563 process_synthesized_event, machine);
564 if (err)
565 goto out;
566
552 if (rec->opts.full_auxtrace) { 567 if (rec->opts.full_auxtrace) {
553 err = perf_event__synthesize_auxtrace_info(rec->itr, tool, 568 err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
554 session, process_synthesized_event); 569 session, process_synthesized_event);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 93ac724fb635..d309f4535a45 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -40,6 +40,11 @@
40#include <sys/mman.h> 40#include <sys/mman.h>
41#include <linux/futex.h> 41#include <linux/futex.h>
42#include <linux/err.h> 42#include <linux/err.h>
43#include <linux/seccomp.h>
44#include <linux/filter.h>
45#include <linux/audit.h>
46#include <sys/ptrace.h>
47#include <linux/random.h>
43 48
44/* For older distros: */ 49/* For older distros: */
45#ifndef MAP_STACK 50#ifndef MAP_STACK
@@ -1001,6 +1006,69 @@ static const char *tioctls[] = {
1001static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401); 1006static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
1002#endif /* defined(__i386__) || defined(__x86_64__) */ 1007#endif /* defined(__i386__) || defined(__x86_64__) */
1003 1008
1009static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
1010{
1011 int op = arg->val;
1012 size_t printed = 0;
1013
1014 switch (op) {
1015#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
1016 P_SECCOMP_SET_MODE_OP(STRICT);
1017 P_SECCOMP_SET_MODE_OP(FILTER);
1018#undef P_SECCOMP_SET_MODE_OP
1019 default: printed = scnprintf(bf, size, "%#x", op); break;
1020 }
1021
1022 return printed;
1023}
1024
1025#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
1026
1027static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
1028 struct syscall_arg *arg)
1029{
1030 int printed = 0, flags = arg->val;
1031
1032#define P_FLAG(n) \
1033 if (flags & SECCOMP_FILTER_FLAG_##n) { \
1034 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1035 flags &= ~SECCOMP_FILTER_FLAG_##n; \
1036 }
1037
1038 P_FLAG(TSYNC);
1039#undef P_FLAG
1040
1041 if (flags)
1042 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1043
1044 return printed;
1045}
1046
1047#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
1048
1049static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
1050 struct syscall_arg *arg)
1051{
1052 int printed = 0, flags = arg->val;
1053
1054#define P_FLAG(n) \
1055 if (flags & GRND_##n) { \
1056 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1057 flags &= ~GRND_##n; \
1058 }
1059
1060 P_FLAG(RANDOM);
1061 P_FLAG(NONBLOCK);
1062#undef P_FLAG
1063
1064 if (flags)
1065 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1066
1067 return printed;
1068}
1069
1070#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
1071
1004#define STRARRAY(arg, name, array) \ 1072#define STRARRAY(arg, name, array) \
1005 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ 1073 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
1006 .arg_parm = { [arg] = &strarray__##array, } 1074 .arg_parm = { [arg] = &strarray__##array, }
@@ -1093,6 +1161,8 @@ static struct syscall_fmt {
1093 { .name = "getdents64", .errmsg = true, 1161 { .name = "getdents64", .errmsg = true,
1094 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1162 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1095 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, 1163 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1164 { .name = "getrandom", .errmsg = true,
1165 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
1096 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, 1166 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
1097 { .name = "getxattr", .errmsg = true, 1167 { .name = "getxattr", .errmsg = true,
1098 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, 1168 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
@@ -1234,6 +1304,9 @@ static struct syscall_fmt {
1234 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, 1304 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1235 { .name = "rt_tgsigqueueinfo", .errmsg = true, 1305 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1236 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, 1306 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1307 { .name = "seccomp", .errmsg = true,
1308 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1309 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
1237 { .name = "select", .errmsg = true, .timeout = true, }, 1310 { .name = "select", .errmsg = true, .timeout = true, },
1238 { .name = "sendmmsg", .errmsg = true, 1311 { .name = "sendmmsg", .errmsg = true,
1239 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 1312 .arg_scnprintf = { [0] = SCA_FD, /* fd */
@@ -1618,6 +1691,7 @@ static int trace__process_event(struct trace *trace, struct machine *machine,
1618 color_fprintf(trace->output, PERF_COLOR_RED, 1691 color_fprintf(trace->output, PERF_COLOR_RED,
1619 "LOST %" PRIu64 " events!\n", event->lost.lost); 1692 "LOST %" PRIu64 " events!\n", event->lost.lost);
1620 ret = machine__process_lost_event(machine, event, sample); 1693 ret = machine__process_lost_event(machine, event, sample);
1694 break;
1621 default: 1695 default:
1622 ret = machine__process_event(machine, event, sample); 1696 ret = machine__process_event(machine, event, sample);
1623 break; 1697 break;
@@ -2326,6 +2400,23 @@ static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2326 return false; 2400 return false;
2327} 2401}
2328 2402
2403static void trace__set_base_time(struct trace *trace,
2404 struct perf_evsel *evsel,
2405 struct perf_sample *sample)
2406{
2407 /*
2408 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2409 * and don't use sample->time unconditionally, we may end up having
2410 * some other event in the future without PERF_SAMPLE_TIME for good
2411 * reason, i.e. we may not be interested in its timestamps, just in
2412 * it taking place, picking some piece of information when it
2413 * appears in our event stream (vfs_getname comes to mind).
2414 */
2415 if (trace->base_time == 0 && !trace->full_time &&
2416 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
2417 trace->base_time = sample->time;
2418}
2419
2329static int trace__process_sample(struct perf_tool *tool, 2420static int trace__process_sample(struct perf_tool *tool,
2330 union perf_event *event, 2421 union perf_event *event,
2331 struct perf_sample *sample, 2422 struct perf_sample *sample,
@@ -2340,8 +2431,7 @@ static int trace__process_sample(struct perf_tool *tool,
2340 if (skip_sample(trace, sample)) 2431 if (skip_sample(trace, sample))
2341 return 0; 2432 return 0;
2342 2433
2343 if (!trace->full_time && trace->base_time == 0) 2434 trace__set_base_time(trace, evsel, sample);
2344 trace->base_time = sample->time;
2345 2435
2346 if (handler) { 2436 if (handler) {
2347 ++trace->nr_events; 2437 ++trace->nr_events;
@@ -2479,9 +2569,6 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st
2479 const u32 type = event->header.type; 2569 const u32 type = event->header.type;
2480 struct perf_evsel *evsel; 2570 struct perf_evsel *evsel;
2481 2571
2482 if (!trace->full_time && trace->base_time == 0)
2483 trace->base_time = sample->time;
2484
2485 if (type != PERF_RECORD_SAMPLE) { 2572 if (type != PERF_RECORD_SAMPLE) {
2486 trace__process_event(trace, trace->host, event, sample); 2573 trace__process_event(trace, trace->host, event, sample);
2487 return; 2574 return;
@@ -2493,6 +2580,8 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st
2493 return; 2580 return;
2494 } 2581 }
2495 2582
2583 trace__set_base_time(trace, evsel, sample);
2584
2496 if (evsel->attr.type == PERF_TYPE_TRACEPOINT && 2585 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2497 sample->raw_data == NULL) { 2586 sample->raw_data == NULL) {
2498 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 2587 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
index 6461e02ab940..3573f315f955 100644
--- a/tools/perf/jvmti/jvmti_agent.c
+++ b/tools/perf/jvmti/jvmti_agent.c
@@ -92,6 +92,22 @@ error:
92 return ret; 92 return ret;
93} 93}
94 94
95static int use_arch_timestamp;
96
97static inline uint64_t
98get_arch_timestamp(void)
99{
100#if defined(__i386__) || defined(__x86_64__)
101 unsigned int low, high;
102
103 asm volatile("rdtsc" : "=a" (low), "=d" (high));
104
105 return low | ((uint64_t)high) << 32;
106#else
107 return 0;
108#endif
109}
110
95#define NSEC_PER_SEC 1000000000 111#define NSEC_PER_SEC 1000000000
96static int perf_clk_id = CLOCK_MONOTONIC; 112static int perf_clk_id = CLOCK_MONOTONIC;
97 113
@@ -107,6 +123,9 @@ perf_get_timestamp(void)
107 struct timespec ts; 123 struct timespec ts;
108 int ret; 124 int ret;
109 125
126 if (use_arch_timestamp)
127 return get_arch_timestamp();
128
110 ret = clock_gettime(perf_clk_id, &ts); 129 ret = clock_gettime(perf_clk_id, &ts);
111 if (ret) 130 if (ret)
112 return 0; 131 return 0;
@@ -203,6 +222,17 @@ perf_close_marker_file(void)
203 munmap(marker_addr, pgsz); 222 munmap(marker_addr, pgsz);
204} 223}
205 224
225static void
226init_arch_timestamp(void)
227{
228 char *str = getenv("JITDUMP_USE_ARCH_TIMESTAMP");
229
230 if (!str || !*str || !strcmp(str, "0"))
231 return;
232
233 use_arch_timestamp = 1;
234}
235
206void *jvmti_open(void) 236void *jvmti_open(void)
207{ 237{
208 int pad_cnt; 238 int pad_cnt;
@@ -211,11 +241,17 @@ void *jvmti_open(void)
211 int fd; 241 int fd;
212 FILE *fp; 242 FILE *fp;
213 243
244 init_arch_timestamp();
245
214 /* 246 /*
215 * check if clockid is supported 247 * check if clockid is supported
216 */ 248 */
217 if (!perf_get_timestamp()) 249 if (!perf_get_timestamp()) {
218 warnx("jvmti: kernel does not support %d clock id", perf_clk_id); 250 if (use_arch_timestamp)
251 warnx("jvmti: arch timestamp not supported");
252 else
253 warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
254 }
219 255
220 memset(&header, 0, sizeof(header)); 256 memset(&header, 0, sizeof(header));
221 257
@@ -263,6 +299,9 @@ void *jvmti_open(void)
263 299
264 header.timestamp = perf_get_timestamp(); 300 header.timestamp = perf_get_timestamp();
265 301
302 if (use_arch_timestamp)
303 header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP;
304
266 if (!fwrite(&header, sizeof(header), 1, fp)) { 305 if (!fwrite(&header, sizeof(header), 1, fp)) {
267 warn("jvmti: cannot write dumpfile header"); 306 warn("jvmti: cannot write dumpfile header");
268 goto error; 307 goto error;
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index da48fd843438..85ceff357769 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -69,8 +69,7 @@ libperf-y += stat-shadow.o
69libperf-y += record.o 69libperf-y += record.o
70libperf-y += srcline.o 70libperf-y += srcline.o
71libperf-y += data.o 71libperf-y += data.o
72libperf-$(CONFIG_X86) += tsc.o 72libperf-y += tsc.o
73libperf-$(CONFIG_AUXTRACE) += tsc.o
74libperf-y += cloexec.o 73libperf-y += cloexec.o
75libperf-y += thread-stack.o 74libperf-y += thread-stack.o
76libperf-$(CONFIG_AUXTRACE) += auxtrace.o 75libperf-$(CONFIG_AUXTRACE) += auxtrace.o
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index dad55d04ffdd..b68959037688 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -45,6 +45,7 @@ static const char *perf_event__names[] = {
45 [PERF_RECORD_STAT] = "STAT", 45 [PERF_RECORD_STAT] = "STAT",
46 [PERF_RECORD_STAT_ROUND] = "STAT_ROUND", 46 [PERF_RECORD_STAT_ROUND] = "STAT_ROUND",
47 [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", 47 [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE",
48 [PERF_RECORD_TIME_CONV] = "TIME_CONV",
48}; 49};
49 50
50const char *perf_event__name(unsigned int id) 51const char *perf_event__name(unsigned int id)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 6bb1c928350d..8d363d5e65a2 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -233,6 +233,7 @@ enum perf_user_event_type { /* above any possible kernel type */
233 PERF_RECORD_STAT = 76, 233 PERF_RECORD_STAT = 76,
234 PERF_RECORD_STAT_ROUND = 77, 234 PERF_RECORD_STAT_ROUND = 77,
235 PERF_RECORD_EVENT_UPDATE = 78, 235 PERF_RECORD_EVENT_UPDATE = 78,
236 PERF_RECORD_TIME_CONV = 79,
236 PERF_RECORD_HEADER_MAX 237 PERF_RECORD_HEADER_MAX
237}; 238};
238 239
@@ -469,6 +470,13 @@ struct stat_round_event {
469 u64 time; 470 u64 time;
470}; 471};
471 472
473struct time_conv_event {
474 struct perf_event_header header;
475 u64 time_shift;
476 u64 time_mult;
477 u64 time_zero;
478};
479
472union perf_event { 480union perf_event {
473 struct perf_event_header header; 481 struct perf_event_header header;
474 struct mmap_event mmap; 482 struct mmap_event mmap;
@@ -497,6 +505,7 @@ union perf_event {
497 struct stat_config_event stat_config; 505 struct stat_config_event stat_config;
498 struct stat_event stat; 506 struct stat_event stat;
499 struct stat_round_event stat_round; 507 struct stat_round_event stat_round;
508 struct time_conv_event time_conv;
500}; 509};
501 510
502void perf_event__print_totals(void); 511void perf_event__print_totals(void);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 738ce226002b..3fd7c2c72f4a 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -226,7 +226,8 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
226 perf_evsel__init(evsel, attr, idx); 226 perf_evsel__init(evsel, attr, idx);
227 227
228 if (perf_evsel__is_bpf_output(evsel)) { 228 if (perf_evsel__is_bpf_output(evsel)) {
229 evsel->attr.sample_type |= PERF_SAMPLE_RAW; 229 evsel->attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
230 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD),
230 evsel->attr.sample_period = 1; 231 evsel->attr.sample_period = 1;
231 } 232 }
232 233
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index ad0c0bb1fbc7..52fcef3074fe 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -17,6 +17,7 @@
17#include "strlist.h" 17#include "strlist.h"
18#include <elf.h> 18#include <elf.h>
19 19
20#include "tsc.h"
20#include "session.h" 21#include "session.h"
21#include "jit.h" 22#include "jit.h"
22#include "jitdump.h" 23#include "jitdump.h"
@@ -33,6 +34,7 @@ struct jit_buf_desc {
33 size_t bufsize; 34 size_t bufsize;
34 FILE *in; 35 FILE *in;
35 bool needs_bswap; /* handles cross-endianess */ 36 bool needs_bswap; /* handles cross-endianess */
37 bool use_arch_timestamp;
36 void *debug_data; 38 void *debug_data;
37 size_t nr_debug_entries; 39 size_t nr_debug_entries;
38 uint32_t code_load_count; 40 uint32_t code_load_count;
@@ -158,13 +160,16 @@ jit_open(struct jit_buf_desc *jd, const char *name)
158 header.flags = bswap_64(header.flags); 160 header.flags = bswap_64(header.flags);
159 } 161 }
160 162
163 jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP;
164
161 if (verbose > 2) 165 if (verbose > 2)
162 pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n", 166 pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n",
163 header.version, 167 header.version,
164 header.total_size, 168 header.total_size,
165 (unsigned long long)header.timestamp, 169 (unsigned long long)header.timestamp,
166 header.pid, 170 header.pid,
167 header.elf_mach); 171 header.elf_mach,
172 jd->use_arch_timestamp);
168 173
169 if (header.flags & JITDUMP_FLAGS_RESERVED) { 174 if (header.flags & JITDUMP_FLAGS_RESERVED) {
170 pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n", 175 pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
@@ -172,10 +177,15 @@ jit_open(struct jit_buf_desc *jd, const char *name)
172 goto error; 177 goto error;
173 } 178 }
174 179
180 if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) {
181 pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n");
182 goto error;
183 }
184
175 /* 185 /*
176 * validate event is using the correct clockid 186 * validate event is using the correct clockid
177 */ 187 */
178 if (jit_validate_events(jd->session)) { 188 if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) {
179 pr_err("error, jitted code must be sampled with perf record -k 1\n"); 189 pr_err("error, jitted code must be sampled with perf record -k 1\n");
180 goto error; 190 goto error;
181 } 191 }
@@ -329,6 +339,23 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
329 return 0; 339 return 0;
330} 340}
331 341
342static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp)
343{
344 struct perf_tsc_conversion tc;
345
346 if (!jd->use_arch_timestamp)
347 return timestamp;
348
349 tc.time_shift = jd->session->time_conv.time_shift;
350 tc.time_mult = jd->session->time_conv.time_mult;
351 tc.time_zero = jd->session->time_conv.time_zero;
352
353 if (!tc.time_mult)
354 return 0;
355
356 return tsc_to_perf_time(timestamp, &tc);
357}
358
332static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) 359static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
333{ 360{
334 struct perf_sample sample; 361 struct perf_sample sample;
@@ -410,7 +437,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
410 id->tid = tid; 437 id->tid = tid;
411 } 438 }
412 if (jd->sample_type & PERF_SAMPLE_TIME) 439 if (jd->sample_type & PERF_SAMPLE_TIME)
413 id->time = jr->load.p.timestamp; 440 id->time = convert_timestamp(jd, jr->load.p.timestamp);
414 441
415 /* 442 /*
416 * create pseudo sample to induce dso hit increment 443 * create pseudo sample to induce dso hit increment
@@ -499,7 +526,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
499 id->tid = tid; 526 id->tid = tid;
500 } 527 }
501 if (jd->sample_type & PERF_SAMPLE_TIME) 528 if (jd->sample_type & PERF_SAMPLE_TIME)
502 id->time = jr->load.p.timestamp; 529 id->time = convert_timestamp(jd, jr->load.p.timestamp);
503 530
504 /* 531 /*
505 * create pseudo sample to induce dso hit increment 532 * create pseudo sample to induce dso hit increment
diff --git a/tools/perf/util/jitdump.h b/tools/perf/util/jitdump.h
index b66c1f503d9e..bcacd20d0c1c 100644
--- a/tools/perf/util/jitdump.h
+++ b/tools/perf/util/jitdump.h
@@ -23,9 +23,12 @@
23#define JITHEADER_VERSION 1 23#define JITHEADER_VERSION 1
24 24
25enum jitdump_flags_bits { 25enum jitdump_flags_bits {
26 JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT,
26 JITDUMP_FLAGS_MAX_BIT, 27 JITDUMP_FLAGS_MAX_BIT,
27}; 28};
28 29
30#define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT)
31
29#define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \ 32#define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \
30 (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0) 33 (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
31 34
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index adef23b1352e..bf34468a99cb 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -602,14 +602,13 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
602 602
603static __u64 pmu_format_max_value(const unsigned long *format) 603static __u64 pmu_format_max_value(const unsigned long *format)
604{ 604{
605 int w; 605 __u64 w = 0;
606 int fbit;
606 607
607 w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 608 for_each_set_bit(fbit, format, PERF_PMU_FORMAT_BITS)
608 if (!w) 609 w |= (1ULL << fbit);
609 return 0; 610
610 if (w < 64) 611 return w;
611 return (1ULL << w) - 1;
612 return -1;
613} 612}
614 613
615/* 614/*
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 4abd85c6346d..ef370557fb9a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -409,6 +409,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
409 tool->stat = process_stat_stub; 409 tool->stat = process_stat_stub;
410 if (tool->stat_round == NULL) 410 if (tool->stat_round == NULL)
411 tool->stat_round = process_stat_round_stub; 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
414static void swap_sample_id_all(union perf_event *event, void *data) 416static void swap_sample_id_all(union perf_event *event, void *data)
@@ -794,6 +796,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
794 [PERF_RECORD_STAT] = perf_event__stat_swap, 796 [PERF_RECORD_STAT] = perf_event__stat_swap,
795 [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap, 797 [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap,
796 [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap, 798 [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap,
799 [PERF_RECORD_TIME_CONV] = perf_event__all64_swap,
797 [PERF_RECORD_HEADER_MAX] = NULL, 800 [PERF_RECORD_HEADER_MAX] = NULL,
798}; 801};
799 802
@@ -1341,6 +1344,9 @@ static s64 perf_session__process_user_event(struct perf_session *session,
1341 return tool->stat(tool, event, session); 1344 return tool->stat(tool, event, session);
1342 case PERF_RECORD_STAT_ROUND: 1345 case PERF_RECORD_STAT_ROUND:
1343 return tool->stat_round(tool, event, session); 1346 return tool->stat_round(tool, event, session);
1347 case PERF_RECORD_TIME_CONV:
1348 session->time_conv = event->time_conv;
1349 return tool->time_conv(tool, event, session);
1344 default: 1350 default:
1345 return -EINVAL; 1351 return -EINVAL;
1346 } 1352 }
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 5f792e35d4c1..f96fc9e8c52e 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -26,6 +26,7 @@ struct perf_session {
26 struct itrace_synth_opts *itrace_synth_opts; 26 struct itrace_synth_opts *itrace_synth_opts;
27 struct list_head auxtrace_index; 27 struct list_head auxtrace_index;
28 struct trace_event tevent; 28 struct trace_event tevent;
29 struct time_conv_event time_conv;
29 bool repipe; 30 bool repipe;
30 bool one_mmap; 31 bool one_mmap;
31 void *one_mmap_addr; 32 void *one_mmap_addr;
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index 55de4cffcd4e..ac2590a3de2d 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -57,6 +57,7 @@ struct perf_tool {
57 id_index, 57 id_index,
58 auxtrace_info, 58 auxtrace_info,
59 auxtrace_error, 59 auxtrace_error,
60 time_conv,
60 thread_map, 61 thread_map,
61 cpu_map, 62 cpu_map,
62 stat_config, 63 stat_config,
diff --git a/tools/perf/util/tsc.h b/tools/perf/util/tsc.h
index a8b78f1b3243..d5b11e2b85e0 100644
--- a/tools/perf/util/tsc.h
+++ b/tools/perf/util/tsc.h
@@ -3,10 +3,29 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6#include "../arch/x86/util/tsc.h" 6#include "event.h"
7
8struct perf_tsc_conversion {
9 u16 time_shift;
10 u32 time_mult;
11 u64 time_zero;
12};
13struct perf_event_mmap_page;
14
15int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
16 struct perf_tsc_conversion *tc);
7 17
8u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); 18u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
9u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); 19u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
10u64 rdtsc(void); 20u64 rdtsc(void);
11 21
22struct perf_event_mmap_page;
23struct perf_tool;
24struct machine;
25
26int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc,
27 struct perf_tool *tool,
28 perf_event__handler_t process,
29 struct machine *machine);
30
12#endif 31#endif