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#include <limits.h>
  14
  15#include <getopt.h>
  16
  17#include "cpufreq.h"
  18#include "helpers/sysfs.h"
  19#include "helpers/helpers.h"
  20#include "helpers/bitmask.h"
  21
  22#define LINE_LEN 10
  23
  24static unsigned int count_cpus(void)
  25{
  26        FILE *fp;
  27        char value[LINE_LEN];
  28        unsigned int ret = 0;
  29        unsigned int cpunr = 0;
  30
  31        fp = fopen("/proc/stat", "r");
  32        if (!fp) {
  33                printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
  34                return 1;
  35        }
  36
  37        while (!feof(fp)) {
  38                if (!fgets(value, LINE_LEN, fp))
  39                        continue;
  40                value[LINE_LEN - 1] = '\0';
  41                if (strlen(value) < (LINE_LEN - 2))
  42                        continue;
  43                if (strstr(value, "cpu "))
  44                        continue;
  45                if (sscanf(value, "cpu%d ", &cpunr) != 1)
  46                        continue;
  47                if (cpunr > ret)
  48                        ret = cpunr;
  49        }
  50        fclose(fp);
  51
  52        /* cpu count starts from 0, on error return 1 (UP) */
  53        return ret + 1;
  54}
  55
  56
  57static void proc_cpufreq_output(void)
  58{
  59        unsigned int cpu, nr_cpus;
  60        struct cpufreq_policy *policy;
  61        unsigned int min_pctg = 0;
  62        unsigned int max_pctg = 0;
  63        unsigned long min, max;
  64
  65        printf(_("          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"));
  66
  67        nr_cpus = count_cpus();
  68        for (cpu = 0; cpu < nr_cpus; cpu++) {
  69                policy = cpufreq_get_policy(cpu);
  70                if (!policy)
  71                        continue;
  72
  73                if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
  74                        max = 0;
  75                } else {
  76                        min_pctg = (policy->min * 100) / max;
  77                        max_pctg = (policy->max * 100) / max;
  78                }
  79                printf("CPU%3d    %9lu kHz (%3d %%)  -  %9lu kHz (%3d %%)  -  %s\n",
  80                        cpu , policy->min, max ? min_pctg : 0, policy->max,
  81                        max ? max_pctg : 0, policy->governor);
  82
  83                cpufreq_put_policy(policy);
  84        }
  85}
  86
  87static int no_rounding;
  88static void print_speed(unsigned long speed)
  89{
  90        unsigned long tmp;
  91
  92        if (no_rounding) {
  93                if (speed > 1000000)
  94                        printf("%u.%06u GHz", ((unsigned int) speed/1000000),
  95                                ((unsigned int) speed%1000000));
  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 (!pstates[i])
 204                                continue;
 205                        if (i < b_states)
 206                                printf(_("    Pstate-Pb%d: %luMHz (boost state)"
 207                                         "\n"), i, pstates[i]);
 208                        else
 209                                printf(_("    Pstate-P%d:  %luMHz\n"),
 210                                       i - b_states, pstates[i]);
 211                }
 212        } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) {
 213                double bclk;
 214                unsigned long long intel_turbo_ratio = 0;
 215                unsigned int ratio;
 216
 217                /* Any way to autodetect this ? */
 218                if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB)
 219                        bclk = 100.00;
 220                else
 221                        bclk = 133.33;
 222                intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu);
 223                dprint ("    Ratio: 0x%llx - bclk: %f\n",
 224                        intel_turbo_ratio, bclk);
 225
 226                ratio = (intel_turbo_ratio >> 24) & 0xFF;
 227                if (ratio)
 228                        printf(_("    %.0f MHz max turbo 4 active cores\n"),
 229                               ratio * bclk);
 230
 231                ratio = (intel_turbo_ratio >> 16) & 0xFF;
 232                if (ratio)
 233                        printf(_("    %.0f MHz max turbo 3 active cores\n"),
 234                               ratio * bclk);
 235
 236                ratio = (intel_turbo_ratio >> 8) & 0xFF;
 237                if (ratio)
 238                        printf(_("    %.0f MHz max turbo 2 active cores\n"),
 239                               ratio * bclk);
 240
 241                ratio = (intel_turbo_ratio >> 0) & 0xFF;
 242                if (ratio)
 243                        printf(_("    %.0f MHz max turbo 1 active cores\n"),
 244                               ratio * bclk);
 245        }
 246        return 0;
 247}
 248
 249/* --freq / -f */
 250
 251static int get_freq_kernel(unsigned int cpu, unsigned int human)
 252{
 253        unsigned long freq = cpufreq_get_freq_kernel(cpu);
 254        printf(_("  current CPU frequency: "));
 255        if (!freq) {
 256                printf(_(" Unable to call to kernel\n"));
 257                return -EINVAL;
 258        }
 259        if (human) {
 260                print_speed(freq);
 261        } else
 262                printf("%lu", freq);
 263        printf(_(" (asserted by call to kernel)\n"));
 264        return 0;
 265}
 266
 267
 268/* --hwfreq / -w */
 269
 270static int get_freq_hardware(unsigned int cpu, unsigned int human)
 271{
 272        unsigned long freq = cpufreq_get_freq_hardware(cpu);
 273        printf(_("  current CPU frequency: "));
 274        if (!freq) {
 275                printf("Unable to call hardware\n");
 276                return -EINVAL;
 277        }
 278        if (human) {
 279                print_speed(freq);
 280        } else
 281                printf("%lu", freq);
 282        printf(_(" (asserted by call to hardware)\n"));
 283        return 0;
 284}
 285
 286/* --hwlimits / -l */
 287
 288static int get_hardware_limits(unsigned int cpu, unsigned int human)
 289{
 290        unsigned long min, max;
 291
 292        if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
 293                printf(_("Not Available\n"));
 294                return -EINVAL;
 295        }
 296
 297        if (human) {
 298                printf(_("  hardware limits: "));
 299                print_speed(min);
 300                printf(" - ");
 301                print_speed(max);
 302                printf("\n");
 303        } else {
 304                printf("%lu %lu\n", min, max);
 305        }
 306        return 0;
 307}
 308
 309/* --driver / -d */
 310
 311static int get_driver(unsigned int cpu)
 312{
 313        char *driver = cpufreq_get_driver(cpu);
 314        if (!driver) {
 315                printf(_("  no or unknown cpufreq driver is active on this CPU\n"));
 316                return -EINVAL;
 317        }
 318        printf("  driver: %s\n", driver);
 319        cpufreq_put_driver(driver);
 320        return 0;
 321}
 322
 323/* --policy / -p */
 324
 325static int get_policy(unsigned int cpu)
 326{
 327        struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
 328        if (!policy) {
 329                printf(_("  Unable to determine current policy\n"));
 330                return -EINVAL;
 331        }
 332        printf(_("  current policy: frequency should be within "));
 333        print_speed(policy->min);
 334        printf(_(" and "));
 335        print_speed(policy->max);
 336
 337        printf(".\n                  ");
 338        printf(_("The governor \"%s\" may decide which speed to use\n"
 339               "                  within this range.\n"),
 340               policy->governor);
 341        cpufreq_put_policy(policy);
 342        return 0;
 343}
 344
 345/* --governors / -g */
 346
 347static int get_available_governors(unsigned int cpu)
 348{
 349        struct cpufreq_available_governors *governors =
 350                cpufreq_get_available_governors(cpu);
 351
 352        printf(_("  available cpufreq governors: "));
 353        if (!governors) {
 354                printf(_("Not Available\n"));
 355                return -EINVAL;
 356        }
 357
 358        while (governors->next) {
 359                printf("%s ", governors->governor);
 360                governors = governors->next;
 361        }
 362        printf("%s\n", governors->governor);
 363        cpufreq_put_available_governors(governors);
 364        return 0;
 365}
 366
 367
 368/* --affected-cpus  / -a */
 369
 370static int get_affected_cpus(unsigned int cpu)
 371{
 372        struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
 373
 374        printf(_("  CPUs which need to have their frequency coordinated by software: "));
 375        if (!cpus) {
 376                printf(_("Not Available\n"));
 377                return -EINVAL;
 378        }
 379
 380        while (cpus->next) {
 381                printf("%d ", cpus->cpu);
 382                cpus = cpus->next;
 383        }
 384        printf("%d\n", cpus->cpu);
 385        cpufreq_put_affected_cpus(cpus);
 386        return 0;
 387}
 388
 389/* --related-cpus  / -r */
 390
 391static int get_related_cpus(unsigned int cpu)
 392{
 393        struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
 394
 395        printf(_("  CPUs which run at the same hardware frequency: "));
 396        if (!cpus) {
 397                printf(_("Not Available\n"));
 398                return -EINVAL;
 399        }
 400
 401        while (cpus->next) {
 402                printf("%d ", cpus->cpu);
 403                cpus = cpus->next;
 404        }
 405        printf("%d\n", cpus->cpu);
 406        cpufreq_put_related_cpus(cpus);
 407        return 0;
 408}
 409
 410/* --stats / -s */
 411
 412static int get_freq_stats(unsigned int cpu, unsigned int human)
 413{
 414        unsigned long total_trans = cpufreq_get_transitions(cpu);
 415        unsigned long long total_time;
 416        struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
 417        while (stats) {
 418                if (human) {
 419                        print_speed(stats->frequency);
 420                        printf(":%.2f%%",
 421                                (100.0 * stats->time_in_state) / total_time);
 422                } else
 423                        printf("%lu:%llu",
 424                                stats->frequency, stats->time_in_state);
 425                stats = stats->next;
 426                if (stats)
 427                        printf(", ");
 428        }
 429        cpufreq_put_stats(stats);
 430        if (total_trans)
 431                printf("  (%lu)\n", total_trans);
 432        return 0;
 433}
 434
 435/* --latency / -y */
 436
 437static int get_latency(unsigned int cpu, unsigned int human)
 438{
 439        unsigned long latency = cpufreq_get_transition_latency(cpu);
 440
 441        printf(_("  maximum transition latency: "));
 442        if (!latency || latency == UINT_MAX) {
 443                printf(_(" Cannot determine or is not supported.\n"));
 444                return -EINVAL;
 445        }
 446
 447        if (human) {
 448                print_duration(latency);
 449                printf("\n");
 450        } else
 451                printf("%lu\n", latency);
 452        return 0;
 453}
 454
 455static void debug_output_one(unsigned int cpu)
 456{
 457        struct cpufreq_available_frequencies *freqs;
 458
 459        get_driver(cpu);
 460        get_related_cpus(cpu);
 461        get_affected_cpus(cpu);
 462        get_latency(cpu, 1);
 463        get_hardware_limits(cpu, 1);
 464
 465        freqs = cpufreq_get_available_frequencies(cpu);
 466        if (freqs) {
 467                printf(_("  available frequency steps:  "));
 468                while (freqs->next) {
 469                        print_speed(freqs->frequency);
 470                        printf(", ");
 471                        freqs = freqs->next;
 472                }
 473                print_speed(freqs->frequency);
 474                printf("\n");
 475                cpufreq_put_available_frequencies(freqs);
 476        }
 477
 478        get_available_governors(cpu);
 479        get_policy(cpu);
 480        if (get_freq_hardware(cpu, 1) < 0)
 481                get_freq_kernel(cpu, 1);
 482        get_boost_mode(cpu);
 483}
 484
 485static struct option info_opts[] = {
 486        {"debug",        no_argument,            NULL,   'e'},
 487        {"boost",        no_argument,            NULL,   'b'},
 488        {"freq",         no_argument,            NULL,   'f'},
 489        {"hwfreq",       no_argument,            NULL,   'w'},
 490        {"hwlimits",     no_argument,            NULL,   'l'},
 491        {"driver",       no_argument,            NULL,   'd'},
 492        {"policy",       no_argument,            NULL,   'p'},
 493        {"governors",    no_argument,            NULL,   'g'},
 494        {"related-cpus",  no_argument,   NULL,   'r'},
 495        {"affected-cpus", no_argument,   NULL,   'a'},
 496        {"stats",        no_argument,            NULL,   's'},
 497        {"latency",      no_argument,            NULL,   'y'},
 498        {"proc",         no_argument,            NULL,   'o'},
 499        {"human",        no_argument,            NULL,   'm'},
 500        {"no-rounding", no_argument,     NULL,   'n'},
 501        { },
 502};
 503
 504int cmd_freq_info(int argc, char **argv)
 505{
 506        extern char *optarg;
 507        extern int optind, opterr, optopt;
 508        int ret = 0, cont = 1;
 509        unsigned int cpu = 0;
 510        unsigned int human = 0;
 511        int output_param = 0;
 512
 513        do {
 514                ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts,
 515                                  NULL);
 516                switch (ret) {
 517                case '?':
 518                        output_param = '?';
 519                        cont = 0;
 520                        break;
 521                case -1:
 522                        cont = 0;
 523                        break;
 524                case 'b':
 525                case 'o':
 526                case 'a':
 527                case 'r':
 528                case 'g':
 529                case 'p':
 530                case 'd':
 531                case 'l':
 532                case 'w':
 533                case 'f':
 534                case 'e':
 535                case 's':
 536                case 'y':
 537                        if (output_param) {
 538                                output_param = -1;
 539                                cont = 0;
 540                                break;
 541                        }
 542                        output_param = ret;
 543                        break;
 544                case 'm':
 545                        if (human) {
 546                                output_param = -1;
 547                                cont = 0;
 548                                break;
 549                        }
 550                        human = 1;
 551                        break;
 552                case 'n':
 553                        no_rounding = 1;
 554                        break;
 555                default:
 556                        fprintf(stderr, "invalid or unknown argument\n");
 557                        return EXIT_FAILURE;
 558                }
 559        } while (cont);
 560
 561        switch (output_param) {
 562        case 'o':
 563                if (!bitmask_isallclear(cpus_chosen)) {
 564                        printf(_("The argument passed to this tool can't be "
 565                                 "combined with passing a --cpu argument\n"));
 566                        return -EINVAL;
 567                }
 568                break;
 569        case 0:
 570                output_param = 'e';
 571        }
 572
 573        ret = 0;
 574
 575        /* Default is: show output of CPU 0 only */
 576        if (bitmask_isallclear(cpus_chosen))
 577                bitmask_setbit(cpus_chosen, 0);
 578
 579        switch (output_param) {
 580        case -1:
 581                printf(_("You can't specify more than one --cpu parameter and/or\n"
 582                       "more than one output-specific argument\n"));
 583                return -EINVAL;
 584        case '?':
 585                printf(_("invalid or unknown argument\n"));
 586                return -EINVAL;
 587        case 'o':
 588                proc_cpufreq_output();
 589                return EXIT_SUCCESS;
 590        }
 591
 592        for (cpu = bitmask_first(cpus_chosen);
 593             cpu <= bitmask_last(cpus_chosen); cpu++) {
 594
 595                if (!bitmask_isbitset(cpus_chosen, cpu))
 596                        continue;
 597
 598                printf(_("analyzing CPU %d:\n"), cpu);
 599
 600                if (sysfs_is_cpu_online(cpu) != 1) {
 601                        printf(_(" *is offline\n"));
 602                        printf("\n");
 603                        continue;
 604                }
 605
 606                switch (output_param) {
 607                case 'b':
 608                        get_boost_mode(cpu);
 609                        break;
 610                case 'e':
 611                        debug_output_one(cpu);
 612                        break;
 613                case 'a':
 614                        ret = get_affected_cpus(cpu);
 615                        break;
 616                case 'r':
 617                        ret = get_related_cpus(cpu);
 618                        break;
 619                case 'g':
 620                        ret = get_available_governors(cpu);
 621                        break;
 622                case 'p':
 623                        ret = get_policy(cpu);
 624                        break;
 625                case 'd':
 626                        ret = get_driver(cpu);
 627                        break;
 628                case 'l':
 629                        ret = get_hardware_limits(cpu, human);
 630                        break;
 631                case 'w':
 632                        ret = get_freq_hardware(cpu, human);
 633                        break;
 634                case 'f':
 635                        ret = get_freq_kernel(cpu, human);
 636                        break;
 637                case 's':
 638                        ret = get_freq_stats(cpu, human);
 639                        break;
 640                case 'y':
 641                        ret = get_latency(cpu, human);
 642                        break;
 643                }
 644                if (ret)
 645                        return ret;
 646        }
 647        return ret;
 648}
 649