Commit 2a28e230 authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo

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: default avatarAdrian 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.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 46bc29b9
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <linux/types.h> #include <linux/types.h>
#include "../../util/debug.h" #include "../../util/debug.h"
#include "../../util/tsc.h" #include "../../util/tsc.h"
#include "tsc.h"
int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
struct perf_tsc_conversion *tc) struct perf_tsc_conversion *tc)
......
#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
#include <linux/types.h>
struct perf_tsc_conversion {
u16 time_shift;
u32 time_mult;
u64 time_zero;
};
struct perf_event_mmap_page;
int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
struct perf_tsc_conversion *tc);
#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
...@@ -92,6 +92,22 @@ static int get_e_machine(struct jitheader *hdr) ...@@ -92,6 +92,22 @@ static int get_e_machine(struct jitheader *hdr)
return ret; return ret;
} }
static int use_arch_timestamp;
static inline uint64_t
get_arch_timestamp(void)
{
#if defined(__i386__) || defined(__x86_64__)
unsigned int low, high;
asm volatile("rdtsc" : "=a" (low), "=d" (high));
return low | ((uint64_t)high) << 32;
#else
return 0;
#endif
}
#define NSEC_PER_SEC 1000000000 #define NSEC_PER_SEC 1000000000
static int perf_clk_id = CLOCK_MONOTONIC; static int perf_clk_id = CLOCK_MONOTONIC;
...@@ -107,6 +123,9 @@ perf_get_timestamp(void) ...@@ -107,6 +123,9 @@ perf_get_timestamp(void)
struct timespec ts; struct timespec ts;
int ret; int ret;
if (use_arch_timestamp)
return get_arch_timestamp();
ret = clock_gettime(perf_clk_id, &ts); ret = clock_gettime(perf_clk_id, &ts);
if (ret) if (ret)
return 0; return 0;
...@@ -203,6 +222,17 @@ perf_close_marker_file(void) ...@@ -203,6 +222,17 @@ perf_close_marker_file(void)
munmap(marker_addr, pgsz); munmap(marker_addr, pgsz);
} }
static void
init_arch_timestamp(void)
{
char *str = getenv("JITDUMP_USE_ARCH_TIMESTAMP");
if (!str || !*str || !strcmp(str, "0"))
return;
use_arch_timestamp = 1;
}
void *jvmti_open(void) void *jvmti_open(void)
{ {
int pad_cnt; int pad_cnt;
...@@ -211,11 +241,17 @@ void *jvmti_open(void) ...@@ -211,11 +241,17 @@ void *jvmti_open(void)
int fd; int fd;
FILE *fp; FILE *fp;
init_arch_timestamp();
/* /*
* check if clockid is supported * check if clockid is supported
*/ */
if (!perf_get_timestamp()) if (!perf_get_timestamp()) {
warnx("jvmti: kernel does not support %d clock id", perf_clk_id); if (use_arch_timestamp)
warnx("jvmti: arch timestamp not supported");
else
warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
}
memset(&header, 0, sizeof(header)); memset(&header, 0, sizeof(header));
...@@ -263,6 +299,9 @@ void *jvmti_open(void) ...@@ -263,6 +299,9 @@ void *jvmti_open(void)
header.timestamp = perf_get_timestamp(); header.timestamp = perf_get_timestamp();
if (use_arch_timestamp)
header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP;
if (!fwrite(&header, sizeof(header), 1, fp)) { if (!fwrite(&header, sizeof(header), 1, fp)) {
warn("jvmti: cannot write dumpfile header"); warn("jvmti: cannot write dumpfile header");
goto error; goto error;
......
...@@ -69,8 +69,7 @@ libperf-y += stat-shadow.o ...@@ -69,8 +69,7 @@ libperf-y += stat-shadow.o
libperf-y += record.o libperf-y += record.o
libperf-y += srcline.o libperf-y += srcline.o
libperf-y += data.o libperf-y += data.o
libperf-$(CONFIG_X86) += tsc.o libperf-y += tsc.o
libperf-$(CONFIG_AUXTRACE) += tsc.o
libperf-y += cloexec.o libperf-y += cloexec.o
libperf-y += thread-stack.o libperf-y += thread-stack.o
libperf-$(CONFIG_AUXTRACE) += auxtrace.o libperf-$(CONFIG_AUXTRACE) += auxtrace.o
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "strlist.h" #include "strlist.h"
#include <elf.h> #include <elf.h>
#include "tsc.h"
#include "session.h" #include "session.h"
#include "jit.h" #include "jit.h"
#include "jitdump.h" #include "jitdump.h"
...@@ -33,6 +34,7 @@ struct jit_buf_desc { ...@@ -33,6 +34,7 @@ struct jit_buf_desc {
size_t bufsize; size_t bufsize;
FILE *in; FILE *in;
bool needs_bswap; /* handles cross-endianess */ bool needs_bswap; /* handles cross-endianess */
bool use_arch_timestamp;
void *debug_data; void *debug_data;
size_t nr_debug_entries; size_t nr_debug_entries;
uint32_t code_load_count; uint32_t code_load_count;
...@@ -158,13 +160,16 @@ jit_open(struct jit_buf_desc *jd, const char *name) ...@@ -158,13 +160,16 @@ jit_open(struct jit_buf_desc *jd, const char *name)
header.flags = bswap_64(header.flags); header.flags = bswap_64(header.flags);
} }
jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP;
if (verbose > 2) if (verbose > 2)
pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n", pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n",
header.version, header.version,
header.total_size, header.total_size,
(unsigned long long)header.timestamp, (unsigned long long)header.timestamp,
header.pid, header.pid,
header.elf_mach); header.elf_mach,
jd->use_arch_timestamp);
if (header.flags & JITDUMP_FLAGS_RESERVED) { if (header.flags & JITDUMP_FLAGS_RESERVED) {
pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n", 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,10 +177,15 @@ jit_open(struct jit_buf_desc *jd, const char *name)
goto error; goto error;
} }
if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) {
pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n");
goto error;
}
/* /*
* validate event is using the correct clockid * validate event is using the correct clockid
*/ */
if (jit_validate_events(jd->session)) { if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) {
pr_err("error, jitted code must be sampled with perf record -k 1\n"); pr_err("error, jitted code must be sampled with perf record -k 1\n");
goto error; goto error;
} }
...@@ -329,6 +339,23 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event) ...@@ -329,6 +339,23 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
return 0; return 0;
} }
static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp)
{
struct perf_tsc_conversion tc;
if (!jd->use_arch_timestamp)
return timestamp;
tc.time_shift = jd->session->time_conv.time_shift;
tc.time_mult = jd->session->time_conv.time_mult;
tc.time_zero = jd->session->time_conv.time_zero;
if (!tc.time_mult)
return 0;
return tsc_to_perf_time(timestamp, &tc);
}
static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
{ {
struct perf_sample sample; struct perf_sample sample;
...@@ -410,7 +437,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) ...@@ -410,7 +437,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
id->tid = tid; id->tid = tid;
} }
if (jd->sample_type & PERF_SAMPLE_TIME) if (jd->sample_type & PERF_SAMPLE_TIME)
id->time = jr->load.p.timestamp; id->time = convert_timestamp(jd, jr->load.p.timestamp);
/* /*
* create pseudo sample to induce dso hit increment * 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,7 +526,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
id->tid = tid; id->tid = tid;
} }
if (jd->sample_type & PERF_SAMPLE_TIME) if (jd->sample_type & PERF_SAMPLE_TIME)
id->time = jr->load.p.timestamp; id->time = convert_timestamp(jd, jr->load.p.timestamp);
/* /*
* create pseudo sample to induce dso hit increment * create pseudo sample to induce dso hit increment
......
...@@ -23,9 +23,12 @@ ...@@ -23,9 +23,12 @@
#define JITHEADER_VERSION 1 #define JITHEADER_VERSION 1
enum jitdump_flags_bits { enum jitdump_flags_bits {
JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT,
JITDUMP_FLAGS_MAX_BIT, JITDUMP_FLAGS_MAX_BIT,
}; };
#define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT)
#define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \ #define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \
(~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0) (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
......
...@@ -4,7 +4,16 @@ ...@@ -4,7 +4,16 @@
#include <linux/types.h> #include <linux/types.h>
#include "event.h" #include "event.h"
#include "../arch/x86/util/tsc.h"
struct perf_tsc_conversion {
u16 time_shift;
u32 time_mult;
u64 time_zero;
};
struct perf_event_mmap_page;
int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
struct perf_tsc_conversion *tc);
u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment