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