]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gprofng/common/cpu_frequency.h
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gprofng / common / cpu_frequency.h
CommitLineData
fd67aa11 1/* Copyright (C) 2021-2024 Free Software Foundation, Inc.
bb368aad
VM
2 Contributed by Oracle.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21#ifndef _CPU_FREQUENCY_H
22#define _CPU_FREQUENCY_H
23
24#ifdef __cplusplus
25extern "C"
26{
27#endif
28
29#include <alloca.h>
30#include <unistd.h> /* processor_info_t */
31#include <fcntl.h>
32
33 typedef unsigned char uint8_t;
34
35#define MAXSTRLEN 1024
36 /*
37 * This file provide the api to detect Intel CPU frequency variation features
38 */
39
40#define COL_CPUFREQ_NONE 0x0000
41#define COL_CPUFREQ_SCALING 0x0001
42#define COL_CPUFREQ_TURBO 0x0002
43
44#if defined(__i386__) || defined(__x86_64)
45 // XXXX This is a rough table to estimate frequency increment due to intel turbo boost.
46 // CPU with different stepping and different core number have different turbo increment.
47 // It is used internally here, and is not implemented on SPARC
48
49 // YLM: one can use cputrack to estimate max turbo frequency
50 // example: for a cpu-bound app that runs for > 10 seconds, count cycles for 10 seconds:
51 // cputrack -T 10 -v -c cpu_clk_unhalted.thread_p a.out
52
53 static int
54 get_max_turbo_freq (int model)
55 {
56 switch (model)
57 {
58 // Nehalem
59 case 30:// Core i7-870: 2/2/4/5
60 return 2 * 133333;
61 case 26:// Xeon L5520: 1/1/1/2
62 return 2 * 133333;
63 case 46:// Xeon E7540: 2
64 return 2 * 133333;
65 // Westmere
66 case 37:// Core i5-520M: 2/4
67 return 2 * 133333;
68 case 44:// Xeon E5620: 1/1/2/2
69 return 2 * 133333;
70 case 47:// Xeon E7-2820: 1/1/1/2
71 return 1 * 133333;
72 // Sandy Bridge
73 case 42:// Core i5-2500: 1/2/3/4
74 return 3 * 100000;
75 // http://ark.intel.com/products/64584/Intel-Xeon-Processor-E5-2660-20M-Cache-2_20-GHz-8_00-GTs-Intel-QPI
76 case 45:// Xeon E5-2660 GenuineIntel 206D7 family 6 model 45 step 7 clock 2200 MHz
77 return 8 * 100000;
78 // Ivy Bridge
79 case 58:// Core i7-3770: 3/4/5/5
80 return 4 * 100000;
81 case 62:// Xeon E5-2697: 3/3/3/3/3/3/3/4/5/6/7/8
82 return 7 * 100000;
83 // Haswell
84 case 60:
85 return 789000; // empirically we see 3189 MHz - 2400 MHz
86 case 63:
87 return 1280000; // empirically we see 3580 MHz - 2300 MHz for single-threaded
88 // return 500000; // empirically we see 2800 MHz - 2300 MHz for large throughput
89 // Broadwell
90 // where are these values listed?
91 // maybe try https://en.wikipedia.org/wiki/Broadwell_%28microarchitecture%29#Server_processors
92 case 61:
93 return 400000;
94 case 71:
95 return 400000;
96 case 79:
97 return 950000; // empirically we see (3550-2600) MHz for single-threaded on x6-2a
98 case 85:
99 return 1600000; // X7: empirically see ~3.7GHz with single thread, baseline is 2.1Ghz Return 3,700,000-2,100,000
100 case 31: // Nehalem?
101 case 28: // Atom
102 case 69: // Haswell
103 case 70: // Haswell
104 case 78: // Skylake
105 case 94: // Skylake
106 default:
107 return 0;
108 }
109 }
110#endif
111
112 /*
113 * parameter: mode, pointer to a 8bit mode indicator
114 * return: max cpu frequency in MHz
115 */
116 //YXXX Updating this function? Check similar cut/paste code in:
117 // collctrl.cc::Coll_Ctrl()
118 // collector.c::log_header_write()
119 // cpu_frequency.h::get_cpu_frequency()
120
121 static int
122 get_cpu_frequency (uint8_t *mode)
123 {
124 int ret_freq = 0;
125 if (mode != NULL)
126 *mode = COL_CPUFREQ_NONE;
127 FILE *procf = fopen ("/proc/cpuinfo", "r");
128 if (procf != NULL)
129 {
130 char temp[1024];
131 int cpu = -1;
132#if defined(__i386__) || defined(__x86_64)
133 int model = -1;
134 int family = -1;
135#endif
136 while (fgets (temp, 1024, procf) != NULL)
137 {
138 if (strncmp (temp, "processor", strlen ("processor")) == 0)
139 {
140 char *val = strchr (temp, ':');
141 cpu = val ? atoi (val + 1) : -1;
142 }
143#if defined(__i386__) || defined(__x86_64)
144 else if (strncmp (temp, "model", strlen ("model")) == 0
145 && strstr (temp, "name") == 0)
146 {
147 char *val = strchr (temp, ':');
148 model = val ? atoi (val + 1) : -1;
149 }
150 else if (strncmp (temp, "cpu family", strlen ("cpu family")) == 0)
151 {
152 char *val = strchr (temp, ':');
153 family = val ? atoi (val + 1) : -1;
154 }
155#endif
156 else if (strncmp (temp, "cpu MHz", strlen ("cpu MHz")) == 0)
157 {
158 char *val = strchr (temp, ':');
159 int mhz = val ? atoi (val + 1) : 0; /* reading it as int is fine */
160 char scaling_freq_file[MAXSTRLEN + 1];
161 snprintf (scaling_freq_file, sizeof (scaling_freq_file),
162 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_driver", cpu);
163 int intel_pstate = 0;
164 int no_turbo = 0;
165 if (access (scaling_freq_file, R_OK) == 0)
166 {
167 FILE *cpufreqd = fopen (scaling_freq_file, "r");
168 if (cpufreqd != NULL)
169 {
170 if (fgets (temp, 1024, cpufreqd) != NULL
171 && strncmp (temp, "intel_pstate", sizeof ("intel_pstate") - 1) == 0)
172 intel_pstate = 1;
173 fclose (cpufreqd);
174 }
175 }
176 snprintf (scaling_freq_file, sizeof (scaling_freq_file),
177 "/sys/devices/system/cpu/intel_pstate/no_turbo");
178 if (access (scaling_freq_file, R_OK) == 0)
179 {
180 FILE *pstatent = fopen (scaling_freq_file, "r");
181 if (pstatent != NULL)
182 {
183 if (fgets (temp, 1024, pstatent) != NULL)
184 if (strncmp (temp, "1", sizeof ("1") - 1) == 0)
185 no_turbo = 1;
186 fclose (pstatent);
187 }
188 }
189
190 snprintf (scaling_freq_file, sizeof (scaling_freq_file),
191 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu);
192 int frequency_scaling = 0;
193 int turbo_mode = 0;
194 if (access (scaling_freq_file, R_OK) == 0)
195 {
196 FILE *cpufreqf = fopen (scaling_freq_file, "r");
197 if (cpufreqf != NULL)
198 {
199 if (fgets (temp, 1024, cpufreqf) != NULL)
200 {
201 int ondemand = 0;
202 if (strncmp (temp, "ondemand", sizeof ("ondemand") - 1) == 0)
203 ondemand = 1;
204 int performance = 0;
205 if (strncmp (temp, "performance", sizeof ("performance") - 1) == 0)
206 performance = 1;
207 int powersave = 0;
208 if (strncmp (temp, "powersave", sizeof ("powersave") - 1) == 0)
209 powersave = 1;
210 if (intel_pstate || ondemand || performance)
211 {
212 snprintf (scaling_freq_file, sizeof (scaling_freq_file),
213 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
214 if (access (scaling_freq_file, R_OK) == 0)
215 {
216 FILE * cpufreqf_max;
217 if ((cpufreqf_max = fopen (scaling_freq_file, "r")) != NULL)
218 {
219 if (fgets (temp, 1024, cpufreqf_max) != NULL)
220 {
221 int tmpmhz = atoi (temp);
222 snprintf (scaling_freq_file, sizeof (scaling_freq_file),
223 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_available_frequencies", cpu);
224 if (intel_pstate)
225 {
226 frequency_scaling = 1;
227 turbo_mode = !no_turbo;
228 if (powersave)
229 // the system might have been relatively cold
230 // so we might do better with scaling_max_freq
231 mhz = (int) (((double) tmpmhz / 1000.0) + 0.5);
232 }
233 else if (access (scaling_freq_file, R_OK) == 0)
234 {
235 FILE * cpufreqf_ava;
236 if ((cpufreqf_ava = fopen (scaling_freq_file, "r")) != NULL)
237 {
238 if (fgets (temp, 1024, cpufreqf_ava) != NULL)
239 {
240 if (strchr (temp, ' ') != strrchr (temp, ' ') && ondemand)
241 frequency_scaling = 1;
242 if (tmpmhz > 1000)
243 {
244#if defined(__i386__) || defined(__x86_64)
245 if (family == 6)
246 {
247 // test turbo mode
248 char non_turbo_max_freq[1024];
249 snprintf (non_turbo_max_freq, sizeof (non_turbo_max_freq),
250 "%d", tmpmhz - 1000);
251 if (strstr (temp, non_turbo_max_freq))
252 {
253 turbo_mode = 1;
254 tmpmhz = (tmpmhz - 1000) + get_max_turbo_freq (model);
255 }
256 }
257#endif
258 }
259 }
260 fclose (cpufreqf_ava);
261 }
262 mhz = (int) (((double) tmpmhz / 1000.0) + 0.5);
263 }
264 }
265 fclose (cpufreqf_max);
266 }
267 }
268 }
269 }
270 fclose (cpufreqf);
271 }
272 }
273 if (mhz > ret_freq)
274 ret_freq = mhz;
275 if (frequency_scaling && mode != NULL)
276 *mode |= COL_CPUFREQ_SCALING;
277 if (turbo_mode && mode != NULL)
278 *mode |= COL_CPUFREQ_TURBO;
279 }
280 else if (strncmp (temp, "Cpu", 3) == 0 && temp[3] != '\0' &&
281 strncmp (strchr (temp + 1, 'C') ? strchr (temp + 1, 'C') : (temp + 4), "ClkTck", 6) == 0)
282 { // sparc-Linux
283 char *val = strchr (temp, ':');
284 if (val)
285 {
286 unsigned long long freq;
287 sscanf (val + 2, "%llx", &freq);
288 int mhz = (unsigned int) (((double) freq) / 1000000.0 + 0.5);
289 if (mhz > ret_freq)
290 ret_freq = mhz;
291 }
292 }
293 }
294 fclose (procf);
295 }
296 return ret_freq;
297 }
298
299#ifdef __cplusplus
300}
301#endif
302
303#endif /*_CPU_FREQUENCY_H*/