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.hun...@intel.com>
---

Changes in V2:

        Fixed "From" and "Signed-off-by" email addresses

 tools/perf/jvmti/jvmti_agent.c | 43 ++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/jitdump.c      | 37 +++++++++++++++++++++++++++++++-----
 tools/perf/util/jitdump.h      |  3 +++
 3 files changed, 76 insertions(+), 7 deletions(-)

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:
        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;
 
@@ -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;
@@ -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;
@@ -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));
 
@@ -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;
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index cd272cc21e05..5608179dff34 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -17,6 +17,7 @@
 #include "strlist.h"
 #include <elf.h>
 
+#include "tsc.h"
 #include "session.h"
 #include "jit.h"
 #include "jitdump.h"
@@ -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;
@@ -158,13 +160,16 @@ 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",
@@ -172,10 +177,15 @@ jit_open(struct jit_buf_desc *jd, const char *name)
                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;
        }
@@ -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;
@@ -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
@@ -498,7 +525,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
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 @@
 #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)
 
-- 
1.9.1

Reply via email to