1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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)
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.
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. */
21 #ifndef _CPU_FREQUENCY_H
22 #define _CPU_FREQUENCY_H
30 #include <unistd.h> /* processor_info_t */
33 typedef unsigned char uint8_t;
35 #define MAXSTRLEN 1024
37 * This file provide the api to detect Intel CPU frequency variation features
40 #define COL_CPUFREQ_NONE 0x0000
41 #define COL_CPUFREQ_SCALING 0x0001
42 #define COL_CPUFREQ_TURBO 0x0002
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
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
54 get_max_turbo_freq (int model
)
59 case 30:// Core i7-870: 2/2/4/5
61 case 26:// Xeon L5520: 1/1/1/2
63 case 46:// Xeon E7540: 2
66 case 37:// Core i5-520M: 2/4
68 case 44:// Xeon E5620: 1/1/2/2
70 case 47:// Xeon E7-2820: 1/1/1/2
73 case 42:// Core i5-2500: 1/2/3/4
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
79 case 58:// Core i7-3770: 3/4/5/5
81 case 62:// Xeon E5-2697: 3/3/3/3/3/3/3/4/5/6/7/8
85 return 789000; // empirically we see 3189 MHz - 2400 MHz
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
90 // where are these values listed?
91 // maybe try https://en.wikipedia.org/wiki/Broadwell_%28microarchitecture%29#Server_processors
97 return 950000; // empirically we see (3550-2600) MHz for single-threaded on x6-2a
99 return 1600000; // X7: empirically see ~3.7GHz with single thread, baseline is 2.1Ghz Return 3,700,000-2,100,000
113 * parameter: mode, pointer to a 8bit mode indicator
114 * return: max cpu frequency in MHz
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()
122 get_cpu_frequency (uint8_t *mode
)
126 *mode
= COL_CPUFREQ_NONE
;
127 FILE *procf
= fopen ("/proc/cpuinfo", "r");
132 #if defined(__i386__) || defined(__x86_64)
136 while (fgets (temp
, 1024, procf
) != NULL
)
138 if (strncmp (temp
, "processor", strlen ("processor")) == 0)
140 char *val
= strchr (temp
, ':');
141 cpu
= val
? atoi (val
+ 1) : -1;
143 #if defined(__i386__) || defined(__x86_64)
144 else if (strncmp (temp
, "model", strlen ("model")) == 0
145 && strstr (temp
, "name") == 0)
147 char *val
= strchr (temp
, ':');
148 model
= val
? atoi (val
+ 1) : -1;
150 else if (strncmp (temp
, "cpu family", strlen ("cpu family")) == 0)
152 char *val
= strchr (temp
, ':');
153 family
= val
? atoi (val
+ 1) : -1;
156 else if (strncmp (temp
, "cpu MHz", strlen ("cpu MHz")) == 0)
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;
165 if (access (scaling_freq_file
, R_OK
) == 0)
167 FILE *cpufreqd
= fopen (scaling_freq_file
, "r");
168 if (cpufreqd
!= NULL
)
170 if (fgets (temp
, 1024, cpufreqd
) != NULL
171 && strncmp (temp
, "intel_pstate", sizeof ("intel_pstate") - 1) == 0)
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)
180 FILE *pstatent
= fopen (scaling_freq_file
, "r");
181 if (pstatent
!= NULL
)
183 if (fgets (temp
, 1024, pstatent
) != NULL
)
184 if (strncmp (temp
, "1", sizeof ("1") - 1) == 0)
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;
194 if (access (scaling_freq_file
, R_OK
) == 0)
196 FILE *cpufreqf
= fopen (scaling_freq_file
, "r");
197 if (cpufreqf
!= NULL
)
199 if (fgets (temp
, 1024, cpufreqf
) != NULL
)
202 if (strncmp (temp
, "ondemand", sizeof ("ondemand") - 1) == 0)
205 if (strncmp (temp
, "performance", sizeof ("performance") - 1) == 0)
208 if (strncmp (temp
, "powersave", sizeof ("powersave") - 1) == 0)
210 if (intel_pstate
|| ondemand
|| performance
)
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)
217 if ((cpufreqf_max
= fopen (scaling_freq_file
, "r")) != NULL
)
219 if (fgets (temp
, 1024, cpufreqf_max
) != NULL
)
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
);
226 frequency_scaling
= 1;
227 turbo_mode
= !no_turbo
;
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);
233 else if (access (scaling_freq_file
, R_OK
) == 0)
236 if ((cpufreqf_ava
= fopen (scaling_freq_file
, "r")) != NULL
)
238 if (fgets (temp
, 1024, cpufreqf_ava
) != NULL
)
240 if (strchr (temp
, ' ') != strrchr (temp
, ' ') && ondemand
)
241 frequency_scaling
= 1;
244 #if defined(__i386__) || defined(__x86_64)
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
))
254 tmpmhz
= (tmpmhz
- 1000) + get_max_turbo_freq (model
);
260 fclose (cpufreqf_ava
);
262 mhz
= (int) (((double) tmpmhz
/ 1000.0) + 0.5);
265 fclose (cpufreqf_max
);
275 if (frequency_scaling
&& mode
!= NULL
)
276 *mode
|= COL_CPUFREQ_SCALING
;
277 if (turbo_mode
&& mode
!= NULL
)
278 *mode
|= COL_CPUFREQ_TURBO
;
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)
283 char *val
= strchr (temp
, ':');
286 unsigned long long freq
;
287 sscanf (val
+ 2, "%llx", &freq
);
288 int mhz
= (unsigned int) (((double) freq
) / 1000000.0 + 0.5);
303 #endif /*_CPU_FREQUENCY_H*/