Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / perf / arch / x86 / util / tsc.c
blob3a439e4b12d28e3f9654b5a87add959b820149af
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/types.h>
3 #include <math.h>
4 #include <string.h>
5 #include <stdlib.h>
7 #include "../../../util/debug.h"
8 #include "../../../util/tsc.h"
9 #include "cpuid.h"
11 u64 rdtsc(void)
13 unsigned int low, high;
15 asm volatile("rdtsc" : "=a" (low), "=d" (high));
17 return low | ((u64)high) << 32;
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.
27 static u64 cpuinfo_tsc_freq(void)
29 u64 result = 0;
30 FILE *cpuinfo;
31 char *line = NULL;
32 size_t len = 0;
34 cpuinfo = fopen("/proc/cpuinfo", "r");
35 if (!cpuinfo) {
36 pr_err("Failed to read /proc/cpuinfo for TSC frequency\n");
37 return 0;
39 while (getline(&line, &len, cpuinfo) > 0) {
40 if (!strncmp(line, "model name", 10)) {
41 char *pos = strstr(line + 11, " @ ");
42 double float_result;
44 if (pos && sscanf(pos, " @ %lfGHz", &float_result) == 1) {
45 float_result *= 1000000000;
46 result = (u64)float_result;
47 goto out;
51 out:
52 if (result == 0)
53 pr_err("Failed to find TSC frequency in /proc/cpuinfo\n");
55 free(line);
56 fclose(cpuinfo);
57 return result;
60 u64 arch_get_tsc_freq(void)
62 unsigned int a, b, c, d, lvl;
63 static bool cached;
64 static double tsc;
65 char vendor[16];
67 if (cached)
68 return tsc;
70 cached = true;
71 get_cpuid_0(vendor, &lvl);
72 if (!strstr(vendor, "Intel"))
73 return 0;
76 * Don't support Time Stamp Counter and
77 * Nominal Core Crystal Clock Information Leaf.
79 if (lvl < 0x15) {
80 tsc = cpuinfo_tsc_freq();
81 return tsc;
84 cpuid(0x15, 0, &a, &b, &c, &d);
85 /* TSC frequency is not enumerated */
86 if (!a || !b || !c) {
87 tsc = cpuinfo_tsc_freq();
88 return tsc;
91 tsc = (u64)c * (u64)b / (u64)a;
92 return tsc;