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