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