Home | History | Annotate | Download | only in util
      1 #include <stdbool.h>
      2 #include <errno.h>
      3 
      4 #include <linux/perf_event.h>
      5 
      6 #include "../../perf.h"
      7 #include "../../util/types.h"
      8 #include "../../util/debug.h"
      9 #include "tsc.h"
     10 
     11 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
     12 {
     13 	u64 t, quot, rem;
     14 
     15 	t = ns - tc->time_zero;
     16 	quot = t / tc->time_mult;
     17 	rem  = t % tc->time_mult;
     18 	return (quot << tc->time_shift) +
     19 	       (rem << tc->time_shift) / tc->time_mult;
     20 }
     21 
     22 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
     23 {
     24 	u64 quot, rem;
     25 
     26 	quot = cyc >> tc->time_shift;
     27 	rem  = cyc & ((1 << tc->time_shift) - 1);
     28 	return tc->time_zero + quot * tc->time_mult +
     29 	       ((rem * tc->time_mult) >> tc->time_shift);
     30 }
     31 
     32 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
     33 			     struct perf_tsc_conversion *tc)
     34 {
     35 	bool cap_user_time_zero;
     36 	u32 seq;
     37 	int i = 0;
     38 
     39 	while (1) {
     40 		seq = pc->lock;
     41 		rmb();
     42 		tc->time_mult = pc->time_mult;
     43 		tc->time_shift = pc->time_shift;
     44 		tc->time_zero = pc->time_zero;
     45 		cap_user_time_zero = pc->cap_user_time_zero;
     46 		rmb();
     47 		if (pc->lock == seq && !(seq & 1))
     48 			break;
     49 		if (++i > 10000) {
     50 			pr_debug("failed to get perf_event_mmap_page lock\n");
     51 			return -EINVAL;
     52 		}
     53 	}
     54 
     55 	if (!cap_user_time_zero)
     56 		return -EOPNOTSUPP;
     57 
     58 	return 0;
     59 }
     60