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