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