diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2013-06-28 15:22:19 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-07-23 12:17:59 +0200 |
commit | 3bd5a5fc8c6b9fe769777abf74b0ab5fbd7930b4 (patch) | |
tree | ac509b983fe147d6706449c3bc14031591807585 /tools/perf/arch | |
parent | perf/x86: Add ability to calculate TSC from perf sample timestamps (diff) | |
download | linux-3bd5a5fc8c6b9fe769777abf74b0ab5fbd7930b4.tar.xz linux-3bd5a5fc8c6b9fe769777abf74b0ab5fbd7930b4.zip |
perf tools: Add test for converting perf time to/from TSC
The test uses the newly added cap_usr_time_zero and time_zero of
perf_event_mmap_page. TSC from rdtsc is compared with the time
from 2 perf events. The test passes if the calculated times are
all in the correct order.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/1372425741-1676-4-git-send-email-adrian.hunter@intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/arch')
-rw-r--r-- | tools/perf/arch/x86/Makefile | 2 | ||||
-rw-r--r-- | tools/perf/arch/x86/util/tsc.c | 59 | ||||
-rw-r--r-- | tools/perf/arch/x86/util/tsc.h | 20 |
3 files changed, 81 insertions, 0 deletions
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index 815841c04eb2..8801fe02f206 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile @@ -6,3 +6,5 @@ ifndef NO_LIBUNWIND LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o endif LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o +LIB_H += arch/$(ARCH)/util/tsc.h diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c new file mode 100644 index 000000000000..f1117441cdcd --- /dev/null +++ b/tools/perf/arch/x86/util/tsc.c @@ -0,0 +1,59 @@ +#include <stdbool.h> +#include <errno.h> + +#include <linux/perf_event.h> + +#include "../../perf.h" +#include "../../util/types.h" +#include "../../util/debug.h" +#include "tsc.h" + +u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc) +{ + u64 time, quot, rem; + + time = ns - tc->time_zero; + quot = time / tc->time_mult; + rem = time % tc->time_mult; + return (quot << tc->time_shift) + + (rem << tc->time_shift) / tc->time_mult; +} + +u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) +{ + u64 quot, rem; + + quot = cyc >> tc->time_shift; + rem = cyc & ((1 << tc->time_shift) - 1); + return tc->time_zero + quot * tc->time_mult + + ((rem * tc->time_mult) >> tc->time_shift); +} + +int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, + struct perf_tsc_conversion *tc) +{ + bool cap_usr_time_zero; + u32 seq; + int i = 0; + + while (1) { + seq = pc->lock; + rmb(); + tc->time_mult = pc->time_mult; + tc->time_shift = pc->time_shift; + tc->time_zero = pc->time_zero; + cap_usr_time_zero = pc->cap_usr_time_zero; + rmb(); + if (pc->lock == seq && !(seq & 1)) + break; + if (++i > 10000) { + pr_debug("failed to get perf_event_mmap_page lock\n"); + return -EINVAL; + } + } + + if (!cap_usr_time_zero) + return -EOPNOTSUPP; + + return 0; +} diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h new file mode 100644 index 000000000000..a24dec81c795 --- /dev/null +++ b/tools/perf/arch/x86/util/tsc.h @@ -0,0 +1,20 @@ +#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ +#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ + +#include "../../util/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); + +u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); +u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); + +#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ |