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

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>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
2a28e230 46bc29b9

+87 -28
-1
tools/perf/arch/x86/util/tsc.c
··· 7 7 #include <linux/types.h> 8 8 #include "../../util/debug.h" 9 9 #include "../../util/tsc.h" 10 - #include "tsc.h" 11 10 12 11 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, 13 12 struct perf_tsc_conversion *tc)
-17
tools/perf/arch/x86/util/tsc.h
··· 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__ */
+41 -2
tools/perf/jvmti/jvmti_agent.c
··· 92 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 111 #define NSEC_PER_SEC 1000000000 96 112 static int perf_clk_id = CLOCK_MONOTONIC; 97 113 ··· 122 106 { 123 107 struct timespec ts; 124 108 int ret; 109 + 110 + if (use_arch_timestamp) 111 + return get_arch_timestamp(); 125 112 126 113 ret = clock_gettime(perf_clk_id, &ts); 127 114 if (ret) ··· 222 203 munmap(marker_addr, pgsz); 223 204 } 224 205 206 + static void 207 + init_arch_timestamp(void) 208 + { 209 + char *str = getenv("JITDUMP_USE_ARCH_TIMESTAMP"); 210 + 211 + if (!str || !*str || !strcmp(str, "0")) 212 + return; 213 + 214 + use_arch_timestamp = 1; 215 + } 216 + 225 217 void *jvmti_open(void) 226 218 { 227 219 int pad_cnt; ··· 241 211 int fd; 242 212 FILE *fp; 243 213 214 + init_arch_timestamp(); 215 + 244 216 /* 245 217 * check if clockid is supported 246 218 */ 247 - if (!perf_get_timestamp()) 248 - warnx("jvmti: kernel does not support %d clock id", perf_clk_id); 219 + if (!perf_get_timestamp()) { 220 + if (use_arch_timestamp) 221 + warnx("jvmti: arch timestamp not supported"); 222 + else 223 + warnx("jvmti: kernel does not support %d clock id", perf_clk_id); 224 + } 249 225 250 226 memset(&header, 0, sizeof(header)); 251 227 ··· 298 262 header.total_size += pad_cnt; 299 263 300 264 header.timestamp = perf_get_timestamp(); 265 + 266 + if (use_arch_timestamp) 267 + header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP; 301 268 302 269 if (!fwrite(&header, sizeof(header), 1, fp)) { 303 270 warn("jvmti: cannot write dumpfile header");
+1 -2
tools/perf/util/Build
··· 69 69 libperf-y += record.o 70 70 libperf-y += srcline.o 71 71 libperf-y += data.o 72 - libperf-$(CONFIG_X86) += tsc.o 73 - libperf-$(CONFIG_AUXTRACE) += tsc.o 72 + libperf-y += tsc.o 74 73 libperf-y += cloexec.o 75 74 libperf-y += thread-stack.o 76 75 libperf-$(CONFIG_AUXTRACE) += auxtrace.o
+32 -5
tools/perf/util/jitdump.c
··· 17 17 #include "strlist.h" 18 18 #include <elf.h> 19 19 20 + #include "tsc.h" 20 21 #include "session.h" 21 22 #include "jit.h" 22 23 #include "jitdump.h" ··· 34 33 size_t bufsize; 35 34 FILE *in; 36 35 bool needs_bswap; /* handles cross-endianess */ 36 + bool use_arch_timestamp; 37 37 void *debug_data; 38 38 size_t nr_debug_entries; 39 39 uint32_t code_load_count; ··· 160 158 header.flags = bswap_64(header.flags); 161 159 } 162 160 161 + jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP; 162 + 163 163 if (verbose > 2) 164 - pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n", 164 + pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n", 165 165 header.version, 166 166 header.total_size, 167 167 (unsigned long long)header.timestamp, 168 168 header.pid, 169 - header.elf_mach); 169 + header.elf_mach, 170 + jd->use_arch_timestamp); 170 171 171 172 if (header.flags & JITDUMP_FLAGS_RESERVED) { 172 173 pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n", ··· 177 172 goto error; 178 173 } 179 174 175 + if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) { 176 + pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n"); 177 + goto error; 178 + } 179 + 180 180 /* 181 181 * validate event is using the correct clockid 182 182 */ 183 - if (jit_validate_events(jd->session)) { 183 + if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) { 184 184 pr_err("error, jitted code must be sampled with perf record -k 1\n"); 185 185 goto error; 186 186 } ··· 339 329 return 0; 340 330 } 341 331 332 + static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp) 333 + { 334 + struct perf_tsc_conversion tc; 335 + 336 + if (!jd->use_arch_timestamp) 337 + return timestamp; 338 + 339 + tc.time_shift = jd->session->time_conv.time_shift; 340 + tc.time_mult = jd->session->time_conv.time_mult; 341 + tc.time_zero = jd->session->time_conv.time_zero; 342 + 343 + if (!tc.time_mult) 344 + return 0; 345 + 346 + return tsc_to_perf_time(timestamp, &tc); 347 + } 348 + 342 349 static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) 343 350 { 344 351 struct perf_sample sample; ··· 437 410 id->tid = tid; 438 411 } 439 412 if (jd->sample_type & PERF_SAMPLE_TIME) 440 - id->time = jr->load.p.timestamp; 413 + id->time = convert_timestamp(jd, jr->load.p.timestamp); 441 414 442 415 /* 443 416 * create pseudo sample to induce dso hit increment ··· 526 499 id->tid = tid; 527 500 } 528 501 if (jd->sample_type & PERF_SAMPLE_TIME) 529 - id->time = jr->load.p.timestamp; 502 + id->time = convert_timestamp(jd, jr->load.p.timestamp); 530 503 531 504 /* 532 505 * create pseudo sample to induce dso hit increment
+3
tools/perf/util/jitdump.h
··· 23 23 #define JITHEADER_VERSION 1 24 24 25 25 enum jitdump_flags_bits { 26 + JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT, 26 27 JITDUMP_FLAGS_MAX_BIT, 27 28 }; 29 + 30 + #define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT) 28 31 29 32 #define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \ 30 33 (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
+10 -1
tools/perf/util/tsc.h
··· 4 4 #include <linux/types.h> 5 5 6 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 18 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); 10 19 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);