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