diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2016-03-08 03:38:50 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-04-01 17:42:55 -0400 |
commit | 2a28e23049af99e1c810111ef5e56455cafeda45 (patch) | |
tree | c719c4c372e05c8906ab778b36f5801abc623039 /tools | |
parent | 46bc29b970f0011a9099077f1db8f3540aa829fe (diff) |
perf jit: Add support for using TSC as a timestamp
Intel PT uses TSC as a timestamp, so add support for using TSC instead
of the monotonic clock. Use of TSC is selected by an environment
variable "JITDUMP_USE_ARCH_TIMESTAMP" and flagged in the jitdump file
with flag JITDUMP_FLAGS_ARCH_TIMESTAMP.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1457426330-30226-1-git-send-email-adrian.hunter@intel.com
[ Added the fixup from He Kuang to make it build on other arches, ]
[ such as aarch64, to avoid inserting this bisectiong breakage upstream ]
Link: http://lkml.kernel.org/r/1459482572-129494-1-git-send-email-hekuang@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/arch/x86/util/tsc.c | 1 | ||||
-rw-r--r-- | tools/perf/arch/x86/util/tsc.h | 17 | ||||
-rw-r--r-- | tools/perf/jvmti/jvmti_agent.c | 43 | ||||
-rw-r--r-- | tools/perf/util/Build | 3 | ||||
-rw-r--r-- | tools/perf/util/jitdump.c | 37 | ||||
-rw-r--r-- | tools/perf/util/jitdump.h | 3 | ||||
-rw-r--r-- | tools/perf/util/tsc.h | 11 |
7 files changed, 87 insertions, 28 deletions
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index 70ff7c14bea6..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 | ||
12 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | 11 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, |
13 | struct perf_tsc_conversion *tc) | 12 | struct perf_tsc_conversion *tc) |
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 | |||
6 | struct perf_tsc_conversion { | ||
7 | u16 time_shift; | ||
8 | u32 time_mult; | ||
9 | u64 time_zero; | ||
10 | }; | ||
11 | |||
12 | struct perf_event_mmap_page; | ||
13 | |||
14 | int 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/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 | ||
95 | static int use_arch_timestamp; | ||
96 | |||
97 | static inline uint64_t | ||
98 | get_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 |
96 | static int perf_clk_id = CLOCK_MONOTONIC; | 112 | static 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 | ||
225 | static void | ||
226 | init_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 | |||
206 | void *jvmti_open(void) | 236 | void *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 | |||
69 | libperf-y += record.o | 69 | libperf-y += record.o |
70 | libperf-y += srcline.o | 70 | libperf-y += srcline.o |
71 | libperf-y += data.o | 71 | libperf-y += data.o |
72 | libperf-$(CONFIG_X86) += tsc.o | 72 | libperf-y += tsc.o |
73 | libperf-$(CONFIG_AUXTRACE) += tsc.o | ||
74 | libperf-y += cloexec.o | 73 | libperf-y += cloexec.o |
75 | libperf-y += thread-stack.o | 74 | libperf-y += thread-stack.o |
76 | libperf-$(CONFIG_AUXTRACE) += auxtrace.o | 75 | libperf-$(CONFIG_AUXTRACE) += auxtrace.o |
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 | ||
342 | static 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 | |||
332 | static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) | 359 | static 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 | ||
25 | enum jitdump_flags_bits { | 25 | enum 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/tsc.h b/tools/perf/util/tsc.h index 280ddc067556..d5b11e2b85e0 100644 --- a/tools/perf/util/tsc.h +++ b/tools/perf/util/tsc.h | |||
@@ -4,7 +4,16 @@ | |||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | 5 | ||
6 | #include "event.h" | 6 | #include "event.h" |
7 | #include "../arch/x86/util/tsc.h" | 7 | |
8 | struct perf_tsc_conversion { | ||
9 | u16 time_shift; | ||
10 | u32 time_mult; | ||
11 | u64 time_zero; | ||
12 | }; | ||
13 | struct perf_event_mmap_page; | ||
14 | |||
15 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | ||
16 | struct perf_tsc_conversion *tc); | ||
8 | 17 | ||
9 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); | 18 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); |
10 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); | 19 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); |