linux/tools/power/cpupower/utils/cpufreq-info.c
<<
>>
Prefs
   1/*
   2 *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
   3 *
   4 *  Licensed under the terms of the GNU GPL License version 2.
   5 */
   6
   7
   8#include <unistd.h>
   9#include <stdio.h>
  10#include <errno.h>
  11#include <stdlib.h>
  12#include <string.h>
  13
  14#include <getopt.h>
  15
  16#include "cpufreq.h"
  17#include "helpers/helpers.h"
  18#include "helpers/bitmask.h"
  19
  20#define LINE_LEN 10
  21
  22static unsigned int count_cpus(void)
  23{
  24        FILE *fp;
  25        char value[LINE_LEN];
  26        unsigned int ret = 0;
  27        unsigned int cpunr = 0;
  28
  29        fp = fopen("/proc/stat", "r");
  30        if (!fp) {
  31                printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
  32                return 1;
  33        }
  34
  35        while (!feof(fp)) {
  36                if (!fgets(value, LINE_LEN, fp))
  37                        continue;
  38                value[LINE_LEN - 1] = '\0';
  39                if (strlen(value) < (LINE_LEN - 2))
  40                        continue;
  41                if (strstr(value, "cpu "))
  42                        continue;
  43                if (sscanf(value, "cpu%d ", &cpunr) != 1)
  44                        continue;
  45                if (cpunr > ret)
  46                        ret = cpunr;
  47        }
  48        fclose(fp);
  49
  50        /* cpu count starts from 0, on error return 1 (UP) */
  51        return ret + 1;
  52}
  53
  54
  55static void proc_cpufreq_output(void)
  56{
  57        unsigned int cpu, nr_cpus;
  58        struct cpufreq_policy *policy;
  59        unsigned int min_pctg = 0;
  60        unsigned int max_pctg = 0;
  61        unsigned long min, max;
  62
  63        printf(_("          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"));
  64
  65        nr_cpus = count_cpus();
  66        for (cpu = 0; cpu < nr_cpus; cpu++) {
  67                policy = cpufreq_get_policy(cpu);
  68                if (!policy)
  69                        continue;
  70
  71                if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
  72                        max = 0;
  73                } else {
  74                        min_pctg = (policy->min * 100) / max;
  75                        max_pctg = (policy->max * 100) / max;
  76                }
  77                printf("CPU%3d    %9lu kHz (%3d %%)  -  %9lu kHz (%3d %%)  -  %s\n",
  78                        cpu , policy->min, max ? min_pctg : 0, policy->max,
  79                        max ? max_pctg : 0, policy->governor);
  80
  81                cpufreq_put_policy(policy);
  82        }
  83}
  84
  85static int no_rounding;
  86static void print_speed(unsigned long speed)
  87{
  88        unsigned long tmp;
  89
  90        if (no_rounding) {
  91                if (speed > 1000000)
  92                        printf("%u.%06u GHz", ((unsigned int) speed/1000000),
  93                                ((unsigned int) speed%1000000));
  94                else if (speed > 100000)
  95                        printf("%u MHz", (unsigned int) speed);
  96                else if (speed > 1000)
  97                        printf("%u.%03u MHz", ((unsigned int) speed/1000),
  98                                (unsigned int) (speed%1000));
  99                else
 100                        printf("%lu kHz", speed);
 101        } else {
 102                if (speed > 1000000) {
 103                        tmp = speed%10000;
 104                        if (tmp >= 5000)
 105                                speed += 10000;
 106                        printf("%u.%02u GHz", ((unsigned int) speed/1000000),
 107                                ((unsigned int) (speed%1000000)/10000));
 108                } else if (speed > 100000) {
 109                        tmp = speed%1000;
 110                        if (tmp >= 500)
 111                                speed += 1000;
 112                        printf("%u MHz", ((unsigned int) speed/1000));
 113                } else if (speed > 1000) {
 114                        tmp = speed%100;
 115                        if (tmp >= 50)
 116                                speed += 100;
 117                        printf("%u.%01u MHz", ((unsigned int) speed/1000),
 118                                ((unsigned int) (speed%1000)/100));
 119                }
 120        }
 121
 122        return;
 123}
 124
 125static void print_duration(unsigned long duration)
 126{
 127        unsigned long tmp;
 128
 129        if (no_rounding) {
 130                if (duration > 1000000)
 131                        printf("%u.%06u ms", ((unsigned int) duration/1000000),
 132                                ((unsigned int) duration%1000000));
 133                else if (duration > 100000)
 134                        printf("%u us", ((unsigned int) duration/1000));
 135                else if (duration > 1000)
 136                        printf("%u.%03u us", ((unsigned int) duration/1000),
 137                                ((unsigned int) duration%1000));
 138                else
 139                        printf("%lu ns", duration);
 140        } else {
 141                if (duration > 1000000) {
 142                        tmp = duration%10000;
 143                        if (tmp >= 5000)
 144                                duration += 10000;
 145                        printf("%u.%02u ms", ((unsigned int) duration/1000000),
 146                                ((unsigned int) (duration%1000000)/10000));
 147                } else if (duration > 100000) {
 148                        tmp = duration%1000;
 149                        if (tmp >= 500)
 150                                duration += 1000;
 151                        printf("%u us", ((unsigned int) duration / 1000));
 152                } else if (duration > 1000) {
 153                        tmp = duration%100;
 154                        if (tmp >= 50)
 155                                duration += 100;
 156                        printf("%u.%01u us", ((unsigned int) duration/1000),
 157                                ((unsigned int) (duration%1000)/100));
 158                } else
 159                        printf("%lu ns", duration);
 160        }
 161        return;
 162}
 163
 164/* --boost / -b */
 165
 166static int get_boost_mode(unsigned int cpu)
 167{
 168        int support, active, b_states = 0, ret, pstate_no, i;
 169        /* ToDo: Make this more global */
 170        unsigned long pstates[MAX_HW_PSTATES] = {0,};
 171
 172        if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
 173            cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
 174                return 0;
 175
 176        ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
 177        if (ret) {
 178                printf(_("Error while evaluating Boost Capabilities"
 179                                " on CPU %d -- are you root?\n"), cpu);
 180                return ret;
 181        }
 182        /* P state changes via MSR are identified via cpuid 80000007
 183           on Intel and AMD, but we assume boost capable machines can do that
 184           if (cpuid_eax(0x80000000) >= 0x80000007
 185           && (cpuid_edx(0x80000007) & (1 << 7)))
 186        */
 187
 188        printf(_("  boost state support:\n"));
 189
 190        printf(_("    Supported: %s\n"), support ? _("yes") : _("no"));
 191        printf(_("    Active: %s\n"), active ? _("yes") : _("no"));
 192
 193        if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
 194            cpupower_cpu_info.family >= 0x10) {
 195                ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
 196                                     pstates, &pstate_no);
 197                if (ret)
 198                        return ret;
 199
 200                printf(_("    Boost States: %d\n"), b_states);
 201                printf(_("    Total States: %d\n"), pstate_no);
 202                for (i = 0; i < pstate_no; i++) {
 203                        if (i < b_states)
 204                                printf(_("    Pstate-Pb%d: %luMHz (boost state)"
 205                                         "\n"), i, pstates[i]);
 206                        else
 207                                printf(_("    Pstate-P%d:  %luMHz\n"),
 208                                       i - b_states, pstates[i]);
 209                }
 210        } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) {
 211                double bclk;
 212                unsigned long long intel_turbo_ratio = 0;
 213                unsigned int ratio;
 214
 215                /* Any way to autodetect this ? */
 216                if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB)
 217                        bclk = 100.00;
 218                else
 219                        bclk = 133.33;
 220                intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu);
 221                dprint ("    Ratio: 0x%llx - bclk: %f\n",
 222                        intel_turbo_ratio, bclk);
 223
 224                ratio = (intel_turbo_ratio >> 24) & 0xFF;
 225                if (ratio)
 226                        printf(_("    %.0f MHz max turbo 4 active cores\n"),
 227                               ratio * bclk);
 228
 229                ratio = (intel_turbo_ratio >> 16) & 0xFF;
 230                if (ratio)
 231                        printf(_("    %.0f MHz max turbo 3 active cores\n"),
 232                               ratio * bclk);
 233
 234                ratio = (intel_turbo_ratio >> 8) & 0xFF;
 235                if (ratio)
 236                        printf(_("    %.0f MHz max turbo 2 active cores\n"),
 237                               ratio * bclk);
 238
 239                ratio = (intel_turbo_ratio >> 0) & 0xFF;
 240                if (ratio)
 241                        printf(_("    %.0f MHz max turbo 1 active cores\n"),
 242                               ratio * bclk);
 243        }
 244        return 0;
 245}
 246
 247static void debug_output_one(unsigned int cpu)
 248{
 249        char *driver;
 250        struct cpufreq_affected_cpus *cpus;
 251        struct cpufreq_available_frequencies *freqs;
 252        unsigned long min, max, freq_kernel, freq_hardware;
 253        unsigned long total_trans, latency;
 254        unsigned long long total_time;
 255        struct cpufreq_policy *policy;
 256        struct cpufreq_available_governors *governors;
 257        struct cpufreq_stats *stats;
 258
 259        if (cpufreq_cpu_exists(cpu))
 260                return;
 261
 262        freq_kernel = cpufreq_get_freq_kernel(cpu);
 263        freq_hardware = cpufreq_get_freq_hardware(cpu);
 264
 265        driver = cpufreq_get_driver(cpu);
 266        if (!driver) {
 267                printf(_("  no or unknown cpufreq driver is active on this CPU\n"));
 268        } else {
 269                printf(_("  driver: %s\n"), driver);
 270                cpufreq_put_driver(driver);
 271        }
 272
 273        cpus = cpufreq_get_related_cpus(cpu);
 274        if (cpus) {
 275                printf(_("  CPUs which run at the same hardware frequency: "));
 276                while (cpus->next) {
 277                        printf("%d ", cpus->cpu);
 278                        cpus = cpus->next;
 279                }
 280                printf("%d\n", cpus->cpu);
 281                cpufreq_put_related_cpus(cpus);
 282        }
 283
 284        cpus = cpufreq_get_affected_cpus(cpu);
 285        if (cpus) {
 286                printf(_("  CPUs which need to have their frequency coordinated by software: "));
 287                while (cpus->next) {
 288                        printf("%d ", cpus->cpu);
 289                        cpus = cpus->next;
 290                }
 291                printf("%d\n", cpus->cpu);
 292                cpufreq_put_affected_cpus(cpus);
 293        }
 294
 295        latency = cpufreq_get_transition_latency(cpu);
 296        if (latency) {
 297                printf(_("  maximum transition latency: "));
 298                print_duration(latency);
 299                printf(".\n");
 300        }
 301
 302        if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) {
 303                printf(_("  hardware limits: "));
 304                print_speed(min);
 305                printf(" - ");
 306                print_speed(max);
 307                printf("\n");
 308        }
 309
 310        freqs = cpufreq_get_available_frequencies(cpu);
 311        if (freqs) {
 312                printf(_("  available frequency steps: "));
 313                while (freqs->next) {
 314                        print_speed(freqs->frequency);
 315                        printf(", ");
 316                        freqs = freqs->next;
 317                }
 318                print_speed(freqs->frequency);
 319                printf("\n");
 320                cpufreq_put_available_frequencies(freqs);
 321        }
 322
 323        governors = cpufreq_get_available_governors(cpu);
 324        if (governors) {
 325                printf(_("  available cpufreq governors: "));
 326                while (governors->next) {
 327                        printf("%s, ", governors->governor);
 328                        governors = governors->next;
 329                }
 330                printf("%s\n", governors->governor);
 331                cpufreq_put_available_governors(governors);
 332        }
 333
 334        policy = cpufreq_get_policy(cpu);
 335        if (policy) {
 336                printf(_("  current policy: frequency should be within "));
 337                print_speed(policy->min);
 338                printf(_(" and "));
 339                print_speed(policy->max);
 340
 341                printf(".\n                  ");
 342                printf(_("The governor \"%s\" may"
 343                       " decide which speed to use\n                  within this range.\n"),
 344                       policy->governor);
 345                cpufreq_put_policy(policy);
 346        }
 347
 348        if (freq_kernel || freq_hardware) {
 349                printf(_("  current CPU frequency is "));
 350                if (freq_hardware) {
 351                        print_speed(freq_hardware);
 352                        printf(_(" (asserted by call to hardware)"));
 353                } else
 354                        print_speed(freq_kernel);
 355                printf(".\n");
 356        }
 357        stats = cpufreq_get_stats(cpu, &total_time);
 358        if (stats) {
 359                printf(_("  cpufreq stats: "));
 360                while (stats) {
 361                        print_speed(stats->frequency);
 362                        printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
 363                        stats = stats->next;
 364                        if (stats)
 365                                printf(", ");
 366                }
 367                cpufreq_put_stats(stats);
 368                total_trans = cpufreq_get_transitions(cpu);
 369                if (total_trans)
 370                        printf("  (%lu)\n", total_trans);
 371                else
 372                        printf("\n");
 373        }
 374        get_boost_mode(cpu);
 375
 376}
 377
 378/* --freq / -f */
 379
 380static int get_freq_kernel(unsigned int cpu, unsigned int human)
 381{
 382        unsigned long freq = cpufreq_get_freq_kernel(cpu);
 383        if (!freq)
 384                return -EINVAL;
 385        if (human) {
 386                print_speed(freq);
 387                printf("\n");
 388        } else
 389                printf("%lu\n", freq);
 390        return 0;
 391}
 392
 393
 394/* --hwfreq / -w */
 395
 396static int get_freq_hardware(unsigned int cpu, unsigned int human)
 397{
 398        unsigned long freq = cpufreq_get_freq_hardware(cpu);
 399        if (!freq)
 400                return -EINVAL;
 401        if (human) {
 402                print_speed(freq);
 403                printf("\n");
 404        } else
 405                printf("%lu\n", freq);
 406        return 0;
 407}
 408
 409/* --hwlimits / -l */
 410
 411static int get_hardware_limits(unsigned int cpu)
 412{
 413        unsigned long min, max;
 414        if (cpufreq_get_hardware_limits(cpu, &min, &max))
 415                return -EINVAL;
 416        printf("%lu %lu\n", min, max);
 417        return 0;
 418}
 419
 420/* --driver / -d */
 421
 422static int get_driver(unsigned int cpu)
 423{
 424        char *driver = cpufreq_get_driver(cpu);
 425        if (!driver)
 426                return -EINVAL;
 427        printf("%s\n", driver);
 428        cpufreq_put_driver(driver);
 429        return 0;
 430}
 431
 432/* --policy / -p */
 433
 434static int get_policy(unsigned int cpu)
 435{
 436        struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
 437        if (!policy)
 438                return -EINVAL;
 439        printf("%lu %lu %s\n", policy->min, policy->max, policy->governor);
 440        cpufreq_put_policy(policy);
 441        return 0;
 442}
 443
 444/* --governors / -g */
 445
 446static int get_available_governors(unsigned int cpu)
 447{
 448        struct cpufreq_available_governors *governors =
 449                cpufreq_get_available_governors(cpu);
 450        if (!governors)
 451                return -EINVAL;
 452
 453        while (governors->next) {
 454                printf("%s ", governors->governor);
 455                governors = governors->next;
 456        }
 457        printf("%s\n", governors->governor);
 458        cpufreq_put_available_governors(governors);
 459        return 0;
 460}
 461
 462
 463/* --affected-cpus  / -a */
 464
 465static int get_affected_cpus(unsigned int cpu)
 466{
 467        struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
 468        if (!cpus)
 469                return -EINVAL;
 470
 471        while (cpus->next) {
 472                printf("%d ", cpus->cpu);
 473                cpus = cpus->next;
 474        }
 475        printf("%d\n", cpus->cpu);
 476        cpufreq_put_affected_cpus(cpus);
 477        return 0;
 478}
 479
 480/* --related-cpus  / -r */
 481
 482static int get_related_cpus(unsigned int cpu)
 483{
 484        struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
 485        if (!cpus)
 486                return -EINVAL;
 487
 488        while (cpus->next) {
 489                printf("%d ", cpus->cpu);
 490                cpus = cpus->next;
 491        }
 492        printf("%d\n", cpus->cpu);
 493        cpufreq_put_related_cpus(cpus);
 494        return 0;
 495}
 496
 497/* --stats / -s */
 498
 499static int get_freq_stats(unsigned int cpu, unsigned int human)
 500{
 501        unsigned long total_trans = cpufreq_get_transitions(cpu);
 502        unsigned long long total_time;
 503        struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
 504        while (stats) {
 505                if (human) {
 506                        print_speed(stats->frequency);
 507                        printf(":%.2f%%",
 508                                (100.0 * stats->time_in_state) / total_time);
 509                } else
 510                        printf("%lu:%llu",
 511                                stats->frequency, stats->time_in_state);
 512                stats = stats->next;
 513                if (stats)
 514                        printf(", ");
 515        }
 516        cpufreq_put_stats(stats);
 517        if (total_trans)
 518                printf("  (%lu)\n", total_trans);
 519        return 0;
 520}
 521
 522/* --latency / -y */
 523
 524static int get_latency(unsigned int cpu, unsigned int human)
 525{
 526        unsigned long latency = cpufreq_get_transition_latency(cpu);
 527        if (!latency)
 528                return -EINVAL;
 529
 530        if (human) {
 531                print_duration(latency);
 532                printf("\n");
 533        } else
 534                printf("%lu\n", latency);
 535        return 0;
 536}
 537
 538static struct option info_opts[] = {
 539        { .name = "debug",      .has_arg = no_argument,         .flag = NULL,   .val = 'e'},
 540        { .name = "boost",      .has_arg = no_argument,         .flag = NULL,   .val = 'b'},
 541        { .name = "freq",       .has_arg = no_argument,         .flag = NULL,   .val = 'f'},
 542        { .name = "hwfreq",     .has_arg = no_argument,         .flag = NULL,   .val = 'w'},
 543        { .name = "hwlimits",   .has_arg = no_argument,         .flag = NULL,   .val = 'l'},
 544        { .name = "driver",     .has_arg = no_argument,         .flag = NULL,   .val = 'd'},
 545        { .name = "policy",     .has_arg = no_argument,         .flag = NULL,   .val = 'p'},
 546        { .name = "governors",  .has_arg = no_argument,         .flag = NULL,   .val = 'g'},
 547        { .name = "related-cpus", .has_arg = no_argument,       .flag = NULL,   .val = 'r'},
 548        { .name = "affected-cpus",.has_arg = no_argument,       .flag = NULL,   .val = 'a'},
 549        { .name = "stats",      .has_arg = no_argument,         .flag = NULL,   .val = 's'},
 550        { .name = "latency",    .has_arg = no_argument,         .flag = NULL,   .val = 'y'},
 551        { .name = "proc",       .has_arg = no_argument,         .flag = NULL,   .val = 'o'},
 552        { .name = "human",      .has_arg = no_argument,         .flag = NULL,   .val = 'm'},
 553        { .name = "no-rounding", .has_arg = no_argument,        .flag = NULL,   .val = 'n'},
 554        { },
 555};
 556
 557int cmd_freq_info(int argc, char **argv)
 558{
 559        extern char *optarg;
 560        extern int optind, opterr, optopt;
 561        int ret = 0, cont = 1;
 562        unsigned int cpu = 0;
 563        unsigned int human = 0;
 564        int output_param = 0;
 565
 566        do {
 567                ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts,
 568                                  NULL);
 569                switch (ret) {
 570                case '?':
 571                        output_param = '?';
 572                        cont = 0;
 573                        break;
 574                case -1:
 575                        cont = 0;
 576                        break;
 577                case 'b':
 578                case 'o':
 579                case 'a':
 580                case 'r':
 581                case 'g':
 582                case 'p':
 583                case 'd':
 584                case 'l':
 585                case 'w':
 586                case 'f':
 587                case 'e':
 588                case 's':
 589                case 'y':
 590                        if (output_param) {
 591                                output_param = -1;
 592                                cont = 0;
 593                                break;
 594                        }
 595                        output_param = ret;
 596                        break;
 597                case 'm':
 598                        if (human) {
 599                                output_param = -1;
 600                                cont = 0;
 601                                break;
 602                        }
 603                        human = 1;
 604                        break;
 605                case 'n':
 606                        no_rounding = 1;
 607                        break;
 608                default:
 609                        fprintf(stderr, "invalid or unknown argument\n");
 610                        return EXIT_FAILURE;
 611                }
 612        } while (cont);
 613
 614        switch (output_param) {
 615        case 'o':
 616                if (!bitmask_isallclear(cpus_chosen)) {
 617                        printf(_("The argument passed to this tool can't be "
 618                                 "combined with passing a --cpu argument\n"));
 619                        return -EINVAL;
 620                }
 621                break;
 622        case 0:
 623                output_param = 'e';
 624        }
 625
 626        ret = 0;
 627
 628        /* Default is: show output of CPU 0 only */
 629        if (bitmask_isallclear(cpus_chosen))
 630                bitmask_setbit(cpus_chosen, 0);
 631
 632        switch (output_param) {
 633        case -1:
 634                printf(_("You can't specify more than one --cpu parameter and/or\n"
 635                       "more than one output-specific argument\n"));
 636                return -EINVAL;
 637        case '?':
 638                printf(_("invalid or unknown argument\n"));
 639                return -EINVAL;
 640        case 'o':
 641                proc_cpufreq_output();
 642                return EXIT_SUCCESS;
 643        }
 644
 645        for (cpu = bitmask_first(cpus_chosen);
 646             cpu <= bitmask_last(cpus_chosen); cpu++) {
 647
 648                if (!bitmask_isbitset(cpus_chosen, cpu))
 649                        continue;
 650                if (cpufreq_cpu_exists(cpu)) {
 651                        printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu);
 652                        continue;
 653                }
 654                printf(_("analyzing CPU %d:\n"), cpu);
 655
 656                switch (output_param) {
 657                case 'b':
 658                        get_boost_mode(cpu);
 659                        break;
 660                case 'e':
 661                        debug_output_one(cpu);
 662                        break;
 663                case 'a':
 664                        ret = get_affected_cpus(cpu);
 665                        break;
 666                case 'r':
 667                        ret = get_related_cpus(cpu);
 668                        break;
 669                case 'g':
 670                        ret = get_available_governors(cpu);
 671                        break;
 672                case 'p':
 673                        ret = get_policy(cpu);
 674                        break;
 675                case 'd':
 676                        ret = get_driver(cpu);
 677                        break;
 678                case 'l':
 679                        ret = get_hardware_limits(cpu);
 680                        break;
 681                case 'w':
 682                        ret = get_freq_hardware(cpu, human);
 683                        break;
 684                case 'f':
 685                        ret = get_freq_kernel(cpu, human);
 686                        break;
 687                case 's':
 688                        ret = get_freq_stats(cpu, human);
 689                        break;
 690                case 'y':
 691                        ret = get_latency(cpu, human);
 692                        break;
 693                }
 694                if (ret)
 695                        return ret;
 696        }
 697        return ret;
 698}
 699