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