1 #include <stdbool.h> 2 #include <errno.h> 3 4 #include <linux/perf_event.h> 5 6 #include "../../perf.h" 7 #include <linux/types.h> 8 #include "../../util/debug.h" 9 #include "../../util/tsc.h" 10 11 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, 12 struct perf_tsc_conversion *tc) 13 { 14 bool cap_user_time_zero; 15 u32 seq; 16 int i = 0; 17 18 while (1) { 19 seq = pc->lock; 20 rmb(); 21 tc->time_mult = pc->time_mult; 22 tc->time_shift = pc->time_shift; 23 tc->time_zero = pc->time_zero; 24 cap_user_time_zero = pc->cap_user_time_zero; 25 rmb(); 26 if (pc->lock == seq && !(seq & 1)) 27 break; 28 if (++i > 10000) { 29 pr_debug("failed to get perf_event_mmap_page lock\n"); 30 return -EINVAL; 31 } 32 } 33 34 if (!cap_user_time_zero) 35 return -EOPNOTSUPP; 36 37 return 0; 38 } 39 40 u64 rdtsc(void) 41 { 42 unsigned int low, high; 43 44 asm volatile("rdtsc" : "=a" (low), "=d" (high)); 45 46 return low | ((u64)high) << 32; 47 } 48 49 int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, 50 struct perf_tool *tool, 51 perf_event__handler_t process, 52 struct machine *machine) 53 { 54 union perf_event event = { 55 .time_conv = { 56 .header = { 57 .type = PERF_RECORD_TIME_CONV, 58 .size = sizeof(struct time_conv_event), 59 }, 60 }, 61 }; 62 struct perf_tsc_conversion tc; 63 int err; 64 65 if (!pc) 66 return 0; 67 err = perf_read_tsc_conversion(pc, &tc); 68 if (err == -EOPNOTSUPP) 69 return 0; 70 if (err) 71 return err; 72 73 pr_debug2("Synthesizing TSC conversion information\n"); 74 75 event.time_conv.time_mult = tc.time_mult; 76 event.time_conv.time_shift = tc.time_shift; 77 event.time_conv.time_zero = tc.time_zero; 78 79 return process(tool, &event, NULL, machine); 80 } 81