^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/perf_event.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <asm/barrier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "event.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "synthetic-events.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "debug.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "tsc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) u64 t, quot, rem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) t = ns - tc->time_zero;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) quot = t / tc->time_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) rem = t % tc->time_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) return (quot << tc->time_shift) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) (rem << tc->time_shift) / tc->time_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) u64 quot, rem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (tc->cap_user_time_short)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) cyc = tc->time_cycles +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) ((cyc - tc->time_cycles) & tc->time_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) quot = cyc >> tc->time_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) rem = cyc & (((u64)1 << tc->time_shift) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return tc->time_zero + quot * tc->time_mult +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) ((rem * tc->time_mult) >> tc->time_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct perf_tsc_conversion *tc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u32 seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) seq = pc->lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) tc->time_mult = pc->time_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) tc->time_shift = pc->time_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) tc->time_zero = pc->time_zero;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) tc->time_cycles = pc->time_cycles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) tc->time_mask = pc->time_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) tc->cap_user_time_zero = pc->cap_user_time_zero;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) tc->cap_user_time_short = pc->cap_user_time_short;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (pc->lock == seq && !(seq & 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (++i > 10000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) pr_debug("failed to get perf_event_mmap_page lock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (!tc->cap_user_time_zero)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct perf_tool *tool,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) perf_event__handler_t process,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct machine *machine)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) union perf_event event = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .time_conv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .header = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .type = PERF_RECORD_TIME_CONV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .size = sizeof(struct perf_record_time_conv),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct perf_tsc_conversion tc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (!pc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) err = perf_read_tsc_conversion(pc, &tc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (err == -EOPNOTSUPP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) pr_debug2("Synthesizing TSC conversion information\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) event.time_conv.time_mult = tc.time_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) event.time_conv.time_shift = tc.time_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) event.time_conv.time_zero = tc.time_zero;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) event.time_conv.time_cycles = tc.time_cycles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) event.time_conv.time_mask = tc.time_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) event.time_conv.cap_user_time_zero = tc.cap_user_time_zero;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) event.time_conv.cap_user_time_short = tc.cap_user_time_short;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return process(tool, &event, NULL, machine);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) u64 __weak rdtsc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }