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