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