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