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, 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 244 static 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 271 static 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 290 static 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 308 static 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 331 static 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 345 static 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 367 static 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 390 static 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 411 static 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 432 static 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 457 static 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 475 static 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 505 static 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 524 int 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