]> Git Repo - linux.git/blob - tools/perf/arch/x86/util/tsc.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[linux.git] / tools / perf / arch / x86 / util / tsc.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/types.h>
3 #include <math.h>
4 #include <string.h>
5 #include <stdlib.h>
6
7 #include "../../../util/debug.h"
8 #include "../../../util/tsc.h"
9 #include "cpuid.h"
10
11 u64 rdtsc(void)
12 {
13         unsigned int low, high;
14
15         asm volatile("rdtsc" : "=a" (low), "=d" (high));
16
17         return low | ((u64)high) << 32;
18 }
19
20 /*
21  * Derive the TSC frequency in Hz from the /proc/cpuinfo, for example:
22  * ...
23  * model name      : Intel(R) Xeon(R) Gold 6154 CPU @ 3.00GHz
24  * ...
25  * will return 3000000000.
26  */
27 static double cpuinfo_tsc_freq(void)
28 {
29         double result = 0;
30         FILE *cpuinfo;
31         char *line = NULL;
32         size_t len = 0;
33
34         cpuinfo = fopen("/proc/cpuinfo", "r");
35         if (!cpuinfo) {
36                 pr_err("Failed to read /proc/cpuinfo for TSC frequency");
37                 return NAN;
38         }
39         while (getline(&line, &len, cpuinfo) > 0) {
40                 if (!strncmp(line, "model name", 10)) {
41                         char *pos = strstr(line + 11, " @ ");
42
43                         if (pos && sscanf(pos, " @ %lfGHz", &result) == 1) {
44                                 result *= 1000000000;
45                                 goto out;
46                         }
47                 }
48         }
49 out:
50         if (fpclassify(result) == FP_ZERO)
51                 pr_err("Failed to find TSC frequency in /proc/cpuinfo");
52
53         free(line);
54         fclose(cpuinfo);
55         return result;
56 }
57
58 double arch_get_tsc_freq(void)
59 {
60         unsigned int a, b, c, d, lvl;
61         static bool cached;
62         static double tsc;
63         char vendor[16];
64
65         if (cached)
66                 return tsc;
67
68         cached = true;
69         get_cpuid_0(vendor, &lvl);
70         if (!strstr(vendor, "Intel"))
71                 return 0;
72
73         /*
74          * Don't support Time Stamp Counter and
75          * Nominal Core Crystal Clock Information Leaf.
76          */
77         if (lvl < 0x15) {
78                 tsc = cpuinfo_tsc_freq();
79                 return tsc;
80         }
81
82         cpuid(0x15, 0, &a, &b, &c, &d);
83         /* TSC frequency is not enumerated */
84         if (!a || !b || !c) {
85                 tsc = cpuinfo_tsc_freq();
86                 return tsc;
87         }
88
89         tsc = (double)c * (double)b / (double)a;
90         return tsc;
91 }
This page took 0.037242 seconds and 4 git commands to generate.