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