tsc.c 1.2 KB

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