root/tools/power/cpupower/utils/cpufreq-info.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. count_cpus
  2. proc_cpufreq_output
  3. print_speed
  4. print_duration
  5. get_boost_mode_x86
  6. get_boost_mode
  7. get_freq_kernel
  8. get_freq_hardware
  9. get_hardware_limits
  10. get_driver
  11. get_policy
  12. get_available_governors
  13. get_affected_cpus
  14. get_related_cpus
  15. get_freq_stats
  16. get_latency
  17. debug_output_one
  18. cmd_freq_info

   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 
  23 static 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 
  56 static 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 
  86 static int no_rounding;
  87 static 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 
 124 static 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 
 163 static 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 
 245 static 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 
 272 static 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 
 291 static 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 
 309 static 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 
 332 static 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 
 346 static 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 
 368 static 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 
 391 static 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 
 412 static 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 
 433 static 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 
 458 static 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 
 476 static 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 
 506 static 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 
 525 int 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 }

/* [<][>][^][v][top][bottom][index][help] */