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