123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- /*
- * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
- *
- * Licensed under the terms of the GNU GPL License version 2.
- */
- #include <unistd.h>
- #include <stdio.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include <getopt.h>
- #include "cpufreq.h"
- #include "helpers/helpers.h"
- #include "helpers/bitmask.h"
- #define LINE_LEN 10
- static unsigned int count_cpus(void)
- {
- FILE *fp;
- char value[LINE_LEN];
- unsigned int ret = 0;
- unsigned int cpunr = 0;
- fp = fopen("/proc/stat", "r");
- if (!fp) {
- printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
- return 1;
- }
- while (!feof(fp)) {
- if (!fgets(value, LINE_LEN, fp))
- continue;
- value[LINE_LEN - 1] = '\0';
- if (strlen(value) < (LINE_LEN - 2))
- continue;
- if (strstr(value, "cpu "))
- continue;
- if (sscanf(value, "cpu%d ", &cpunr) != 1)
- continue;
- if (cpunr > ret)
- ret = cpunr;
- }
- fclose(fp);
- /* cpu count starts from 0, on error return 1 (UP) */
- return ret + 1;
- }
- static void proc_cpufreq_output(void)
- {
- unsigned int cpu, nr_cpus;
- struct cpufreq_policy *policy;
- unsigned int min_pctg = 0;
- unsigned int max_pctg = 0;
- unsigned long min, max;
- printf(_(" minimum CPU frequency - maximum CPU frequency - governor\n"));
- nr_cpus = count_cpus();
- for (cpu = 0; cpu < nr_cpus; cpu++) {
- policy = cpufreq_get_policy(cpu);
- if (!policy)
- continue;
- if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
- max = 0;
- } else {
- min_pctg = (policy->min * 100) / max;
- max_pctg = (policy->max * 100) / max;
- }
- printf("CPU%3d %9lu kHz (%3d %%) - %9lu kHz (%3d %%) - %s\n",
- cpu , policy->min, max ? min_pctg : 0, policy->max,
- max ? max_pctg : 0, policy->governor);
- cpufreq_put_policy(policy);
- }
- }
- static void print_speed(unsigned long speed)
- {
- unsigned long tmp;
- if (speed > 1000000) {
- tmp = speed % 10000;
- if (tmp >= 5000)
- speed += 10000;
- printf("%u.%02u GHz", ((unsigned int) speed/1000000),
- ((unsigned int) (speed%1000000)/10000));
- } else if (speed > 100000) {
- tmp = speed % 1000;
- if (tmp >= 500)
- speed += 1000;
- printf("%u MHz", ((unsigned int) speed / 1000));
- } else if (speed > 1000) {
- tmp = speed % 100;
- if (tmp >= 50)
- speed += 100;
- printf("%u.%01u MHz", ((unsigned int) speed/1000),
- ((unsigned int) (speed%1000)/100));
- } else
- printf("%lu kHz", speed);
- return;
- }
- static void print_duration(unsigned long duration)
- {
- unsigned long tmp;
- if (duration > 1000000) {
- tmp = duration % 10000;
- if (tmp >= 5000)
- duration += 10000;
- printf("%u.%02u ms", ((unsigned int) duration/1000000),
- ((unsigned int) (duration%1000000)/10000));
- } else if (duration > 100000) {
- tmp = duration % 1000;
- if (tmp >= 500)
- duration += 1000;
- printf("%u us", ((unsigned int) duration / 1000));
- } else if (duration > 1000) {
- tmp = duration % 100;
- if (tmp >= 50)
- duration += 100;
- printf("%u.%01u us", ((unsigned int) duration/1000),
- ((unsigned int) (duration%1000)/100));
- } else
- printf("%lu ns", duration);
- return;
- }
- /* --boost / -b */
- static int get_boost_mode(unsigned int cpu)
- {
- int support, active, b_states = 0, ret, pstate_no, i;
- /* ToDo: Make this more global */
- unsigned long pstates[MAX_HW_PSTATES] = {0,};
- if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
- cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
- return 0;
- ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
- if (ret) {
- printf(_("Error while evaluating Boost Capabilities"
- " on CPU %d -- are you root?\n"), cpu);
- return ret;
- }
- /* P state changes via MSR are identified via cpuid 80000007
- on Intel and AMD, but we assume boost capable machines can do that
- if (cpuid_eax(0x80000000) >= 0x80000007
- && (cpuid_edx(0x80000007) & (1 << 7)))
- */
- printf(_(" boost state support:\n"));
- printf(_(" Supported: %s\n"), support ? _("yes") : _("no"));
- printf(_(" Active: %s\n"), active ? _("yes") : _("no"));
- if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
- cpupower_cpu_info.family >= 0x10) {
- ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
- pstates, &pstate_no);
- if (ret)
- return ret;
- printf(_(" Boost States: %d\n"), b_states);
- printf(_(" Total States: %d\n"), pstate_no);
- for (i = 0; i < pstate_no; i++) {
- if (i < b_states)
- printf(_(" Pstate-Pb%d: %luMHz (boost state)"
- "\n"), i, pstates[i]);
- else
- printf(_(" Pstate-P%d: %luMHz\n"),
- i - b_states, pstates[i]);
- }
- } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) {
- double bclk;
- unsigned long long intel_turbo_ratio = 0;
- unsigned int ratio;
- /* Any way to autodetect this ? */
- if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB)
- bclk = 100.00;
- else
- bclk = 133.33;
- intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu);
- dprint (" Ratio: 0x%llx - bclk: %f\n",
- intel_turbo_ratio, bclk);
- ratio = (intel_turbo_ratio >> 24) & 0xFF;
- if (ratio)
- printf(_(" %.0f MHz max turbo 4 active cores\n"),
- ratio * bclk);
- ratio = (intel_turbo_ratio >> 16) & 0xFF;
- if (ratio)
- printf(_(" %.0f MHz max turbo 3 active cores\n"),
- ratio * bclk);
- ratio = (intel_turbo_ratio >> 8) & 0xFF;
- if (ratio)
- printf(_(" %.0f MHz max turbo 2 active cores\n"),
- ratio * bclk);
- ratio = (intel_turbo_ratio >> 0) & 0xFF;
- if (ratio)
- printf(_(" %.0f MHz max turbo 1 active cores\n"),
- ratio * bclk);
- }
- return 0;
- }
- static void debug_output_one(unsigned int cpu)
- {
- char *driver;
- struct cpufreq_affected_cpus *cpus;
- struct cpufreq_available_frequencies *freqs;
- unsigned long min, max, freq_kernel, freq_hardware;
- unsigned long total_trans, latency;
- unsigned long long total_time;
- struct cpufreq_policy *policy;
- struct cpufreq_available_governors *governors;
- struct cpufreq_stats *stats;
- if (cpufreq_cpu_exists(cpu))
- return;
- freq_kernel = cpufreq_get_freq_kernel(cpu);
- freq_hardware = cpufreq_get_freq_hardware(cpu);
- driver = cpufreq_get_driver(cpu);
- if (!driver) {
- printf(_(" no or unknown cpufreq driver is active on this CPU\n"));
- } else {
- printf(_(" driver: %s\n"), driver);
- cpufreq_put_driver(driver);
- }
- cpus = cpufreq_get_related_cpus(cpu);
- if (cpus) {
- printf(_(" CPUs which run at the same hardware frequency: "));
- while (cpus->next) {
- printf("%d ", cpus->cpu);
- cpus = cpus->next;
- }
- printf("%d\n", cpus->cpu);
- cpufreq_put_related_cpus(cpus);
- }
- cpus = cpufreq_get_affected_cpus(cpu);
- if (cpus) {
- printf(_(" CPUs which need to have their frequency coordinated by software: "));
- while (cpus->next) {
- printf("%d ", cpus->cpu);
- cpus = cpus->next;
- }
- printf("%d\n", cpus->cpu);
- cpufreq_put_affected_cpus(cpus);
- }
- latency = cpufreq_get_transition_latency(cpu);
- if (latency) {
- printf(_(" maximum transition latency: "));
- print_duration(latency);
- printf(".\n");
- }
- if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) {
- printf(_(" hardware limits: "));
- print_speed(min);
- printf(" - ");
- print_speed(max);
- printf("\n");
- }
- freqs = cpufreq_get_available_frequencies(cpu);
- if (freqs) {
- printf(_(" available frequency steps: "));
- while (freqs->next) {
- print_speed(freqs->frequency);
- printf(", ");
- freqs = freqs->next;
- }
- print_speed(freqs->frequency);
- printf("\n");
- cpufreq_put_available_frequencies(freqs);
- }
- governors = cpufreq_get_available_governors(cpu);
- if (governors) {
- printf(_(" available cpufreq governors: "));
- while (governors->next) {
- printf("%s, ", governors->governor);
- governors = governors->next;
- }
- printf("%s\n", governors->governor);
- cpufreq_put_available_governors(governors);
- }
- policy = cpufreq_get_policy(cpu);
- if (policy) {
- printf(_(" current policy: frequency should be within "));
- print_speed(policy->min);
- printf(_(" and "));
- print_speed(policy->max);
- printf(".\n ");
- printf(_("The governor \"%s\" may"
- " decide which speed to use\n within this range.\n"),
- policy->governor);
- cpufreq_put_policy(policy);
- }
- if (freq_kernel || freq_hardware) {
- printf(_(" current CPU frequency is "));
- if (freq_hardware) {
- print_speed(freq_hardware);
- printf(_(" (asserted by call to hardware)"));
- } else
- print_speed(freq_kernel);
- printf(".\n");
- }
- stats = cpufreq_get_stats(cpu, &total_time);
- if (stats) {
- printf(_(" cpufreq stats: "));
- while (stats) {
- print_speed(stats->frequency);
- printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
- stats = stats->next;
- if (stats)
- printf(", ");
- }
- cpufreq_put_stats(stats);
- total_trans = cpufreq_get_transitions(cpu);
- if (total_trans)
- printf(" (%lu)\n", total_trans);
- else
- printf("\n");
- }
- get_boost_mode(cpu);
- }
- /* --freq / -f */
- static int get_freq_kernel(unsigned int cpu, unsigned int human)
- {
- unsigned long freq = cpufreq_get_freq_kernel(cpu);
- if (!freq)
- return -EINVAL;
- if (human) {
- print_speed(freq);
- printf("\n");
- } else
- printf("%lu\n", freq);
- return 0;
- }
- /* --hwfreq / -w */
- static int get_freq_hardware(unsigned int cpu, unsigned int human)
- {
- unsigned long freq = cpufreq_get_freq_hardware(cpu);
- if (!freq)
- return -EINVAL;
- if (human) {
- print_speed(freq);
- printf("\n");
- } else
- printf("%lu\n", freq);
- return 0;
- }
- /* --hwlimits / -l */
- static int get_hardware_limits(unsigned int cpu)
- {
- unsigned long min, max;
- if (cpufreq_get_hardware_limits(cpu, &min, &max))
- return -EINVAL;
- printf("%lu %lu\n", min, max);
- return 0;
- }
- /* --driver / -d */
- static int get_driver(unsigned int cpu)
- {
- char *driver = cpufreq_get_driver(cpu);
- if (!driver)
- return -EINVAL;
- printf("%s\n", driver);
- cpufreq_put_driver(driver);
- return 0;
- }
- /* --policy / -p */
- static int get_policy(unsigned int cpu)
- {
- struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
- if (!policy)
- return -EINVAL;
- printf("%lu %lu %s\n", policy->min, policy->max, policy->governor);
- cpufreq_put_policy(policy);
- return 0;
- }
- /* --governors / -g */
- static int get_available_governors(unsigned int cpu)
- {
- struct cpufreq_available_governors *governors =
- cpufreq_get_available_governors(cpu);
- if (!governors)
- return -EINVAL;
- while (governors->next) {
- printf("%s ", governors->governor);
- governors = governors->next;
- }
- printf("%s\n", governors->governor);
- cpufreq_put_available_governors(governors);
- return 0;
- }
- /* --affected-cpus / -a */
- static int get_affected_cpus(unsigned int cpu)
- {
- struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
- if (!cpus)
- return -EINVAL;
- while (cpus->next) {
- printf("%d ", cpus->cpu);
- cpus = cpus->next;
- }
- printf("%d\n", cpus->cpu);
- cpufreq_put_affected_cpus(cpus);
- return 0;
- }
- /* --related-cpus / -r */
- static int get_related_cpus(unsigned int cpu)
- {
- struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
- if (!cpus)
- return -EINVAL;
- while (cpus->next) {
- printf("%d ", cpus->cpu);
- cpus = cpus->next;
- }
- printf("%d\n", cpus->cpu);
- cpufreq_put_related_cpus(cpus);
- return 0;
- }
- /* --stats / -s */
- static int get_freq_stats(unsigned int cpu, unsigned int human)
- {
- unsigned long total_trans = cpufreq_get_transitions(cpu);
- unsigned long long total_time;
- struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
- while (stats) {
- if (human) {
- print_speed(stats->frequency);
- printf(":%.2f%%",
- (100.0 * stats->time_in_state) / total_time);
- } else
- printf("%lu:%llu",
- stats->frequency, stats->time_in_state);
- stats = stats->next;
- if (stats)
- printf(", ");
- }
- cpufreq_put_stats(stats);
- if (total_trans)
- printf(" (%lu)\n", total_trans);
- return 0;
- }
- /* --latency / -y */
- static int get_latency(unsigned int cpu, unsigned int human)
- {
- unsigned long latency = cpufreq_get_transition_latency(cpu);
- if (!latency)
- return -EINVAL;
- if (human) {
- print_duration(latency);
- printf("\n");
- } else
- printf("%lu\n", latency);
- return 0;
- }
- static struct option info_opts[] = {
- { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
- { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
- { .name = "freq", .has_arg = no_argument, .flag = NULL, .val = 'f'},
- { .name = "hwfreq", .has_arg = no_argument, .flag = NULL, .val = 'w'},
- { .name = "hwlimits", .has_arg = no_argument, .flag = NULL, .val = 'l'},
- { .name = "driver", .has_arg = no_argument, .flag = NULL, .val = 'd'},
- { .name = "policy", .has_arg = no_argument, .flag = NULL, .val = 'p'},
- { .name = "governors", .has_arg = no_argument, .flag = NULL, .val = 'g'},
- { .name = "related-cpus", .has_arg = no_argument, .flag = NULL, .val = 'r'},
- { .name = "affected-cpus",.has_arg = no_argument, .flag = NULL, .val = 'a'},
- { .name = "stats", .has_arg = no_argument, .flag = NULL, .val = 's'},
- { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
- { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
- { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
- { },
- };
- int cmd_freq_info(int argc, char **argv)
- {
- extern char *optarg;
- extern int optind, opterr, optopt;
- int ret = 0, cont = 1;
- unsigned int cpu = 0;
- unsigned int human = 0;
- int output_param = 0;
- do {
- ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL);
- switch (ret) {
- case '?':
- output_param = '?';
- cont = 0;
- break;
- case -1:
- cont = 0;
- break;
- case 'b':
- case 'o':
- case 'a':
- case 'r':
- case 'g':
- case 'p':
- case 'd':
- case 'l':
- case 'w':
- case 'f':
- case 'e':
- case 's':
- case 'y':
- if (output_param) {
- output_param = -1;
- cont = 0;
- break;
- }
- output_param = ret;
- break;
- case 'm':
- if (human) {
- output_param = -1;
- cont = 0;
- break;
- }
- human = 1;
- break;
- default:
- fprintf(stderr, "invalid or unknown argument\n");
- return EXIT_FAILURE;
- }
- } while (cont);
- switch (output_param) {
- case 'o':
- if (!bitmask_isallclear(cpus_chosen)) {
- printf(_("The argument passed to this tool can't be "
- "combined with passing a --cpu argument\n"));
- return -EINVAL;
- }
- break;
- case 0:
- output_param = 'e';
- }
- ret = 0;
- /* Default is: show output of CPU 0 only */
- if (bitmask_isallclear(cpus_chosen))
- bitmask_setbit(cpus_chosen, 0);
- switch (output_param) {
- case -1:
- printf(_("You can't specify more than one --cpu parameter and/or\n"
- "more than one output-specific argument\n"));
- return -EINVAL;
- case '?':
- printf(_("invalid or unknown argument\n"));
- return -EINVAL;
- case 'o':
- proc_cpufreq_output();
- return EXIT_SUCCESS;
- }
- for (cpu = bitmask_first(cpus_chosen);
- cpu <= bitmask_last(cpus_chosen); cpu++) {
- if (!bitmask_isbitset(cpus_chosen, cpu))
- continue;
- if (cpufreq_cpu_exists(cpu)) {
- printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu);
- continue;
- }
- printf(_("analyzing CPU %d:\n"), cpu);
- switch (output_param) {
- case 'b':
- get_boost_mode(cpu);
- break;
- case 'e':
- debug_output_one(cpu);
- break;
- case 'a':
- ret = get_affected_cpus(cpu);
- break;
- case 'r':
- ret = get_related_cpus(cpu);
- break;
- case 'g':
- ret = get_available_governors(cpu);
- break;
- case 'p':
- ret = get_policy(cpu);
- break;
- case 'd':
- ret = get_driver(cpu);
- break;
- case 'l':
- ret = get_hardware_limits(cpu);
- break;
- case 'w':
- ret = get_freq_hardware(cpu, human);
- break;
- case 'f':
- ret = get_freq_kernel(cpu, human);
- break;
- case 's':
- ret = get_freq_stats(cpu, human);
- break;
- case 'y':
- ret = get_latency(cpu, human);
- break;
- }
- if (ret)
- return ret;
- }
- return ret;
- }
|