diff options
Diffstat (limited to 'kernel/tools/perf/arch/x86/util/tsc.c')
-rw-r--r-- | kernel/tools/perf/arch/x86/util/tsc.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/kernel/tools/perf/arch/x86/util/tsc.c b/kernel/tools/perf/arch/x86/util/tsc.c new file mode 100644 index 000000000..fd2868490 --- /dev/null +++ b/kernel/tools/perf/arch/x86/util/tsc.c @@ -0,0 +1,48 @@ +#include <stdbool.h> +#include <errno.h> + +#include <linux/perf_event.h> + +#include "../../perf.h" +#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) +{ + bool cap_user_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_user_time_zero = pc->cap_user_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_user_time_zero) + return -EOPNOTSUPP; + + return 0; +} + +u64 rdtsc(void) +{ + unsigned int low, high; + + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + + return low | ((u64)high) << 32; +} |