mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-26 14:14:01 +08:00
e091abc7f9
The command "cpupower frequency-info" can be used when using cpupower to
monitor and test processor behaviour to determine if the processor is
behaving as expected. This data can be compared to the output of
/proc/cpuinfo or the output of
/sys/devices/system/cpu/cpuX/cpufreq/scaling_available_frequencies
to determine if the cpu is in an expected state.
When doing this I noticed comparison test failures due to the way the
data is displayed in cpupower. For example,
[root@intel-s3e37-02 cpupower]# cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
2262000 2261000 2128000 1995000
1862000 1729000 1596000 1463000 1330000
1197000 1064000
compared to
[root@intel-s3e37-02 cpupower]# cpupower frequency-info
analyzing CPU 0:
driver: acpi-cpufreq
CPUs which run at the same hardware frequency: 0
CPUs which need to have their frequency coordinated by software: 0
maximum transition latency: 10.0 us.
hardware limits: 1.06 GHz - 2.26 GHz
available frequency steps: 2.26 GHz, 2.26 GHz, 2.13 GHz, 2.00 GHz, 1.86 GHz, 1.73 GHz, 1.60 GHz, 1.46 GHz, 1.33 GHz, 1.20 GHz, 1.06 GHz
available cpufreq governors: conservative, userspace, powersave, ondemand, performance
current policy: frequency should be within 1.06 GHz and 2.26 GHz.
The governor "performance" may decide which speed to use
within this range.
current CPU frequency is 2.26 GHz (asserted by call to hardware).
boost state support:
Supported: yes
Active: yes
shows very different values for the available frequency steps. The cpupower
output rounds off values at 2 decimal points and this causes problems with
test scripts. For example, with the data above,
1.064 is 1.06
1.197 is 1.20
1.596 is 1.60
1.995 is 2.00
2.128 is 2.13
and most confusingly,
2.261 is 2.26
2.262 is 2.26
Truncating these values serves no real purpose other than making the output
pretty. Since the default has been to round off these values I am adding
a -n/--no-rounding option to the cpupower utility that will display the
data without rounding off the still significant digits.
After patch,
analyzing CPU 0:
driver: acpi-cpufreq
CPUs which run at the same hardware frequency: 0
CPUs which need to have their frequency coordinated by software: 0
maximum transition latency: 10.000 us.
hardware limits: 1.064000 GHz - 2.262000 GHz
available frequency steps: 2.262000 GHz, 2.261000 GHz, 2.128000 GHz, 1.995000 GHz, 1.862000 GHz, 1.729000 GHz, 1.596000 GHz, 1.463000 GHz, 1.330000 GHz, 1.197000 GHz, 1.064000 GHz
available cpufreq governors: conservative, userspace, powersave, ondemand, performance
current policy: frequency should be within 1.064000 GHz and 2.262000 GHz.
The governor "performance" may decide which speed to use
within this range.
current CPU frequency is 2.262000 GHz (asserted by call to hardware).
boost state support:
Supported: yes
Active: yes
Acked-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: Prarit Bhargava <prarit@redhat.com>
[rjw: Subject]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
699 lines
16 KiB
C
699 lines
16 KiB
C
/*
|
|
* (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 int no_rounding;
|
|
static void print_speed(unsigned long speed)
|
|
{
|
|
unsigned long tmp;
|
|
|
|
if (no_rounding) {
|
|
if (speed > 1000000)
|
|
printf("%u.%06u GHz", ((unsigned int) speed/1000000),
|
|
((unsigned int) speed%1000000));
|
|
else if (speed > 100000)
|
|
printf("%u MHz", (unsigned int) speed);
|
|
else if (speed > 1000)
|
|
printf("%u.%03u MHz", ((unsigned int) speed/1000),
|
|
(unsigned int) (speed%1000));
|
|
else
|
|
printf("%lu kHz", speed);
|
|
} else {
|
|
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));
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void print_duration(unsigned long duration)
|
|
{
|
|
unsigned long tmp;
|
|
|
|
if (no_rounding) {
|
|
if (duration > 1000000)
|
|
printf("%u.%06u ms", ((unsigned int) duration/1000000),
|
|
((unsigned int) duration%1000000));
|
|
else if (duration > 100000)
|
|
printf("%u us", ((unsigned int) duration/1000));
|
|
else if (duration > 1000)
|
|
printf("%u.%03u us", ((unsigned int) duration/1000),
|
|
((unsigned int) duration%1000));
|
|
else
|
|
printf("%lu ns", duration);
|
|
} else {
|
|
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'},
|
|
{ .name = "no-rounding", .has_arg = no_argument, .flag = NULL, .val = 'n'},
|
|
{ },
|
|
};
|
|
|
|
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, "oefwldpgrasmybn", 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;
|
|
case 'n':
|
|
no_rounding = 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;
|
|
}
|