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