]> Git Repo - binutils.git/blob - gprofng/common/cpu_frequency.h
Automatic date update in version.in
[binutils.git] / gprofng / common / cpu_frequency.h
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
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
25 extern "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*/
This page took 0.042454 seconds and 4 git commands to generate.