tsc.c 1.6 KB

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