Skip to content

Commit

Permalink
perf jit: Add support for using TSC as a timestamp
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: Alexander Shishkin <[email protected]>
Cc: He Kuang <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Josh Poimboeuf <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Sukadev Bhattiprolu <[email protected]>
Cc: Wang Nan <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ 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/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
  • Loading branch information
ahunter6 authored and acmel committed Apr 1, 2016
1 parent 46bc29b commit 2a28e23
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 28 deletions.
1 change: 0 additions & 1 deletion tools/perf/arch/x86/util/tsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include <linux/types.h>
#include "../../util/debug.h"
#include "../../util/tsc.h"
#include "tsc.h"

int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
struct perf_tsc_conversion *tc)
Expand Down
17 changes: 0 additions & 17 deletions tools/perf/arch/x86/util/tsc.h

This file was deleted.

43 changes: 41 additions & 2 deletions tools/perf/jvmti/jvmti_agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@ static int get_e_machine(struct jitheader *hdr)
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
static int perf_clk_id = CLOCK_MONOTONIC;

Expand All @@ -107,6 +123,9 @@ perf_get_timestamp(void)
struct timespec ts;
int ret;

if (use_arch_timestamp)
return get_arch_timestamp();

ret = clock_gettime(perf_clk_id, &ts);
if (ret)
return 0;
Expand Down Expand Up @@ -203,6 +222,17 @@ perf_close_marker_file(void)
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)
{
int pad_cnt;
Expand All @@ -211,11 +241,17 @@ void *jvmti_open(void)
int fd;
FILE *fp;

init_arch_timestamp();

/*
* check if clockid is supported
*/
if (!perf_get_timestamp())
warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
if (!perf_get_timestamp()) {
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));

Expand Down Expand Up @@ -263,6 +299,9 @@ void *jvmti_open(void)

header.timestamp = perf_get_timestamp();

if (use_arch_timestamp)
header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP;

if (!fwrite(&header, sizeof(header), 1, fp)) {
warn("jvmti: cannot write dumpfile header");
goto error;
Expand Down
3 changes: 1 addition & 2 deletions tools/perf/util/Build
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ libperf-y += stat-shadow.o
libperf-y += record.o
libperf-y += srcline.o
libperf-y += data.o
libperf-$(CONFIG_X86) += tsc.o
libperf-$(CONFIG_AUXTRACE) += tsc.o
libperf-y += tsc.o
libperf-y += cloexec.o
libperf-y += thread-stack.o
libperf-$(CONFIG_AUXTRACE) += auxtrace.o
Expand Down
37 changes: 32 additions & 5 deletions tools/perf/util/jitdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "strlist.h"
#include <elf.h>

#include "tsc.h"
#include "session.h"
#include "jit.h"
#include "jitdump.h"
Expand All @@ -33,6 +34,7 @@ struct jit_buf_desc {
size_t bufsize;
FILE *in;
bool needs_bswap; /* handles cross-endianess */
bool use_arch_timestamp;
void *debug_data;
size_t nr_debug_entries;
uint32_t code_load_count;
Expand Down Expand Up @@ -158,24 +160,32 @@ jit_open(struct jit_buf_desc *jd, const char *name)
header.flags = bswap_64(header.flags);
}

jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP;

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.total_size,
(unsigned long long)header.timestamp,
header.pid,
header.elf_mach);
header.elf_mach,
jd->use_arch_timestamp);

if (header.flags & JITDUMP_FLAGS_RESERVED) {
pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
(unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED);
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
*/
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");
goto error;
}
Expand Down Expand Up @@ -329,6 +339,23 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
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)
{
struct perf_sample sample;
Expand Down Expand Up @@ -410,7 +437,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
id->tid = tid;
}
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
Expand Down Expand Up @@ -499,7 +526,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
id->tid = tid;
}
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
Expand Down
3 changes: 3 additions & 0 deletions tools/perf/util/jitdump.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
#define JITHEADER_VERSION 1

enum jitdump_flags_bits {
JITDUMP_FLAGS_ARCH_TIMESTAMP_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 ? \
(~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)

Expand Down
11 changes: 10 additions & 1 deletion tools/perf/util/tsc.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@
#include <linux/types.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 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
Expand Down

0 comments on commit 2a28e23

Please sign in to comment.