Skip to content

Commit

Permalink
perf/x86: Add ability to calculate TSC from perf sample timestamps
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Adrian Hunter authored and Ingo Molnar committed Jul 23, 2013
1 parent 860f085 commit c73deb6
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 2 deletions.
1 change: 1 addition & 0 deletions arch/x86/include/asm/tsc.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ extern void tsc_init(void);
extern void mark_tsc_unstable(char *reason);
extern int unsynchronized_tsc(void);
extern int check_tsc_unstable(void);
extern int check_tsc_disabled(void);
extern unsigned long native_calibrate_tsc(void);

extern int tsc_clocksource_reliable;
Expand Down
6 changes: 6 additions & 0 deletions arch/x86/kernel/cpu/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,7 @@ static struct pmu pmu = {
void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
{
userpg->cap_usr_time = 0;
userpg->cap_usr_time_zero = 0;
userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc;
userpg->pmc_width = x86_pmu.cntval_bits;

Expand All @@ -1897,6 +1898,11 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
userpg->time_mult = this_cpu_read(cyc2ns);
userpg->time_shift = CYC2NS_SCALE_FACTOR;
userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;

if (sched_clock_stable && !check_tsc_disabled()) {
userpg->cap_usr_time_zero = 1;
userpg->time_zero = this_cpu_read(cyc2ns_offset);
}
}

/*
Expand Down
6 changes: 6 additions & 0 deletions arch/x86/kernel/tsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ int check_tsc_unstable(void)
}
EXPORT_SYMBOL_GPL(check_tsc_unstable);

int check_tsc_disabled(void)
{
return tsc_disabled;
}
EXPORT_SYMBOL_GPL(check_tsc_disabled);

#ifdef CONFIG_X86_TSC
int __init notsc_setup(char *str)
{
Expand Down
22 changes: 20 additions & 2 deletions include/uapi/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,8 @@ struct perf_event_mmap_page {
struct {
__u64 cap_usr_time : 1,
cap_usr_rdpmc : 1,
cap_____res : 62;
cap_usr_time_zero : 1,
cap_____res : 61;
};
};

Expand Down Expand Up @@ -420,12 +421,29 @@ struct perf_event_mmap_page {
__u16 time_shift;
__u32 time_mult;
__u64 time_offset;
/*
* If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
* from sample timestamps.
*
* time = timestamp - time_zero;
* quot = time / time_mult;
* rem = time % time_mult;
* cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
*
* And vice versa:
*
* quot = cyc >> time_shift;
* rem = cyc & ((1 << time_shift) - 1);
* timestamp = time_zero + quot * time_mult +
* ((rem * time_mult) >> time_shift);
*/
__u64 time_zero;

/*
* Hole for extension of the self monitor capabilities
*/

__u64 __reserved[120]; /* align to 1k */
__u64 __reserved[119]; /* align to 1k */

/*
* Control data for the mmap() data buffer.
Expand Down

0 comments on commit c73deb6

Please sign in to comment.