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 /* --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 /* --freq / -f */ 248 249 static int get_freq_kernel(unsigned int cpu, unsigned int human) 250 { 251 unsigned long freq = cpufreq_get_freq_kernel(cpu); 252 printf(_(" current CPU frequency: ")); 253 if (!freq) { 254 printf(_(" Unable to call to kernel\n")); 255 return -EINVAL; 256 } 257 if (human) { 258 print_speed(freq); 259 } else 260 printf("%lu", freq); 261 printf(_(" (asserted by call to kernel)\n")); 262 return 0; 263 } 264 265 266 /* --hwfreq / -w */ 267 268 static int get_freq_hardware(unsigned int cpu, unsigned int human) 269 { 270 unsigned long freq = cpufreq_get_freq_hardware(cpu); 271 printf(_(" current CPU frequency: ")); 272 if (!freq) { 273 printf("Unable to call hardware\n"); 274 return -EINVAL; 275 } 276 if (human) { 277 print_speed(freq); 278 } else 279 printf("%lu", freq); 280 printf(_(" (asserted by call to hardware)\n")); 281 return 0; 282 } 283 284 /* --hwlimits / -l */ 285 286 static int get_hardware_limits(unsigned int cpu, unsigned int human) 287 { 288 unsigned long min, max; 289 290 if (cpufreq_get_hardware_limits(cpu, &min, &max)) { 291 printf(_("Not Available\n")); 292 return -EINVAL; 293 } 294 295 if (human) { 296 printf(_(" hardware limits: ")); 297 print_speed(min); 298 printf(" - "); 299 print_speed(max); 300 printf("\n"); 301 } else { 302 printf("%lu %lu\n", min, max); 303 } 304 return 0; 305 } 306 307 /* --driver / -d */ 308 309 static int get_driver(unsigned int cpu) 310 { 311 char *driver = cpufreq_get_driver(cpu); 312 if (!driver) { 313 printf(_(" no or unknown cpufreq driver is active on this CPU\n")); 314 return -EINVAL; 315 } 316 printf(" driver: %s\n", driver); 317 cpufreq_put_driver(driver); 318 return 0; 319 } 320 321 /* --policy / -p */ 322 323 static int get_policy(unsigned int cpu) 324 { 325 struct cpufreq_policy *policy = cpufreq_get_policy(cpu); 326 if (!policy) { 327 printf(_(" Unable to determine current policy\n")); 328 return -EINVAL; 329 } 330 printf(_(" current policy: frequency should be within ")); 331 print_speed(policy->min); 332 printf(_(" and ")); 333 print_speed(policy->max); 334 335 printf(".\n "); 336 printf(_("The governor \"%s\" may decide which speed to use\n" 337 " within this range.\n"), 338 policy->governor); 339 cpufreq_put_policy(policy); 340 return 0; 341 } 342 343 /* --governors / -g */ 344 345 static int get_available_governors(unsigned int cpu) 346 { 347 struct cpufreq_available_governors *governors = 348 cpufreq_get_available_governors(cpu); 349 350 printf(_(" available cpufreq governors: ")); 351 if (!governors) { 352 printf(_("Not Available\n")); 353 return -EINVAL; 354 } 355 356 while (governors->next) { 357 printf("%s ", governors->governor); 358 governors = governors->next; 359 } 360 printf("%s\n", governors->governor); 361 cpufreq_put_available_governors(governors); 362 return 0; 363 } 364 365 366 /* --affected-cpus / -a */ 367 368 static int get_affected_cpus(unsigned int cpu) 369 { 370 struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu); 371 372 printf(_(" CPUs which need to have their frequency coordinated by software: ")); 373 if (!cpus) { 374 printf(_("Not Available\n")); 375 return -EINVAL; 376 } 377 378 while (cpus->next) { 379 printf("%d ", cpus->cpu); 380 cpus = cpus->next; 381 } 382 printf("%d\n", cpus->cpu); 383 cpufreq_put_affected_cpus(cpus); 384 return 0; 385 } 386 387 /* --related-cpus / -r */ 388 389 static int get_related_cpus(unsigned int cpu) 390 { 391 struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu); 392 393 printf(_(" CPUs which run at the same hardware frequency: ")); 394 if (!cpus) { 395 printf(_("Not Available\n")); 396 return -EINVAL; 397 } 398 399 while (cpus->next) { 400 printf("%d ", cpus->cpu); 401 cpus = cpus->next; 402 } 403 printf("%d\n", cpus->cpu); 404 cpufreq_put_related_cpus(cpus); 405 return 0; 406 } 407 408 /* --stats / -s */ 409 410 static int get_freq_stats(unsigned int cpu, unsigned int human) 411 { 412 unsigned long total_trans = cpufreq_get_transitions(cpu); 413 unsigned long long total_time; 414 struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time); 415 while (stats) { 416 if (human) { 417 print_speed(stats->frequency); 418 printf(":%.2f%%", 419 (100.0 * stats->time_in_state) / total_time); 420 } else 421 printf("%lu:%llu", 422 stats->frequency, stats->time_in_state); 423 stats = stats->next; 424 if (stats) 425 printf(", "); 426 } 427 cpufreq_put_stats(stats); 428 if (total_trans) 429 printf(" (%lu)\n", total_trans); 430 return 0; 431 } 432 433 /* --latency / -y */ 434 435 static int get_latency(unsigned int cpu, unsigned int human) 436 { 437 unsigned long latency = cpufreq_get_transition_latency(cpu); 438 439 printf(_(" maximum transition latency: ")); 440 if (!latency || latency == UINT_MAX) { 441 printf(_(" Cannot determine or is not supported.\n")); 442 return -EINVAL; 443 } 444 445 if (human) { 446 print_duration(latency); 447 printf("\n"); 448 } else 449 printf("%lu\n", latency); 450 return 0; 451 } 452 453 static void debug_output_one(unsigned int cpu) 454 { 455 struct cpufreq_available_frequencies *freqs; 456 457 get_driver(cpu); 458 get_related_cpus(cpu); 459 get_affected_cpus(cpu); 460 get_latency(cpu, 1); 461 get_hardware_limits(cpu, 1); 462 463 freqs = cpufreq_get_available_frequencies(cpu); 464 if (freqs) { 465 printf(_(" available frequency steps: ")); 466 while (freqs->next) { 467 print_speed(freqs->frequency); 468 printf(", "); 469 freqs = freqs->next; 470 } 471 print_speed(freqs->frequency); 472 printf("\n"); 473 cpufreq_put_available_frequencies(freqs); 474 } 475 476 get_available_governors(cpu); 477 get_policy(cpu); 478 if (get_freq_hardware(cpu, 1) < 0) 479 get_freq_kernel(cpu, 1); 480 get_boost_mode(cpu); 481 } 482 483 static struct option info_opts[] = { 484 {"debug", no_argument, NULL, 'e'}, 485 {"boost", no_argument, NULL, 'b'}, 486 {"freq", no_argument, NULL, 'f'}, 487 {"hwfreq", no_argument, NULL, 'w'}, 488 {"hwlimits", no_argument, NULL, 'l'}, 489 {"driver", no_argument, NULL, 'd'}, 490 {"policy", no_argument, NULL, 'p'}, 491 {"governors", no_argument, NULL, 'g'}, 492 {"related-cpus", no_argument, NULL, 'r'}, 493 {"affected-cpus", no_argument, NULL, 'a'}, 494 {"stats", no_argument, NULL, 's'}, 495 {"latency", no_argument, NULL, 'y'}, 496 {"proc", no_argument, NULL, 'o'}, 497 {"human", no_argument, NULL, 'm'}, 498 {"no-rounding", no_argument, NULL, 'n'}, 499 { }, 500 }; 501 502 int cmd_freq_info(int argc, char **argv) 503 { 504 extern char *optarg; 505 extern int optind, opterr, optopt; 506 int ret = 0, cont = 1; 507 unsigned int cpu = 0; 508 unsigned int human = 0; 509 int output_param = 0; 510 511 do { 512 ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts, 513 NULL); 514 switch (ret) { 515 case '?': 516 output_param = '?'; 517 cont = 0; 518 break; 519 case -1: 520 cont = 0; 521 break; 522 case 'b': 523 case 'o': 524 case 'a': 525 case 'r': 526 case 'g': 527 case 'p': 528 case 'd': 529 case 'l': 530 case 'w': 531 case 'f': 532 case 'e': 533 case 's': 534 case 'y': 535 if (output_param) { 536 output_param = -1; 537 cont = 0; 538 break; 539 } 540 output_param = ret; 541 break; 542 case 'm': 543 if (human) { 544 output_param = -1; 545 cont = 0; 546 break; 547 } 548 human = 1; 549 break; 550 case 'n': 551 no_rounding = 1; 552 break; 553 default: 554 fprintf(stderr, "invalid or unknown argument\n"); 555 return EXIT_FAILURE; 556 } 557 } while (cont); 558 559 switch (output_param) { 560 case 'o': 561 if (!bitmask_isallclear(cpus_chosen)) { 562 printf(_("The argument passed to this tool can't be " 563 "combined with passing a --cpu argument\n")); 564 return -EINVAL; 565 } 566 break; 567 case 0: 568 output_param = 'e'; 569 } 570 571 ret = 0; 572 573 /* Default is: show output of CPU 0 only */ 574 if (bitmask_isallclear(cpus_chosen)) 575 bitmask_setbit(cpus_chosen, 0); 576 577 switch (output_param) { 578 case -1: 579 printf(_("You can't specify more than one --cpu parameter and/or\n" 580 "more than one output-specific argument\n")); 581 return -EINVAL; 582 case '?': 583 printf(_("invalid or unknown argument\n")); 584 return -EINVAL; 585 case 'o': 586 proc_cpufreq_output(); 587 return EXIT_SUCCESS; 588 } 589 590 for (cpu = bitmask_first(cpus_chosen); 591 cpu <= bitmask_last(cpus_chosen); cpu++) { 592 593 if (!bitmask_isbitset(cpus_chosen, cpu)) 594 continue; 595 596 printf(_("analyzing CPU %d:\n"), cpu); 597 598 if (sysfs_is_cpu_online(cpu) != 1) { 599 printf(_(" *is offline\n")); 600 printf("\n"); 601 continue; 602 } 603 604 switch (output_param) { 605 case 'b': 606 get_boost_mode(cpu); 607 break; 608 case 'e': 609 debug_output_one(cpu); 610 break; 611 case 'a': 612 ret = get_affected_cpus(cpu); 613 break; 614 case 'r': 615 ret = get_related_cpus(cpu); 616 break; 617 case 'g': 618 ret = get_available_governors(cpu); 619 break; 620 case 'p': 621 ret = get_policy(cpu); 622 break; 623 case 'd': 624 ret = get_driver(cpu); 625 break; 626 case 'l': 627 ret = get_hardware_limits(cpu, human); 628 break; 629 case 'w': 630 ret = get_freq_hardware(cpu, human); 631 break; 632 case 'f': 633 ret = get_freq_kernel(cpu, human); 634 break; 635 case 's': 636 ret = get_freq_stats(cpu, human); 637 break; 638 case 'y': 639 ret = get_latency(cpu, human); 640 break; 641 } 642 if (ret) 643 return ret; 644 } 645 return ret; 646 } 647