1*103a8feaSLen Brown /* 2*103a8feaSLen Brown * turbostat -- show CPU frequency and C-state residency 3*103a8feaSLen Brown * on modern Intel turbo-capable processors. 4*103a8feaSLen Brown * 5*103a8feaSLen Brown * Copyright (c) 2010, Intel Corporation. 6*103a8feaSLen Brown * Len Brown <len.brown@intel.com> 7*103a8feaSLen Brown * 8*103a8feaSLen Brown * This program is free software; you can redistribute it and/or modify it 9*103a8feaSLen Brown * under the terms and conditions of the GNU General Public License, 10*103a8feaSLen Brown * version 2, as published by the Free Software Foundation. 11*103a8feaSLen Brown * 12*103a8feaSLen Brown * This program is distributed in the hope it will be useful, but WITHOUT 13*103a8feaSLen Brown * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14*103a8feaSLen Brown * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15*103a8feaSLen Brown * more details. 16*103a8feaSLen Brown * 17*103a8feaSLen Brown * You should have received a copy of the GNU General Public License along with 18*103a8feaSLen Brown * this program; if not, write to the Free Software Foundation, Inc., 19*103a8feaSLen Brown * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 20*103a8feaSLen Brown */ 21*103a8feaSLen Brown 22*103a8feaSLen Brown #include <stdio.h> 23*103a8feaSLen Brown #include <unistd.h> 24*103a8feaSLen Brown #include <sys/types.h> 25*103a8feaSLen Brown #include <sys/wait.h> 26*103a8feaSLen Brown #include <sys/stat.h> 27*103a8feaSLen Brown #include <sys/resource.h> 28*103a8feaSLen Brown #include <fcntl.h> 29*103a8feaSLen Brown #include <signal.h> 30*103a8feaSLen Brown #include <sys/time.h> 31*103a8feaSLen Brown #include <stdlib.h> 32*103a8feaSLen Brown #include <dirent.h> 33*103a8feaSLen Brown #include <string.h> 34*103a8feaSLen Brown #include <ctype.h> 35*103a8feaSLen Brown 36*103a8feaSLen Brown #define MSR_TSC 0x10 37*103a8feaSLen Brown #define MSR_NEHALEM_PLATFORM_INFO 0xCE 38*103a8feaSLen Brown #define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD 39*103a8feaSLen Brown #define MSR_APERF 0xE8 40*103a8feaSLen Brown #define MSR_MPERF 0xE7 41*103a8feaSLen Brown #define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */ 42*103a8feaSLen Brown #define MSR_PKG_C3_RESIDENCY 0x3F8 43*103a8feaSLen Brown #define MSR_PKG_C6_RESIDENCY 0x3F9 44*103a8feaSLen Brown #define MSR_PKG_C7_RESIDENCY 0x3FA /* SNB only */ 45*103a8feaSLen Brown #define MSR_CORE_C3_RESIDENCY 0x3FC 46*103a8feaSLen Brown #define MSR_CORE_C6_RESIDENCY 0x3FD 47*103a8feaSLen Brown #define MSR_CORE_C7_RESIDENCY 0x3FE /* SNB only */ 48*103a8feaSLen Brown 49*103a8feaSLen Brown char *proc_stat = "/proc/stat"; 50*103a8feaSLen Brown unsigned int interval_sec = 5; /* set with -i interval_sec */ 51*103a8feaSLen Brown unsigned int verbose; /* set with -v */ 52*103a8feaSLen Brown unsigned int skip_c0; 53*103a8feaSLen Brown unsigned int skip_c1; 54*103a8feaSLen Brown unsigned int do_nhm_cstates; 55*103a8feaSLen Brown unsigned int do_snb_cstates; 56*103a8feaSLen Brown unsigned int has_aperf; 57*103a8feaSLen Brown unsigned int units = 1000000000; /* Ghz etc */ 58*103a8feaSLen Brown unsigned int genuine_intel; 59*103a8feaSLen Brown unsigned int has_invariant_tsc; 60*103a8feaSLen Brown unsigned int do_nehalem_platform_info; 61*103a8feaSLen Brown unsigned int do_nehalem_turbo_ratio_limit; 62*103a8feaSLen Brown unsigned int extra_msr_offset; 63*103a8feaSLen Brown double bclk; 64*103a8feaSLen Brown unsigned int show_pkg; 65*103a8feaSLen Brown unsigned int show_core; 66*103a8feaSLen Brown unsigned int show_cpu; 67*103a8feaSLen Brown 68*103a8feaSLen Brown int aperf_mperf_unstable; 69*103a8feaSLen Brown int backwards_count; 70*103a8feaSLen Brown char *progname; 71*103a8feaSLen Brown int need_reinitialize; 72*103a8feaSLen Brown 73*103a8feaSLen Brown int num_cpus; 74*103a8feaSLen Brown 75*103a8feaSLen Brown typedef struct per_cpu_counters { 76*103a8feaSLen Brown unsigned long long tsc; /* per thread */ 77*103a8feaSLen Brown unsigned long long aperf; /* per thread */ 78*103a8feaSLen Brown unsigned long long mperf; /* per thread */ 79*103a8feaSLen Brown unsigned long long c1; /* per thread (calculated) */ 80*103a8feaSLen Brown unsigned long long c3; /* per core */ 81*103a8feaSLen Brown unsigned long long c6; /* per core */ 82*103a8feaSLen Brown unsigned long long c7; /* per core */ 83*103a8feaSLen Brown unsigned long long pc2; /* per package */ 84*103a8feaSLen Brown unsigned long long pc3; /* per package */ 85*103a8feaSLen Brown unsigned long long pc6; /* per package */ 86*103a8feaSLen Brown unsigned long long pc7; /* per package */ 87*103a8feaSLen Brown unsigned long long extra_msr; /* per thread */ 88*103a8feaSLen Brown int pkg; 89*103a8feaSLen Brown int core; 90*103a8feaSLen Brown int cpu; 91*103a8feaSLen Brown struct per_cpu_counters *next; 92*103a8feaSLen Brown } PCC; 93*103a8feaSLen Brown 94*103a8feaSLen Brown PCC *pcc_even; 95*103a8feaSLen Brown PCC *pcc_odd; 96*103a8feaSLen Brown PCC *pcc_delta; 97*103a8feaSLen Brown PCC *pcc_average; 98*103a8feaSLen Brown struct timeval tv_even; 99*103a8feaSLen Brown struct timeval tv_odd; 100*103a8feaSLen Brown struct timeval tv_delta; 101*103a8feaSLen Brown 102*103a8feaSLen Brown unsigned long long get_msr(int cpu, off_t offset) 103*103a8feaSLen Brown { 104*103a8feaSLen Brown ssize_t retval; 105*103a8feaSLen Brown unsigned long long msr; 106*103a8feaSLen Brown char pathname[32]; 107*103a8feaSLen Brown int fd; 108*103a8feaSLen Brown 109*103a8feaSLen Brown sprintf(pathname, "/dev/cpu/%d/msr", cpu); 110*103a8feaSLen Brown fd = open(pathname, O_RDONLY); 111*103a8feaSLen Brown if (fd < 0) { 112*103a8feaSLen Brown perror(pathname); 113*103a8feaSLen Brown need_reinitialize = 1; 114*103a8feaSLen Brown return 0; 115*103a8feaSLen Brown } 116*103a8feaSLen Brown 117*103a8feaSLen Brown retval = pread(fd, &msr, sizeof msr, offset); 118*103a8feaSLen Brown if (retval != sizeof msr) { 119*103a8feaSLen Brown fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n", 120*103a8feaSLen Brown cpu, offset, retval); 121*103a8feaSLen Brown exit(-2); 122*103a8feaSLen Brown } 123*103a8feaSLen Brown 124*103a8feaSLen Brown close(fd); 125*103a8feaSLen Brown return msr; 126*103a8feaSLen Brown } 127*103a8feaSLen Brown 128*103a8feaSLen Brown void print_header() 129*103a8feaSLen Brown { 130*103a8feaSLen Brown if (show_pkg) 131*103a8feaSLen Brown fprintf(stderr, "pkg "); 132*103a8feaSLen Brown if (show_core) 133*103a8feaSLen Brown fprintf(stderr, "core"); 134*103a8feaSLen Brown if (show_cpu) 135*103a8feaSLen Brown fprintf(stderr, " CPU"); 136*103a8feaSLen Brown if (do_nhm_cstates) 137*103a8feaSLen Brown fprintf(stderr, " %%c0 "); 138*103a8feaSLen Brown if (has_aperf) 139*103a8feaSLen Brown fprintf(stderr, " GHz"); 140*103a8feaSLen Brown fprintf(stderr, " TSC"); 141*103a8feaSLen Brown if (do_nhm_cstates) 142*103a8feaSLen Brown fprintf(stderr, " %%c1 "); 143*103a8feaSLen Brown if (do_nhm_cstates) 144*103a8feaSLen Brown fprintf(stderr, " %%c3 "); 145*103a8feaSLen Brown if (do_nhm_cstates) 146*103a8feaSLen Brown fprintf(stderr, " %%c6 "); 147*103a8feaSLen Brown if (do_snb_cstates) 148*103a8feaSLen Brown fprintf(stderr, " %%c7 "); 149*103a8feaSLen Brown if (do_snb_cstates) 150*103a8feaSLen Brown fprintf(stderr, " %%pc2 "); 151*103a8feaSLen Brown if (do_nhm_cstates) 152*103a8feaSLen Brown fprintf(stderr, " %%pc3 "); 153*103a8feaSLen Brown if (do_nhm_cstates) 154*103a8feaSLen Brown fprintf(stderr, " %%pc6 "); 155*103a8feaSLen Brown if (do_snb_cstates) 156*103a8feaSLen Brown fprintf(stderr, " %%pc7 "); 157*103a8feaSLen Brown if (extra_msr_offset) 158*103a8feaSLen Brown fprintf(stderr, " MSR 0x%x ", extra_msr_offset); 159*103a8feaSLen Brown 160*103a8feaSLen Brown putc('\n', stderr); 161*103a8feaSLen Brown } 162*103a8feaSLen Brown 163*103a8feaSLen Brown void dump_pcc(PCC *pcc) 164*103a8feaSLen Brown { 165*103a8feaSLen Brown fprintf(stderr, "package: %d ", pcc->pkg); 166*103a8feaSLen Brown fprintf(stderr, "core:: %d ", pcc->core); 167*103a8feaSLen Brown fprintf(stderr, "CPU: %d ", pcc->cpu); 168*103a8feaSLen Brown fprintf(stderr, "TSC: %016llX\n", pcc->tsc); 169*103a8feaSLen Brown fprintf(stderr, "c3: %016llX\n", pcc->c3); 170*103a8feaSLen Brown fprintf(stderr, "c6: %016llX\n", pcc->c6); 171*103a8feaSLen Brown fprintf(stderr, "c7: %016llX\n", pcc->c7); 172*103a8feaSLen Brown fprintf(stderr, "aperf: %016llX\n", pcc->aperf); 173*103a8feaSLen Brown fprintf(stderr, "pc2: %016llX\n", pcc->pc2); 174*103a8feaSLen Brown fprintf(stderr, "pc3: %016llX\n", pcc->pc3); 175*103a8feaSLen Brown fprintf(stderr, "pc6: %016llX\n", pcc->pc6); 176*103a8feaSLen Brown fprintf(stderr, "pc7: %016llX\n", pcc->pc7); 177*103a8feaSLen Brown fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, pcc->extra_msr); 178*103a8feaSLen Brown } 179*103a8feaSLen Brown 180*103a8feaSLen Brown void dump_list(PCC *pcc) 181*103a8feaSLen Brown { 182*103a8feaSLen Brown printf("dump_list 0x%p\n", pcc); 183*103a8feaSLen Brown 184*103a8feaSLen Brown for (; pcc; pcc = pcc->next) 185*103a8feaSLen Brown dump_pcc(pcc); 186*103a8feaSLen Brown } 187*103a8feaSLen Brown 188*103a8feaSLen Brown void print_pcc(PCC *p) 189*103a8feaSLen Brown { 190*103a8feaSLen Brown double interval_float; 191*103a8feaSLen Brown 192*103a8feaSLen Brown interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0; 193*103a8feaSLen Brown 194*103a8feaSLen Brown /* topology columns, print blanks on 1st (average) line */ 195*103a8feaSLen Brown if (p == pcc_average) { 196*103a8feaSLen Brown if (show_pkg) 197*103a8feaSLen Brown fprintf(stderr, " "); 198*103a8feaSLen Brown if (show_core) 199*103a8feaSLen Brown fprintf(stderr, " "); 200*103a8feaSLen Brown if (show_cpu) 201*103a8feaSLen Brown fprintf(stderr, " "); 202*103a8feaSLen Brown } else { 203*103a8feaSLen Brown if (show_pkg) 204*103a8feaSLen Brown fprintf(stderr, "%4d", p->pkg); 205*103a8feaSLen Brown if (show_core) 206*103a8feaSLen Brown fprintf(stderr, "%4d", p->core); 207*103a8feaSLen Brown if (show_cpu) 208*103a8feaSLen Brown fprintf(stderr, "%4d", p->cpu); 209*103a8feaSLen Brown } 210*103a8feaSLen Brown 211*103a8feaSLen Brown /* %c0 */ 212*103a8feaSLen Brown if (do_nhm_cstates) { 213*103a8feaSLen Brown if (!skip_c0) 214*103a8feaSLen Brown fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc); 215*103a8feaSLen Brown else 216*103a8feaSLen Brown fprintf(stderr, " ****"); 217*103a8feaSLen Brown } 218*103a8feaSLen Brown 219*103a8feaSLen Brown /* GHz */ 220*103a8feaSLen Brown if (has_aperf) { 221*103a8feaSLen Brown if (!aperf_mperf_unstable) { 222*103a8feaSLen Brown fprintf(stderr, "%5.2f", 223*103a8feaSLen Brown 1.0 * p->tsc / units * p->aperf / 224*103a8feaSLen Brown p->mperf / interval_float); 225*103a8feaSLen Brown } else { 226*103a8feaSLen Brown if (p->aperf > p->tsc || p->mperf > p->tsc) { 227*103a8feaSLen Brown fprintf(stderr, " ****"); 228*103a8feaSLen Brown } else { 229*103a8feaSLen Brown fprintf(stderr, "%4.1f*", 230*103a8feaSLen Brown 1.0 * p->tsc / 231*103a8feaSLen Brown units * p->aperf / 232*103a8feaSLen Brown p->mperf / interval_float); 233*103a8feaSLen Brown } 234*103a8feaSLen Brown } 235*103a8feaSLen Brown } 236*103a8feaSLen Brown 237*103a8feaSLen Brown /* TSC */ 238*103a8feaSLen Brown fprintf(stderr, "%5.2f", 1.0 * p->tsc/units/interval_float); 239*103a8feaSLen Brown 240*103a8feaSLen Brown if (do_nhm_cstates) { 241*103a8feaSLen Brown if (!skip_c1) 242*103a8feaSLen Brown fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc); 243*103a8feaSLen Brown else 244*103a8feaSLen Brown fprintf(stderr, " ****"); 245*103a8feaSLen Brown } 246*103a8feaSLen Brown if (do_nhm_cstates) 247*103a8feaSLen Brown fprintf(stderr, "%7.2f", 100.0 * p->c3/p->tsc); 248*103a8feaSLen Brown if (do_nhm_cstates) 249*103a8feaSLen Brown fprintf(stderr, "%7.2f", 100.0 * p->c6/p->tsc); 250*103a8feaSLen Brown if (do_snb_cstates) 251*103a8feaSLen Brown fprintf(stderr, "%7.2f", 100.0 * p->c7/p->tsc); 252*103a8feaSLen Brown if (do_snb_cstates) 253*103a8feaSLen Brown fprintf(stderr, "%7.2f", 100.0 * p->pc2/p->tsc); 254*103a8feaSLen Brown if (do_nhm_cstates) 255*103a8feaSLen Brown fprintf(stderr, "%7.2f", 100.0 * p->pc3/p->tsc); 256*103a8feaSLen Brown if (do_nhm_cstates) 257*103a8feaSLen Brown fprintf(stderr, "%7.2f", 100.0 * p->pc6/p->tsc); 258*103a8feaSLen Brown if (do_snb_cstates) 259*103a8feaSLen Brown fprintf(stderr, "%7.2f", 100.0 * p->pc7/p->tsc); 260*103a8feaSLen Brown if (extra_msr_offset) 261*103a8feaSLen Brown fprintf(stderr, " 0x%016llx", p->extra_msr); 262*103a8feaSLen Brown putc('\n', stderr); 263*103a8feaSLen Brown } 264*103a8feaSLen Brown 265*103a8feaSLen Brown void print_counters(PCC *cnt) 266*103a8feaSLen Brown { 267*103a8feaSLen Brown PCC *pcc; 268*103a8feaSLen Brown 269*103a8feaSLen Brown print_header(); 270*103a8feaSLen Brown 271*103a8feaSLen Brown if (num_cpus > 1) 272*103a8feaSLen Brown print_pcc(pcc_average); 273*103a8feaSLen Brown 274*103a8feaSLen Brown for (pcc = cnt; pcc != NULL; pcc = pcc->next) 275*103a8feaSLen Brown print_pcc(pcc); 276*103a8feaSLen Brown 277*103a8feaSLen Brown } 278*103a8feaSLen Brown 279*103a8feaSLen Brown #define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after)) 280*103a8feaSLen Brown 281*103a8feaSLen Brown 282*103a8feaSLen Brown int compute_delta(PCC *after, PCC *before, PCC *delta) 283*103a8feaSLen Brown { 284*103a8feaSLen Brown int errors = 0; 285*103a8feaSLen Brown int perf_err = 0; 286*103a8feaSLen Brown 287*103a8feaSLen Brown skip_c0 = skip_c1 = 0; 288*103a8feaSLen Brown 289*103a8feaSLen Brown for ( ; after && before && delta; 290*103a8feaSLen Brown after = after->next, before = before->next, delta = delta->next) { 291*103a8feaSLen Brown if (before->cpu != after->cpu) { 292*103a8feaSLen Brown printf("cpu configuration changed: %d != %d\n", 293*103a8feaSLen Brown before->cpu, after->cpu); 294*103a8feaSLen Brown return -1; 295*103a8feaSLen Brown } 296*103a8feaSLen Brown 297*103a8feaSLen Brown if (SUBTRACT_COUNTER(after->tsc, before->tsc, delta->tsc)) { 298*103a8feaSLen Brown fprintf(stderr, "cpu%d TSC went backwards %llX to %llX\n", 299*103a8feaSLen Brown before->cpu, before->tsc, after->tsc); 300*103a8feaSLen Brown errors++; 301*103a8feaSLen Brown } 302*103a8feaSLen Brown /* check for TSC < 1 Mcycles over interval */ 303*103a8feaSLen Brown if (delta->tsc < (1000 * 1000)) { 304*103a8feaSLen Brown fprintf(stderr, "Insanely slow TSC rate," 305*103a8feaSLen Brown " TSC stops in idle?\n"); 306*103a8feaSLen Brown fprintf(stderr, "You can disable all c-states" 307*103a8feaSLen Brown " by booting with \"idle=poll\"\n"); 308*103a8feaSLen Brown fprintf(stderr, "or just the deep ones with" 309*103a8feaSLen Brown " \"processor.max_cstate=1\"\n"); 310*103a8feaSLen Brown exit(-3); 311*103a8feaSLen Brown } 312*103a8feaSLen Brown if (SUBTRACT_COUNTER(after->c3, before->c3, delta->c3)) { 313*103a8feaSLen Brown fprintf(stderr, "cpu%d c3 counter went backwards %llX to %llX\n", 314*103a8feaSLen Brown before->cpu, before->c3, after->c3); 315*103a8feaSLen Brown errors++; 316*103a8feaSLen Brown } 317*103a8feaSLen Brown if (SUBTRACT_COUNTER(after->c6, before->c6, delta->c6)) { 318*103a8feaSLen Brown fprintf(stderr, "cpu%d c6 counter went backwards %llX to %llX\n", 319*103a8feaSLen Brown before->cpu, before->c6, after->c6); 320*103a8feaSLen Brown errors++; 321*103a8feaSLen Brown } 322*103a8feaSLen Brown if (SUBTRACT_COUNTER(after->c7, before->c7, delta->c7)) { 323*103a8feaSLen Brown fprintf(stderr, "cpu%d c7 counter went backwards %llX to %llX\n", 324*103a8feaSLen Brown before->cpu, before->c7, after->c7); 325*103a8feaSLen Brown errors++; 326*103a8feaSLen Brown } 327*103a8feaSLen Brown if (SUBTRACT_COUNTER(after->pc2, before->pc2, delta->pc2)) { 328*103a8feaSLen Brown fprintf(stderr, "cpu%d pc2 counter went backwards %llX to %llX\n", 329*103a8feaSLen Brown before->cpu, before->pc2, after->pc2); 330*103a8feaSLen Brown errors++; 331*103a8feaSLen Brown } 332*103a8feaSLen Brown if (SUBTRACT_COUNTER(after->pc3, before->pc3, delta->pc3)) { 333*103a8feaSLen Brown fprintf(stderr, "cpu%d pc3 counter went backwards %llX to %llX\n", 334*103a8feaSLen Brown before->cpu, before->pc3, after->pc3); 335*103a8feaSLen Brown errors++; 336*103a8feaSLen Brown } 337*103a8feaSLen Brown if (SUBTRACT_COUNTER(after->pc6, before->pc6, delta->pc6)) { 338*103a8feaSLen Brown fprintf(stderr, "cpu%d pc6 counter went backwards %llX to %llX\n", 339*103a8feaSLen Brown before->cpu, before->pc6, after->pc6); 340*103a8feaSLen Brown errors++; 341*103a8feaSLen Brown } 342*103a8feaSLen Brown if (SUBTRACT_COUNTER(after->pc7, before->pc7, delta->pc7)) { 343*103a8feaSLen Brown fprintf(stderr, "cpu%d pc7 counter went backwards %llX to %llX\n", 344*103a8feaSLen Brown before->cpu, before->pc7, after->pc7); 345*103a8feaSLen Brown errors++; 346*103a8feaSLen Brown } 347*103a8feaSLen Brown 348*103a8feaSLen Brown perf_err = SUBTRACT_COUNTER(after->aperf, before->aperf, delta->aperf); 349*103a8feaSLen Brown if (perf_err) { 350*103a8feaSLen Brown fprintf(stderr, "cpu%d aperf counter went backwards %llX to %llX\n", 351*103a8feaSLen Brown before->cpu, before->aperf, after->aperf); 352*103a8feaSLen Brown } 353*103a8feaSLen Brown perf_err |= SUBTRACT_COUNTER(after->mperf, before->mperf, delta->mperf); 354*103a8feaSLen Brown if (perf_err) { 355*103a8feaSLen Brown fprintf(stderr, "cpu%d mperf counter went backwards %llX to %llX\n", 356*103a8feaSLen Brown before->cpu, before->mperf, after->mperf); 357*103a8feaSLen Brown } 358*103a8feaSLen Brown if (perf_err) { 359*103a8feaSLen Brown if (!aperf_mperf_unstable) { 360*103a8feaSLen Brown fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname); 361*103a8feaSLen Brown fprintf(stderr, "* Frequency results do not cover entire interval *\n"); 362*103a8feaSLen Brown fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n"); 363*103a8feaSLen Brown 364*103a8feaSLen Brown aperf_mperf_unstable = 1; 365*103a8feaSLen Brown } 366*103a8feaSLen Brown /* 367*103a8feaSLen Brown * mperf delta is likely a huge "positive" number 368*103a8feaSLen Brown * can not use it for calculating c0 time 369*103a8feaSLen Brown */ 370*103a8feaSLen Brown skip_c0 = 1; 371*103a8feaSLen Brown skip_c1 = 1; 372*103a8feaSLen Brown } 373*103a8feaSLen Brown 374*103a8feaSLen Brown /* 375*103a8feaSLen Brown * As mperf and tsc collection are not atomic, 376*103a8feaSLen Brown * it is possible for mperf's non-halted cycles 377*103a8feaSLen Brown * to exceed TSC's all cycles: show c1 = 0% in that case. 378*103a8feaSLen Brown */ 379*103a8feaSLen Brown if (delta->mperf > delta->tsc) 380*103a8feaSLen Brown delta->c1 = 0; 381*103a8feaSLen Brown else /* normal case, derive c1 */ 382*103a8feaSLen Brown delta->c1 = delta->tsc - delta->mperf 383*103a8feaSLen Brown - delta->c3 - delta->c6 - delta->c7; 384*103a8feaSLen Brown 385*103a8feaSLen Brown if (delta->mperf == 0) 386*103a8feaSLen Brown delta->mperf = 1; /* divide by 0 protection */ 387*103a8feaSLen Brown 388*103a8feaSLen Brown /* 389*103a8feaSLen Brown * for "extra msr", just copy the latest w/o subtracting 390*103a8feaSLen Brown */ 391*103a8feaSLen Brown delta->extra_msr = after->extra_msr; 392*103a8feaSLen Brown if (errors) { 393*103a8feaSLen Brown fprintf(stderr, "ERROR cpu%d before:\n", before->cpu); 394*103a8feaSLen Brown dump_pcc(before); 395*103a8feaSLen Brown fprintf(stderr, "ERROR cpu%d after:\n", before->cpu); 396*103a8feaSLen Brown dump_pcc(after); 397*103a8feaSLen Brown errors = 0; 398*103a8feaSLen Brown } 399*103a8feaSLen Brown } 400*103a8feaSLen Brown return 0; 401*103a8feaSLen Brown } 402*103a8feaSLen Brown 403*103a8feaSLen Brown void compute_average(PCC *delta, PCC *avg) 404*103a8feaSLen Brown { 405*103a8feaSLen Brown PCC *sum; 406*103a8feaSLen Brown 407*103a8feaSLen Brown sum = calloc(1, sizeof(PCC)); 408*103a8feaSLen Brown if (sum == NULL) { 409*103a8feaSLen Brown perror("calloc sum"); 410*103a8feaSLen Brown exit(1); 411*103a8feaSLen Brown } 412*103a8feaSLen Brown 413*103a8feaSLen Brown for (; delta; delta = delta->next) { 414*103a8feaSLen Brown sum->tsc += delta->tsc; 415*103a8feaSLen Brown sum->c1 += delta->c1; 416*103a8feaSLen Brown sum->c3 += delta->c3; 417*103a8feaSLen Brown sum->c6 += delta->c6; 418*103a8feaSLen Brown sum->c7 += delta->c7; 419*103a8feaSLen Brown sum->aperf += delta->aperf; 420*103a8feaSLen Brown sum->mperf += delta->mperf; 421*103a8feaSLen Brown sum->pc2 += delta->pc2; 422*103a8feaSLen Brown sum->pc3 += delta->pc3; 423*103a8feaSLen Brown sum->pc6 += delta->pc6; 424*103a8feaSLen Brown sum->pc7 += delta->pc7; 425*103a8feaSLen Brown } 426*103a8feaSLen Brown avg->tsc = sum->tsc/num_cpus; 427*103a8feaSLen Brown avg->c1 = sum->c1/num_cpus; 428*103a8feaSLen Brown avg->c3 = sum->c3/num_cpus; 429*103a8feaSLen Brown avg->c6 = sum->c6/num_cpus; 430*103a8feaSLen Brown avg->c7 = sum->c7/num_cpus; 431*103a8feaSLen Brown avg->aperf = sum->aperf/num_cpus; 432*103a8feaSLen Brown avg->mperf = sum->mperf/num_cpus; 433*103a8feaSLen Brown avg->pc2 = sum->pc2/num_cpus; 434*103a8feaSLen Brown avg->pc3 = sum->pc3/num_cpus; 435*103a8feaSLen Brown avg->pc6 = sum->pc6/num_cpus; 436*103a8feaSLen Brown avg->pc7 = sum->pc7/num_cpus; 437*103a8feaSLen Brown 438*103a8feaSLen Brown free(sum); 439*103a8feaSLen Brown } 440*103a8feaSLen Brown 441*103a8feaSLen Brown void get_counters(PCC *pcc) 442*103a8feaSLen Brown { 443*103a8feaSLen Brown for ( ; pcc; pcc = pcc->next) { 444*103a8feaSLen Brown pcc->tsc = get_msr(pcc->cpu, MSR_TSC); 445*103a8feaSLen Brown if (do_nhm_cstates) 446*103a8feaSLen Brown pcc->c3 = get_msr(pcc->cpu, MSR_CORE_C3_RESIDENCY); 447*103a8feaSLen Brown if (do_nhm_cstates) 448*103a8feaSLen Brown pcc->c6 = get_msr(pcc->cpu, MSR_CORE_C6_RESIDENCY); 449*103a8feaSLen Brown if (do_snb_cstates) 450*103a8feaSLen Brown pcc->c7 = get_msr(pcc->cpu, MSR_CORE_C7_RESIDENCY); 451*103a8feaSLen Brown if (has_aperf) 452*103a8feaSLen Brown pcc->aperf = get_msr(pcc->cpu, MSR_APERF); 453*103a8feaSLen Brown if (has_aperf) 454*103a8feaSLen Brown pcc->mperf = get_msr(pcc->cpu, MSR_MPERF); 455*103a8feaSLen Brown if (do_snb_cstates) 456*103a8feaSLen Brown pcc->pc2 = get_msr(pcc->cpu, MSR_PKG_C2_RESIDENCY); 457*103a8feaSLen Brown if (do_nhm_cstates) 458*103a8feaSLen Brown pcc->pc3 = get_msr(pcc->cpu, MSR_PKG_C3_RESIDENCY); 459*103a8feaSLen Brown if (do_nhm_cstates) 460*103a8feaSLen Brown pcc->pc6 = get_msr(pcc->cpu, MSR_PKG_C6_RESIDENCY); 461*103a8feaSLen Brown if (do_snb_cstates) 462*103a8feaSLen Brown pcc->pc7 = get_msr(pcc->cpu, MSR_PKG_C7_RESIDENCY); 463*103a8feaSLen Brown if (extra_msr_offset) 464*103a8feaSLen Brown pcc->extra_msr = get_msr(pcc->cpu, extra_msr_offset); 465*103a8feaSLen Brown } 466*103a8feaSLen Brown } 467*103a8feaSLen Brown 468*103a8feaSLen Brown 469*103a8feaSLen Brown void print_nehalem_info() 470*103a8feaSLen Brown { 471*103a8feaSLen Brown unsigned long long msr; 472*103a8feaSLen Brown unsigned int ratio; 473*103a8feaSLen Brown 474*103a8feaSLen Brown if (!do_nehalem_platform_info) 475*103a8feaSLen Brown return; 476*103a8feaSLen Brown 477*103a8feaSLen Brown msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO); 478*103a8feaSLen Brown 479*103a8feaSLen Brown ratio = (msr >> 40) & 0xFF; 480*103a8feaSLen Brown fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", 481*103a8feaSLen Brown ratio, bclk, ratio * bclk); 482*103a8feaSLen Brown 483*103a8feaSLen Brown ratio = (msr >> 8) & 0xFF; 484*103a8feaSLen Brown fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n", 485*103a8feaSLen Brown ratio, bclk, ratio * bclk); 486*103a8feaSLen Brown 487*103a8feaSLen Brown if (verbose > 1) 488*103a8feaSLen Brown fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr); 489*103a8feaSLen Brown 490*103a8feaSLen Brown if (!do_nehalem_turbo_ratio_limit) 491*103a8feaSLen Brown return; 492*103a8feaSLen Brown 493*103a8feaSLen Brown msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT); 494*103a8feaSLen Brown 495*103a8feaSLen Brown ratio = (msr >> 24) & 0xFF; 496*103a8feaSLen Brown if (ratio) 497*103a8feaSLen Brown fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n", 498*103a8feaSLen Brown ratio, bclk, ratio * bclk); 499*103a8feaSLen Brown 500*103a8feaSLen Brown ratio = (msr >> 16) & 0xFF; 501*103a8feaSLen Brown if (ratio) 502*103a8feaSLen Brown fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 3 active cores\n", 503*103a8feaSLen Brown ratio, bclk, ratio * bclk); 504*103a8feaSLen Brown 505*103a8feaSLen Brown ratio = (msr >> 8) & 0xFF; 506*103a8feaSLen Brown if (ratio) 507*103a8feaSLen Brown fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 2 active cores\n", 508*103a8feaSLen Brown ratio, bclk, ratio * bclk); 509*103a8feaSLen Brown 510*103a8feaSLen Brown ratio = (msr >> 0) & 0xFF; 511*103a8feaSLen Brown if (ratio) 512*103a8feaSLen Brown fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n", 513*103a8feaSLen Brown ratio, bclk, ratio * bclk); 514*103a8feaSLen Brown 515*103a8feaSLen Brown } 516*103a8feaSLen Brown 517*103a8feaSLen Brown void free_counter_list(PCC *list) 518*103a8feaSLen Brown { 519*103a8feaSLen Brown PCC *p; 520*103a8feaSLen Brown 521*103a8feaSLen Brown for (p = list; p; ) { 522*103a8feaSLen Brown PCC *free_me; 523*103a8feaSLen Brown 524*103a8feaSLen Brown free_me = p; 525*103a8feaSLen Brown p = p->next; 526*103a8feaSLen Brown free(free_me); 527*103a8feaSLen Brown } 528*103a8feaSLen Brown return; 529*103a8feaSLen Brown } 530*103a8feaSLen Brown 531*103a8feaSLen Brown void free_all_counters(void) 532*103a8feaSLen Brown { 533*103a8feaSLen Brown free_counter_list(pcc_even); 534*103a8feaSLen Brown pcc_even = NULL; 535*103a8feaSLen Brown 536*103a8feaSLen Brown free_counter_list(pcc_odd); 537*103a8feaSLen Brown pcc_odd = NULL; 538*103a8feaSLen Brown 539*103a8feaSLen Brown free_counter_list(pcc_delta); 540*103a8feaSLen Brown pcc_delta = NULL; 541*103a8feaSLen Brown 542*103a8feaSLen Brown free_counter_list(pcc_average); 543*103a8feaSLen Brown pcc_average = NULL; 544*103a8feaSLen Brown } 545*103a8feaSLen Brown 546*103a8feaSLen Brown void insert_cpu_counters(PCC **list, PCC *new) 547*103a8feaSLen Brown { 548*103a8feaSLen Brown PCC *prev; 549*103a8feaSLen Brown 550*103a8feaSLen Brown /* 551*103a8feaSLen Brown * list was empty 552*103a8feaSLen Brown */ 553*103a8feaSLen Brown if (*list == NULL) { 554*103a8feaSLen Brown new->next = *list; 555*103a8feaSLen Brown *list = new; 556*103a8feaSLen Brown return; 557*103a8feaSLen Brown } 558*103a8feaSLen Brown 559*103a8feaSLen Brown show_cpu = 1; /* there is more than one CPU */ 560*103a8feaSLen Brown 561*103a8feaSLen Brown /* 562*103a8feaSLen Brown * insert on front of list. 563*103a8feaSLen Brown * It is sorted by ascending package#, core#, cpu# 564*103a8feaSLen Brown */ 565*103a8feaSLen Brown if (((*list)->pkg > new->pkg) || 566*103a8feaSLen Brown (((*list)->pkg == new->pkg) && ((*list)->core > new->core)) || 567*103a8feaSLen Brown (((*list)->pkg == new->pkg) && ((*list)->core == new->core) && ((*list)->cpu > new->cpu))) { 568*103a8feaSLen Brown new->next = *list; 569*103a8feaSLen Brown *list = new; 570*103a8feaSLen Brown return; 571*103a8feaSLen Brown } 572*103a8feaSLen Brown 573*103a8feaSLen Brown prev = *list; 574*103a8feaSLen Brown 575*103a8feaSLen Brown while (prev->next && (prev->next->pkg < new->pkg)) { 576*103a8feaSLen Brown prev = prev->next; 577*103a8feaSLen Brown show_pkg = 1; /* there is more than 1 package */ 578*103a8feaSLen Brown } 579*103a8feaSLen Brown 580*103a8feaSLen Brown while (prev->next && (prev->next->pkg == new->pkg) 581*103a8feaSLen Brown && (prev->next->core < new->core)) { 582*103a8feaSLen Brown prev = prev->next; 583*103a8feaSLen Brown show_core = 1; /* there is more than 1 core */ 584*103a8feaSLen Brown } 585*103a8feaSLen Brown 586*103a8feaSLen Brown while (prev->next && (prev->next->pkg == new->pkg) 587*103a8feaSLen Brown && (prev->next->core == new->core) 588*103a8feaSLen Brown && (prev->next->cpu < new->cpu)) { 589*103a8feaSLen Brown prev = prev->next; 590*103a8feaSLen Brown } 591*103a8feaSLen Brown 592*103a8feaSLen Brown /* 593*103a8feaSLen Brown * insert after "prev" 594*103a8feaSLen Brown */ 595*103a8feaSLen Brown new->next = prev->next; 596*103a8feaSLen Brown prev->next = new; 597*103a8feaSLen Brown 598*103a8feaSLen Brown return; 599*103a8feaSLen Brown } 600*103a8feaSLen Brown 601*103a8feaSLen Brown void alloc_new_cpu_counters(int pkg, int core, int cpu) 602*103a8feaSLen Brown { 603*103a8feaSLen Brown PCC *new; 604*103a8feaSLen Brown 605*103a8feaSLen Brown if (verbose > 1) 606*103a8feaSLen Brown printf("pkg%d core%d, cpu%d\n", pkg, core, cpu); 607*103a8feaSLen Brown 608*103a8feaSLen Brown new = (PCC *)calloc(1, sizeof(PCC)); 609*103a8feaSLen Brown if (new == NULL) { 610*103a8feaSLen Brown perror("calloc"); 611*103a8feaSLen Brown exit(1); 612*103a8feaSLen Brown } 613*103a8feaSLen Brown new->pkg = pkg; 614*103a8feaSLen Brown new->core = core; 615*103a8feaSLen Brown new->cpu = cpu; 616*103a8feaSLen Brown insert_cpu_counters(&pcc_odd, new); 617*103a8feaSLen Brown 618*103a8feaSLen Brown new = (PCC *)calloc(1, sizeof(PCC)); 619*103a8feaSLen Brown if (new == NULL) { 620*103a8feaSLen Brown perror("calloc"); 621*103a8feaSLen Brown exit(1); 622*103a8feaSLen Brown } 623*103a8feaSLen Brown new->pkg = pkg; 624*103a8feaSLen Brown new->core = core; 625*103a8feaSLen Brown new->cpu = cpu; 626*103a8feaSLen Brown insert_cpu_counters(&pcc_even, new); 627*103a8feaSLen Brown 628*103a8feaSLen Brown new = (PCC *)calloc(1, sizeof(PCC)); 629*103a8feaSLen Brown if (new == NULL) { 630*103a8feaSLen Brown perror("calloc"); 631*103a8feaSLen Brown exit(1); 632*103a8feaSLen Brown } 633*103a8feaSLen Brown new->pkg = pkg; 634*103a8feaSLen Brown new->core = core; 635*103a8feaSLen Brown new->cpu = cpu; 636*103a8feaSLen Brown insert_cpu_counters(&pcc_delta, new); 637*103a8feaSLen Brown 638*103a8feaSLen Brown new = (PCC *)calloc(1, sizeof(PCC)); 639*103a8feaSLen Brown if (new == NULL) { 640*103a8feaSLen Brown perror("calloc"); 641*103a8feaSLen Brown exit(1); 642*103a8feaSLen Brown } 643*103a8feaSLen Brown new->pkg = pkg; 644*103a8feaSLen Brown new->core = core; 645*103a8feaSLen Brown new->cpu = cpu; 646*103a8feaSLen Brown pcc_average = new; 647*103a8feaSLen Brown } 648*103a8feaSLen Brown 649*103a8feaSLen Brown int get_physical_package_id(int cpu) 650*103a8feaSLen Brown { 651*103a8feaSLen Brown char path[64]; 652*103a8feaSLen Brown FILE *filep; 653*103a8feaSLen Brown int pkg; 654*103a8feaSLen Brown 655*103a8feaSLen Brown sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); 656*103a8feaSLen Brown filep = fopen(path, "r"); 657*103a8feaSLen Brown if (filep == NULL) { 658*103a8feaSLen Brown perror(path); 659*103a8feaSLen Brown exit(1); 660*103a8feaSLen Brown } 661*103a8feaSLen Brown fscanf(filep, "%d", &pkg); 662*103a8feaSLen Brown fclose(filep); 663*103a8feaSLen Brown return pkg; 664*103a8feaSLen Brown } 665*103a8feaSLen Brown 666*103a8feaSLen Brown int get_core_id(int cpu) 667*103a8feaSLen Brown { 668*103a8feaSLen Brown char path[64]; 669*103a8feaSLen Brown FILE *filep; 670*103a8feaSLen Brown int core; 671*103a8feaSLen Brown 672*103a8feaSLen Brown sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); 673*103a8feaSLen Brown filep = fopen(path, "r"); 674*103a8feaSLen Brown if (filep == NULL) { 675*103a8feaSLen Brown perror(path); 676*103a8feaSLen Brown exit(1); 677*103a8feaSLen Brown } 678*103a8feaSLen Brown fscanf(filep, "%d", &core); 679*103a8feaSLen Brown fclose(filep); 680*103a8feaSLen Brown return core; 681*103a8feaSLen Brown } 682*103a8feaSLen Brown 683*103a8feaSLen Brown /* 684*103a8feaSLen Brown * run func(index, cpu) on every cpu in /proc/stat 685*103a8feaSLen Brown */ 686*103a8feaSLen Brown 687*103a8feaSLen Brown int for_all_cpus(void (func)(int, int, int)) 688*103a8feaSLen Brown { 689*103a8feaSLen Brown FILE *fp; 690*103a8feaSLen Brown int cpu_count; 691*103a8feaSLen Brown int retval; 692*103a8feaSLen Brown 693*103a8feaSLen Brown fp = fopen(proc_stat, "r"); 694*103a8feaSLen Brown if (fp == NULL) { 695*103a8feaSLen Brown perror(proc_stat); 696*103a8feaSLen Brown exit(1); 697*103a8feaSLen Brown } 698*103a8feaSLen Brown 699*103a8feaSLen Brown retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); 700*103a8feaSLen Brown if (retval != 0) { 701*103a8feaSLen Brown perror("/proc/stat format"); 702*103a8feaSLen Brown exit(1); 703*103a8feaSLen Brown } 704*103a8feaSLen Brown 705*103a8feaSLen Brown for (cpu_count = 0; ; cpu_count++) { 706*103a8feaSLen Brown int cpu; 707*103a8feaSLen Brown 708*103a8feaSLen Brown retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu); 709*103a8feaSLen Brown if (retval != 1) 710*103a8feaSLen Brown break; 711*103a8feaSLen Brown 712*103a8feaSLen Brown func(get_physical_package_id(cpu), get_core_id(cpu), cpu); 713*103a8feaSLen Brown } 714*103a8feaSLen Brown fclose(fp); 715*103a8feaSLen Brown return cpu_count; 716*103a8feaSLen Brown } 717*103a8feaSLen Brown 718*103a8feaSLen Brown void re_initialize(void) 719*103a8feaSLen Brown { 720*103a8feaSLen Brown printf("turbostat: topology changed, re-initializing.\n"); 721*103a8feaSLen Brown free_all_counters(); 722*103a8feaSLen Brown num_cpus = for_all_cpus(alloc_new_cpu_counters); 723*103a8feaSLen Brown need_reinitialize = 0; 724*103a8feaSLen Brown printf("num_cpus is now %d\n", num_cpus); 725*103a8feaSLen Brown } 726*103a8feaSLen Brown 727*103a8feaSLen Brown void dummy(int pkg, int core, int cpu) { return; } 728*103a8feaSLen Brown /* 729*103a8feaSLen Brown * check to see if a cpu came on-line 730*103a8feaSLen Brown */ 731*103a8feaSLen Brown void verify_num_cpus() 732*103a8feaSLen Brown { 733*103a8feaSLen Brown int new_num_cpus; 734*103a8feaSLen Brown 735*103a8feaSLen Brown new_num_cpus = for_all_cpus(dummy); 736*103a8feaSLen Brown 737*103a8feaSLen Brown if (new_num_cpus != num_cpus) { 738*103a8feaSLen Brown if (verbose) 739*103a8feaSLen Brown printf("num_cpus was %d, is now %d\n", 740*103a8feaSLen Brown num_cpus, new_num_cpus); 741*103a8feaSLen Brown need_reinitialize = 1; 742*103a8feaSLen Brown } 743*103a8feaSLen Brown 744*103a8feaSLen Brown return; 745*103a8feaSLen Brown } 746*103a8feaSLen Brown 747*103a8feaSLen Brown void turbostat_loop() 748*103a8feaSLen Brown { 749*103a8feaSLen Brown restart: 750*103a8feaSLen Brown get_counters(pcc_even); 751*103a8feaSLen Brown gettimeofday(&tv_even, (struct timezone *)NULL); 752*103a8feaSLen Brown 753*103a8feaSLen Brown while (1) { 754*103a8feaSLen Brown verify_num_cpus(); 755*103a8feaSLen Brown if (need_reinitialize) { 756*103a8feaSLen Brown re_initialize(); 757*103a8feaSLen Brown goto restart; 758*103a8feaSLen Brown } 759*103a8feaSLen Brown sleep(interval_sec); 760*103a8feaSLen Brown get_counters(pcc_odd); 761*103a8feaSLen Brown gettimeofday(&tv_odd, (struct timezone *)NULL); 762*103a8feaSLen Brown 763*103a8feaSLen Brown compute_delta(pcc_odd, pcc_even, pcc_delta); 764*103a8feaSLen Brown timersub(&tv_odd, &tv_even, &tv_delta); 765*103a8feaSLen Brown compute_average(pcc_delta, pcc_average); 766*103a8feaSLen Brown print_counters(pcc_delta); 767*103a8feaSLen Brown if (need_reinitialize) { 768*103a8feaSLen Brown re_initialize(); 769*103a8feaSLen Brown goto restart; 770*103a8feaSLen Brown } 771*103a8feaSLen Brown sleep(interval_sec); 772*103a8feaSLen Brown get_counters(pcc_even); 773*103a8feaSLen Brown gettimeofday(&tv_even, (struct timezone *)NULL); 774*103a8feaSLen Brown compute_delta(pcc_even, pcc_odd, pcc_delta); 775*103a8feaSLen Brown timersub(&tv_even, &tv_odd, &tv_delta); 776*103a8feaSLen Brown compute_average(pcc_delta, pcc_average); 777*103a8feaSLen Brown print_counters(pcc_delta); 778*103a8feaSLen Brown } 779*103a8feaSLen Brown } 780*103a8feaSLen Brown 781*103a8feaSLen Brown void check_dev_msr() 782*103a8feaSLen Brown { 783*103a8feaSLen Brown struct stat sb; 784*103a8feaSLen Brown 785*103a8feaSLen Brown if (stat("/dev/cpu/0/msr", &sb)) { 786*103a8feaSLen Brown fprintf(stderr, "no /dev/cpu/0/msr\n"); 787*103a8feaSLen Brown fprintf(stderr, "Try \"# modprobe msr\"\n"); 788*103a8feaSLen Brown exit(-5); 789*103a8feaSLen Brown } 790*103a8feaSLen Brown } 791*103a8feaSLen Brown 792*103a8feaSLen Brown void check_super_user() 793*103a8feaSLen Brown { 794*103a8feaSLen Brown if (getuid() != 0) { 795*103a8feaSLen Brown fprintf(stderr, "must be root\n"); 796*103a8feaSLen Brown exit(-6); 797*103a8feaSLen Brown } 798*103a8feaSLen Brown } 799*103a8feaSLen Brown 800*103a8feaSLen Brown int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) 801*103a8feaSLen Brown { 802*103a8feaSLen Brown if (!genuine_intel) 803*103a8feaSLen Brown return 0; 804*103a8feaSLen Brown 805*103a8feaSLen Brown if (family != 6) 806*103a8feaSLen Brown return 0; 807*103a8feaSLen Brown 808*103a8feaSLen Brown switch (model) { 809*103a8feaSLen Brown case 0x1A: /* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */ 810*103a8feaSLen Brown case 0x1E: /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */ 811*103a8feaSLen Brown case 0x1F: /* Core i7 and i5 Processor - Nehalem */ 812*103a8feaSLen Brown case 0x25: /* Westmere Client - Clarkdale, Arrandale */ 813*103a8feaSLen Brown case 0x2C: /* Westmere EP - Gulftown */ 814*103a8feaSLen Brown case 0x2A: /* SNB */ 815*103a8feaSLen Brown case 0x2D: /* SNB Xeon */ 816*103a8feaSLen Brown return 1; 817*103a8feaSLen Brown case 0x2E: /* Nehalem-EX Xeon - Beckton */ 818*103a8feaSLen Brown case 0x2F: /* Westmere-EX Xeon - Eagleton */ 819*103a8feaSLen Brown default: 820*103a8feaSLen Brown return 0; 821*103a8feaSLen Brown } 822*103a8feaSLen Brown } 823*103a8feaSLen Brown 824*103a8feaSLen Brown int is_snb(unsigned int family, unsigned int model) 825*103a8feaSLen Brown { 826*103a8feaSLen Brown if (!genuine_intel) 827*103a8feaSLen Brown return 0; 828*103a8feaSLen Brown 829*103a8feaSLen Brown switch (model) { 830*103a8feaSLen Brown case 0x2A: 831*103a8feaSLen Brown case 0x2D: 832*103a8feaSLen Brown return 1; 833*103a8feaSLen Brown } 834*103a8feaSLen Brown return 0; 835*103a8feaSLen Brown } 836*103a8feaSLen Brown 837*103a8feaSLen Brown double discover_bclk(unsigned int family, unsigned int model) 838*103a8feaSLen Brown { 839*103a8feaSLen Brown if (is_snb(family, model)) 840*103a8feaSLen Brown return 100.00; 841*103a8feaSLen Brown else 842*103a8feaSLen Brown return 133.33; 843*103a8feaSLen Brown } 844*103a8feaSLen Brown 845*103a8feaSLen Brown void check_cpuid() 846*103a8feaSLen Brown { 847*103a8feaSLen Brown unsigned int eax, ebx, ecx, edx, max_level; 848*103a8feaSLen Brown unsigned int fms, family, model, stepping; 849*103a8feaSLen Brown 850*103a8feaSLen Brown eax = ebx = ecx = edx = 0; 851*103a8feaSLen Brown 852*103a8feaSLen Brown asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0)); 853*103a8feaSLen Brown 854*103a8feaSLen Brown if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) 855*103a8feaSLen Brown genuine_intel = 1; 856*103a8feaSLen Brown 857*103a8feaSLen Brown if (verbose) 858*103a8feaSLen Brown fprintf(stderr, "%.4s%.4s%.4s ", 859*103a8feaSLen Brown (char *)&ebx, (char *)&edx, (char *)&ecx); 860*103a8feaSLen Brown 861*103a8feaSLen Brown asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); 862*103a8feaSLen Brown family = (fms >> 8) & 0xf; 863*103a8feaSLen Brown model = (fms >> 4) & 0xf; 864*103a8feaSLen Brown stepping = fms & 0xf; 865*103a8feaSLen Brown if (family == 6 || family == 0xf) 866*103a8feaSLen Brown model += ((fms >> 16) & 0xf) << 4; 867*103a8feaSLen Brown 868*103a8feaSLen Brown if (verbose) 869*103a8feaSLen Brown fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", 870*103a8feaSLen Brown max_level, family, model, stepping, family, model, stepping); 871*103a8feaSLen Brown 872*103a8feaSLen Brown if (!(edx & (1 << 5))) { 873*103a8feaSLen Brown fprintf(stderr, "CPUID: no MSR\n"); 874*103a8feaSLen Brown exit(1); 875*103a8feaSLen Brown } 876*103a8feaSLen Brown 877*103a8feaSLen Brown /* 878*103a8feaSLen Brown * check max extended function levels of CPUID. 879*103a8feaSLen Brown * This is needed to check for invariant TSC. 880*103a8feaSLen Brown * This check is valid for both Intel and AMD. 881*103a8feaSLen Brown */ 882*103a8feaSLen Brown ebx = ecx = edx = 0; 883*103a8feaSLen Brown asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000)); 884*103a8feaSLen Brown 885*103a8feaSLen Brown if (max_level < 0x80000007) { 886*103a8feaSLen Brown fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level); 887*103a8feaSLen Brown exit(1); 888*103a8feaSLen Brown } 889*103a8feaSLen Brown 890*103a8feaSLen Brown /* 891*103a8feaSLen Brown * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 892*103a8feaSLen Brown * this check is valid for both Intel and AMD 893*103a8feaSLen Brown */ 894*103a8feaSLen Brown asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007)); 895*103a8feaSLen Brown has_invariant_tsc = edx && (1 << 8); 896*103a8feaSLen Brown 897*103a8feaSLen Brown if (!has_invariant_tsc) { 898*103a8feaSLen Brown fprintf(stderr, "No invariant TSC\n"); 899*103a8feaSLen Brown exit(1); 900*103a8feaSLen Brown } 901*103a8feaSLen Brown 902*103a8feaSLen Brown /* 903*103a8feaSLen Brown * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0 904*103a8feaSLen Brown * this check is valid for both Intel and AMD 905*103a8feaSLen Brown */ 906*103a8feaSLen Brown 907*103a8feaSLen Brown asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6)); 908*103a8feaSLen Brown has_aperf = ecx && (1 << 0); 909*103a8feaSLen Brown if (!has_aperf) { 910*103a8feaSLen Brown fprintf(stderr, "No APERF MSR\n"); 911*103a8feaSLen Brown exit(1); 912*103a8feaSLen Brown } 913*103a8feaSLen Brown 914*103a8feaSLen Brown do_nehalem_platform_info = genuine_intel && has_invariant_tsc; 915*103a8feaSLen Brown do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */ 916*103a8feaSLen Brown do_snb_cstates = is_snb(family, model); 917*103a8feaSLen Brown bclk = discover_bclk(family, model); 918*103a8feaSLen Brown 919*103a8feaSLen Brown do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); 920*103a8feaSLen Brown } 921*103a8feaSLen Brown 922*103a8feaSLen Brown 923*103a8feaSLen Brown void usage() 924*103a8feaSLen Brown { 925*103a8feaSLen Brown fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n", 926*103a8feaSLen Brown progname); 927*103a8feaSLen Brown exit(1); 928*103a8feaSLen Brown } 929*103a8feaSLen Brown 930*103a8feaSLen Brown 931*103a8feaSLen Brown /* 932*103a8feaSLen Brown * in /dev/cpu/ return success for names that are numbers 933*103a8feaSLen Brown * ie. filter out ".", "..", "microcode". 934*103a8feaSLen Brown */ 935*103a8feaSLen Brown int dir_filter(const struct dirent *dirp) 936*103a8feaSLen Brown { 937*103a8feaSLen Brown if (isdigit(dirp->d_name[0])) 938*103a8feaSLen Brown return 1; 939*103a8feaSLen Brown else 940*103a8feaSLen Brown return 0; 941*103a8feaSLen Brown } 942*103a8feaSLen Brown 943*103a8feaSLen Brown int open_dev_cpu_msr(int dummy1) 944*103a8feaSLen Brown { 945*103a8feaSLen Brown return 0; 946*103a8feaSLen Brown } 947*103a8feaSLen Brown 948*103a8feaSLen Brown void turbostat_init() 949*103a8feaSLen Brown { 950*103a8feaSLen Brown check_cpuid(); 951*103a8feaSLen Brown 952*103a8feaSLen Brown check_dev_msr(); 953*103a8feaSLen Brown check_super_user(); 954*103a8feaSLen Brown 955*103a8feaSLen Brown num_cpus = for_all_cpus(alloc_new_cpu_counters); 956*103a8feaSLen Brown 957*103a8feaSLen Brown if (verbose) 958*103a8feaSLen Brown print_nehalem_info(); 959*103a8feaSLen Brown } 960*103a8feaSLen Brown 961*103a8feaSLen Brown int fork_it(char **argv) 962*103a8feaSLen Brown { 963*103a8feaSLen Brown int retval; 964*103a8feaSLen Brown pid_t child_pid; 965*103a8feaSLen Brown get_counters(pcc_even); 966*103a8feaSLen Brown gettimeofday(&tv_even, (struct timezone *)NULL); 967*103a8feaSLen Brown 968*103a8feaSLen Brown child_pid = fork(); 969*103a8feaSLen Brown if (!child_pid) { 970*103a8feaSLen Brown /* child */ 971*103a8feaSLen Brown execvp(argv[0], argv); 972*103a8feaSLen Brown } else { 973*103a8feaSLen Brown int status; 974*103a8feaSLen Brown 975*103a8feaSLen Brown /* parent */ 976*103a8feaSLen Brown if (child_pid == -1) { 977*103a8feaSLen Brown perror("fork"); 978*103a8feaSLen Brown exit(1); 979*103a8feaSLen Brown } 980*103a8feaSLen Brown 981*103a8feaSLen Brown signal(SIGINT, SIG_IGN); 982*103a8feaSLen Brown signal(SIGQUIT, SIG_IGN); 983*103a8feaSLen Brown if (waitpid(child_pid, &status, 0) == -1) { 984*103a8feaSLen Brown perror("wait"); 985*103a8feaSLen Brown exit(1); 986*103a8feaSLen Brown } 987*103a8feaSLen Brown } 988*103a8feaSLen Brown get_counters(pcc_odd); 989*103a8feaSLen Brown gettimeofday(&tv_odd, (struct timezone *)NULL); 990*103a8feaSLen Brown retval = compute_delta(pcc_odd, pcc_even, pcc_delta); 991*103a8feaSLen Brown 992*103a8feaSLen Brown timersub(&tv_odd, &tv_even, &tv_delta); 993*103a8feaSLen Brown compute_average(pcc_delta, pcc_average); 994*103a8feaSLen Brown if (!retval) 995*103a8feaSLen Brown print_counters(pcc_delta); 996*103a8feaSLen Brown 997*103a8feaSLen Brown fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);; 998*103a8feaSLen Brown 999*103a8feaSLen Brown return 0; 1000*103a8feaSLen Brown } 1001*103a8feaSLen Brown 1002*103a8feaSLen Brown void cmdline(int argc, char **argv) 1003*103a8feaSLen Brown { 1004*103a8feaSLen Brown int opt; 1005*103a8feaSLen Brown 1006*103a8feaSLen Brown progname = argv[0]; 1007*103a8feaSLen Brown 1008*103a8feaSLen Brown while ((opt = getopt(argc, argv, "+vi:M:")) != -1) { 1009*103a8feaSLen Brown switch (opt) { 1010*103a8feaSLen Brown case 'v': 1011*103a8feaSLen Brown verbose++; 1012*103a8feaSLen Brown break; 1013*103a8feaSLen Brown case 'i': 1014*103a8feaSLen Brown interval_sec = atoi(optarg); 1015*103a8feaSLen Brown break; 1016*103a8feaSLen Brown case 'M': 1017*103a8feaSLen Brown sscanf(optarg, "%x", &extra_msr_offset); 1018*103a8feaSLen Brown if (verbose > 1) 1019*103a8feaSLen Brown fprintf(stderr, "MSR 0x%X\n", extra_msr_offset); 1020*103a8feaSLen Brown break; 1021*103a8feaSLen Brown default: 1022*103a8feaSLen Brown usage(); 1023*103a8feaSLen Brown } 1024*103a8feaSLen Brown } 1025*103a8feaSLen Brown } 1026*103a8feaSLen Brown 1027*103a8feaSLen Brown int main(int argc, char **argv) 1028*103a8feaSLen Brown { 1029*103a8feaSLen Brown cmdline(argc, argv); 1030*103a8feaSLen Brown 1031*103a8feaSLen Brown if (verbose > 1) 1032*103a8feaSLen Brown fprintf(stderr, "turbostat Dec 6, 2010" 1033*103a8feaSLen Brown " - Len Brown <lenb@kernel.org>\n"); 1034*103a8feaSLen Brown if (verbose > 1) 1035*103a8feaSLen Brown fprintf(stderr, "http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/\n"); 1036*103a8feaSLen Brown 1037*103a8feaSLen Brown turbostat_init(); 1038*103a8feaSLen Brown 1039*103a8feaSLen Brown /* 1040*103a8feaSLen Brown * if any params left, it must be a command to fork 1041*103a8feaSLen Brown */ 1042*103a8feaSLen Brown if (argc - optind) 1043*103a8feaSLen Brown return fork_it(argv + optind); 1044*103a8feaSLen Brown else 1045*103a8feaSLen Brown turbostat_loop(); 1046*103a8feaSLen Brown 1047*103a8feaSLen Brown return 0; 1048*103a8feaSLen Brown } 1049