Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/perf/arch/x86/util/tsc.c
26289 views
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 u64 cpuinfo_tsc_freq(void)
28
{
29
u64 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\n");
37
return 0;
38
}
39
while (getline(&line, &len, cpuinfo) > 0) {
40
if (!strncmp(line, "model name", 10)) {
41
char *pos = strstr(line + 11, " @ ");
42
double float_result;
43
44
if (pos && sscanf(pos, " @ %lfGHz", &float_result) == 1) {
45
float_result *= 1000000000;
46
result = (u64)float_result;
47
goto out;
48
}
49
}
50
}
51
out:
52
if (result == 0)
53
pr_err("Failed to find TSC frequency in /proc/cpuinfo\n");
54
55
free(line);
56
fclose(cpuinfo);
57
return result;
58
}
59
60
u64 arch_get_tsc_freq(void)
61
{
62
unsigned int a, b, c, d, lvl;
63
static bool cached;
64
static double tsc;
65
char vendor[16];
66
67
if (cached)
68
return tsc;
69
70
cached = true;
71
get_cpuid_0(vendor, &lvl);
72
if (!strstr(vendor, "Intel"))
73
return 0;
74
75
/*
76
* Don't support Time Stamp Counter and
77
* Nominal Core Crystal Clock Information Leaf.
78
*/
79
if (lvl < 0x15) {
80
tsc = cpuinfo_tsc_freq();
81
return tsc;
82
}
83
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;
89
}
90
91
tsc = (u64)c * (u64)b / (u64)a;
92
return tsc;
93
}
94
95