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 } 670