aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2013-06-28 09:22:18 -0400
committerIngo Molnar <mingo@kernel.org>2013-07-23 06:17:45 -0400
commitc73deb6aecda2955716f31572516f09d930ef450 (patch)
tree037f7945cb4289545d5ffbe9506e071a83d6c1a6
parent860f085b74e9f0075de8140ed3a1e5b5e3e39aa8 (diff)
perf/x86: Add ability to calculate TSC from perf sample timestamps
For modern CPUs, perf clock is directly related to TSC. TSC can be calculated from perf clock and vice versa using a simple calculation. Two of the three componenets of that calculation are already exported in struct perf_event_mmap_page. This patch exports the third. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: "H. Peter Anvin" <hpa@zytor.com> Link: http://lkml.kernel.org/r/1372425741-1676-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/tsc.h1
-rw-r--r--arch/x86/kernel/cpu/perf_event.c6
-rw-r--r--arch/x86/kernel/tsc.c6
-rw-r--r--include/uapi/linux/perf_event.h22
4 files changed, 33 insertions, 2 deletions
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index c91e8b9d588b..235be70d5bb4 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -49,6 +49,7 @@ extern void tsc_init(void);
49extern void mark_tsc_unstable(char *reason); 49extern void mark_tsc_unstable(char *reason);
50extern int unsynchronized_tsc(void); 50extern int unsynchronized_tsc(void);
51extern int check_tsc_unstable(void); 51extern int check_tsc_unstable(void);
52extern int check_tsc_disabled(void);
52extern unsigned long native_calibrate_tsc(void); 53extern unsigned long native_calibrate_tsc(void);
53 54
54extern int tsc_clocksource_reliable; 55extern int tsc_clocksource_reliable;
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index a7c7305030cc..8355c84b9729 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1884,6 +1884,7 @@ static struct pmu pmu = {
1884void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now) 1884void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
1885{ 1885{
1886 userpg->cap_usr_time = 0; 1886 userpg->cap_usr_time = 0;
1887 userpg->cap_usr_time_zero = 0;
1887 userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; 1888 userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc;
1888 userpg->pmc_width = x86_pmu.cntval_bits; 1889 userpg->pmc_width = x86_pmu.cntval_bits;
1889 1890
@@ -1897,6 +1898,11 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
1897 userpg->time_mult = this_cpu_read(cyc2ns); 1898 userpg->time_mult = this_cpu_read(cyc2ns);
1898 userpg->time_shift = CYC2NS_SCALE_FACTOR; 1899 userpg->time_shift = CYC2NS_SCALE_FACTOR;
1899 userpg->time_offset = this_cpu_read(cyc2ns_offset) - now; 1900 userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
1901
1902 if (sched_clock_stable && !check_tsc_disabled()) {
1903 userpg->cap_usr_time_zero = 1;
1904 userpg->time_zero = this_cpu_read(cyc2ns_offset);
1905 }
1900} 1906}
1901 1907
1902/* 1908/*
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 6ff49247edf8..930e5d48f560 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -89,6 +89,12 @@ int check_tsc_unstable(void)
89} 89}
90EXPORT_SYMBOL_GPL(check_tsc_unstable); 90EXPORT_SYMBOL_GPL(check_tsc_unstable);
91 91
92int check_tsc_disabled(void)
93{
94 return tsc_disabled;
95}
96EXPORT_SYMBOL_GPL(check_tsc_disabled);
97
92#ifdef CONFIG_X86_TSC 98#ifdef CONFIG_X86_TSC
93int __init notsc_setup(char *str) 99int __init notsc_setup(char *str)
94{ 100{
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 0041aedf2297..efef1d37a371 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -378,7 +378,8 @@ struct perf_event_mmap_page {
378 struct { 378 struct {
379 __u64 cap_usr_time : 1, 379 __u64 cap_usr_time : 1,
380 cap_usr_rdpmc : 1, 380 cap_usr_rdpmc : 1,
381 cap_____res : 62; 381 cap_usr_time_zero : 1,
382 cap_____res : 61;
382 }; 383 };
383 }; 384 };
384 385
@@ -420,12 +421,29 @@ struct perf_event_mmap_page {
420 __u16 time_shift; 421 __u16 time_shift;
421 __u32 time_mult; 422 __u32 time_mult;
422 __u64 time_offset; 423 __u64 time_offset;
424 /*
425 * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
426 * from sample timestamps.
427 *
428 * time = timestamp - time_zero;
429 * quot = time / time_mult;
430 * rem = time % time_mult;
431 * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
432 *
433 * And vice versa:
434 *
435 * quot = cyc >> time_shift;
436 * rem = cyc & ((1 << time_shift) - 1);
437 * timestamp = time_zero + quot * time_mult +
438 * ((rem * time_mult) >> time_shift);
439 */
440 __u64 time_zero;
423 441
424 /* 442 /*
425 * Hole for extension of the self monitor capabilities 443 * Hole for extension of the self monitor capabilities
426 */ 444 */
427 445
428 __u64 __reserved[120]; /* align to 1k */ 446 __u64 __reserved[119]; /* align to 1k */
429 447
430 /* 448 /*
431 * Control data for the mmap() data buffer. 449 * Control data for the mmap() data buffer.