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