linux/tools/power/cpupower/utils/cpufreq-info.c
<<
>>
Prefs
   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
  24static 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
  57static 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
  87static int no_rounding;
  88static 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
 125static 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
 166static 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
 249static 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
 268static 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
 286static 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
 309static 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
 323static 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
 345static 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
 368static 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
 389static 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
 410static 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
 435static 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
 453static 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
 483static 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
 502int 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