Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/cpupowerutils
* git://git.kernel.org/pub/scm/linux/kernel/git/brodo/cpupowerutils: cpupower: use man(1) when calling "cpupower help subcommand" cpupower: make NLS truly optional cpupower: fix Makefile typo cpupower: Make monitor command -c/--cpu aware cpupower: Better detect offlined CPUs cpupower: Do not show an empty Idle_Stats monitor if no idle driver is available cpupower: mperf monitor - Use TSC to calculate max frequency if possible cpupower: avoid using symlinks
This commit is contained in:
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
# Set the following to `true' to make a unstripped, unoptimized
|
# Set the following to `true' to make a unstripped, unoptimized
|
||||||
# binary. Leave this set to `false' for production use.
|
# binary. Leave this set to `false' for production use.
|
||||||
DEBUG ?= false
|
DEBUG ?= true
|
||||||
|
|
||||||
# make the build silent. Set this to something else to make it noisy again.
|
# make the build silent. Set this to something else to make it noisy again.
|
||||||
V ?= false
|
V ?= false
|
||||||
@@ -35,7 +35,7 @@ NLS ?= true
|
|||||||
|
|
||||||
# Set the following to 'true' to build/install the
|
# Set the following to 'true' to build/install the
|
||||||
# cpufreq-bench benchmarking tool
|
# cpufreq-bench benchmarking tool
|
||||||
CPUFRQ_BENCH ?= true
|
CPUFREQ_BENCH ?= true
|
||||||
|
|
||||||
# Prefix to the directories we're installing to
|
# Prefix to the directories we're installing to
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
@@ -137,9 +137,10 @@ CFLAGS += -pipe
|
|||||||
ifeq ($(strip $(NLS)),true)
|
ifeq ($(strip $(NLS)),true)
|
||||||
INSTALL_NLS += install-gmo
|
INSTALL_NLS += install-gmo
|
||||||
COMPILE_NLS += create-gmo
|
COMPILE_NLS += create-gmo
|
||||||
|
CFLAGS += -DNLS
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(CPUFRQ_BENCH)),true)
|
ifeq ($(strip $(CPUFREQ_BENCH)),true)
|
||||||
INSTALL_BENCH += install-bench
|
INSTALL_BENCH += install-bench
|
||||||
COMPILE_BENCH += compile-bench
|
COMPILE_BENCH += compile-bench
|
||||||
endif
|
endif
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
default: all
|
default: all
|
||||||
|
|
||||||
centrino-decode: centrino-decode.c
|
centrino-decode: ../i386/centrino-decode.c
|
||||||
$(CC) $(CFLAGS) -o centrino-decode centrino-decode.c
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
powernow-k8-decode: powernow-k8-decode.c
|
powernow-k8-decode: ../i386/powernow-k8-decode.c
|
||||||
$(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
all: centrino-decode powernow-k8-decode
|
all: centrino-decode powernow-k8-decode
|
||||||
|
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
../i386/centrino-decode.c
|
|
@@ -1 +0,0 @@
|
|||||||
../i386/powernow-k8-decode.c
|
|
@@ -1,10 +1,10 @@
|
|||||||
.TH "cpufreq-info" "1" "0.1" "Mattia Dongili" ""
|
.TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" ""
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
.LP
|
.LP
|
||||||
cpufreq\-info \- Utility to retrieve cpufreq kernel information
|
cpupower frequency\-info \- Utility to retrieve cpufreq kernel information
|
||||||
.SH "SYNTAX"
|
.SH "SYNTAX"
|
||||||
.LP
|
.LP
|
||||||
cpufreq\-info [\fIoptions\fP]
|
cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP]
|
||||||
.SH "DESCRIPTION"
|
.SH "DESCRIPTION"
|
||||||
.LP
|
.LP
|
||||||
A small tool which prints out cpufreq information helpful to developers and interested users.
|
A small tool which prints out cpufreq information helpful to developers and interested users.
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
.TH "cpufreq-set" "1" "0.1" "Mattia Dongili" ""
|
.TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" ""
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
.LP
|
.LP
|
||||||
cpufreq\-set \- A small tool which allows to modify cpufreq settings.
|
cpupower frequency\-set \- A small tool which allows to modify cpufreq settings.
|
||||||
.SH "SYNTAX"
|
.SH "SYNTAX"
|
||||||
.LP
|
.LP
|
||||||
cpufreq\-set [\fIoptions\fP]
|
cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP]
|
||||||
.SH "DESCRIPTION"
|
.SH "DESCRIPTION"
|
||||||
.LP
|
.LP
|
||||||
cpufreq\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.
|
cpupower frequency\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.
|
||||||
.SH "OPTIONS"
|
.SH "OPTIONS"
|
||||||
.LP
|
.LP
|
||||||
.TP
|
.TP
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
cpupower \- Shows and sets processor power related values
|
cpupower \- Shows and sets processor power related values
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.ft B
|
.ft B
|
||||||
.B cpupower [ \-c cpulist ] subcommand [ARGS]
|
.B cpupower [ \-c cpulist ] <command> [ARGS]
|
||||||
|
|
||||||
.B cpupower \-v|\-\-version
|
.B cpupower \-v|\-\-version
|
||||||
|
|
||||||
@@ -13,24 +13,24 @@ cpupower \- Shows and sets processor power related values
|
|||||||
\fBcpupower \fP is a collection of tools to examine and tune power saving
|
\fBcpupower \fP is a collection of tools to examine and tune power saving
|
||||||
related features of your processor.
|
related features of your processor.
|
||||||
|
|
||||||
The manpages of the subcommands (cpupower\-<subcommand>(1)) provide detailed
|
The manpages of the commands (cpupower\-<command>(1)) provide detailed
|
||||||
descriptions of supported features. Run \fBcpupower help\fP to get an overview
|
descriptions of supported features. Run \fBcpupower help\fP to get an overview
|
||||||
of supported subcommands.
|
of supported commands.
|
||||||
|
|
||||||
.SH Options
|
.SH Options
|
||||||
.PP
|
.PP
|
||||||
\-\-help, \-h
|
\-\-help, \-h
|
||||||
.RS 4
|
.RS 4
|
||||||
Shows supported subcommands and general usage.
|
Shows supported commands and general usage.
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\-\-cpu cpulist, \-c cpulist
|
\-\-cpu cpulist, \-c cpulist
|
||||||
.RS 4
|
.RS 4
|
||||||
Only show or set values for specific cores.
|
Only show or set values for specific cores.
|
||||||
This option is not supported by all subcommands, details can be found in the
|
This option is not supported by all commands, details can be found in the
|
||||||
manpages of the subcommands.
|
manpages of the commands.
|
||||||
|
|
||||||
Some subcommands access all cores (typically the *\-set commands), some only
|
Some commands access all cores (typically the *\-set commands), some only
|
||||||
the first core (typically the *\-info commands) by default.
|
the first core (typically the *\-info commands) by default.
|
||||||
|
|
||||||
The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via
|
The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via
|
||||||
|
@@ -8,11 +8,4 @@ extern int cmd_freq_info(int argc, const char **argv);
|
|||||||
extern int cmd_idle_info(int argc, const char **argv);
|
extern int cmd_idle_info(int argc, const char **argv);
|
||||||
extern int cmd_monitor(int argc, const char **argv);
|
extern int cmd_monitor(int argc, const char **argv);
|
||||||
|
|
||||||
extern void set_help(void);
|
|
||||||
extern void info_help(void);
|
|
||||||
extern void freq_set_help(void);
|
|
||||||
extern void freq_info_help(void);
|
|
||||||
extern void idle_info_help(void);
|
|
||||||
extern void monitor_help(void);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -510,37 +510,6 @@ static int get_latency(unsigned int cpu, unsigned int human)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freq_info_help(void)
|
|
||||||
{
|
|
||||||
printf(_("Usage: cpupower freqinfo [options]\n"));
|
|
||||||
printf(_("Options:\n"));
|
|
||||||
printf(_(" -e, --debug Prints out debug information [default]\n"));
|
|
||||||
printf(_(" -f, --freq Get frequency the CPU currently runs at, according\n"
|
|
||||||
" to the cpufreq core *\n"));
|
|
||||||
printf(_(" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n"
|
|
||||||
" it from hardware (only available to root) *\n"));
|
|
||||||
printf(_(" -l, --hwlimits Determine the minimum and maximum CPU frequency allowed *\n"));
|
|
||||||
printf(_(" -d, --driver Determines the used cpufreq kernel driver *\n"));
|
|
||||||
printf(_(" -p, --policy Gets the currently used cpufreq policy *\n"));
|
|
||||||
printf(_(" -g, --governors Determines available cpufreq governors *\n"));
|
|
||||||
printf(_(" -r, --related-cpus Determines which CPUs run at the same hardware frequency *\n"));
|
|
||||||
printf(_(" -a, --affected-cpus Determines which CPUs need to have their frequency\n"
|
|
||||||
" coordinated by software *\n"));
|
|
||||||
printf(_(" -s, --stats Shows cpufreq statistics if available\n"));
|
|
||||||
printf(_(" -y, --latency Determines the maximum latency on CPU frequency changes *\n"));
|
|
||||||
printf(_(" -b, --boost Checks for turbo or boost modes *\n"));
|
|
||||||
printf(_(" -o, --proc Prints out information like provided by the /proc/cpufreq\n"
|
|
||||||
" interface in 2.4. and early 2.6. kernels\n"));
|
|
||||||
printf(_(" -m, --human human-readable output for the -f, -w, -s and -y parameters\n"));
|
|
||||||
printf(_(" -h, --help Prints out this screen\n"));
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
printf(_("If no argument is given, full output about\n"
|
|
||||||
"cpufreq is printed which is useful e.g. for reporting bugs.\n\n"));
|
|
||||||
printf(_("By default info of CPU 0 is shown which can be overridden\n"
|
|
||||||
"with the cpupower --cpu main command option.\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct option info_opts[] = {
|
static struct option info_opts[] = {
|
||||||
{ .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
|
{ .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
|
||||||
{ .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
|
{ .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
|
||||||
@@ -556,7 +525,6 @@ static struct option info_opts[] = {
|
|||||||
{ .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
|
{ .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
|
||||||
{ .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
|
{ .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
|
||||||
{ .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
|
{ .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
|
||||||
{ .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
|
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -570,16 +538,12 @@ int cmd_freq_info(int argc, char **argv)
|
|||||||
int output_param = 0;
|
int output_param = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL);
|
ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case '?':
|
case '?':
|
||||||
output_param = '?';
|
output_param = '?';
|
||||||
cont = 0;
|
cont = 0;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
|
||||||
output_param = 'h';
|
|
||||||
cont = 0;
|
|
||||||
break;
|
|
||||||
case -1:
|
case -1:
|
||||||
cont = 0;
|
cont = 0;
|
||||||
break;
|
break;
|
||||||
@@ -642,11 +606,7 @@ int cmd_freq_info(int argc, char **argv)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case '?':
|
case '?':
|
||||||
printf(_("invalid or unknown argument\n"));
|
printf(_("invalid or unknown argument\n"));
|
||||||
freq_info_help();
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case 'h':
|
|
||||||
freq_info_help();
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
case 'o':
|
case 'o':
|
||||||
proc_cpufreq_output();
|
proc_cpufreq_output();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@@ -20,34 +20,11 @@
|
|||||||
|
|
||||||
#define NORM_FREQ_LEN 32
|
#define NORM_FREQ_LEN 32
|
||||||
|
|
||||||
void freq_set_help(void)
|
|
||||||
{
|
|
||||||
printf(_("Usage: cpupower frequency-set [options]\n"));
|
|
||||||
printf(_("Options:\n"));
|
|
||||||
printf(_(" -d FREQ, --min FREQ new minimum CPU frequency the governor may select\n"));
|
|
||||||
printf(_(" -u FREQ, --max FREQ new maximum CPU frequency the governor may select\n"));
|
|
||||||
printf(_(" -g GOV, --governor GOV new cpufreq governor\n"));
|
|
||||||
printf(_(" -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n"
|
|
||||||
" governor to be available and loaded\n"));
|
|
||||||
printf(_(" -r, --related Switches all hardware-related CPUs\n"));
|
|
||||||
printf(_(" -h, --help Prints out this screen\n"));
|
|
||||||
printf("\n");
|
|
||||||
printf(_("Notes:\n"
|
|
||||||
"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"));
|
|
||||||
printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n"
|
|
||||||
" except the -c CPU, --cpu CPU parameter\n"
|
|
||||||
"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
|
|
||||||
" by postfixing the value with the wanted unit name, without any space\n"
|
|
||||||
" (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct option set_opts[] = {
|
static struct option set_opts[] = {
|
||||||
{ .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'},
|
{ .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'},
|
||||||
{ .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'},
|
{ .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'},
|
||||||
{ .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'},
|
{ .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'},
|
||||||
{ .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'},
|
{ .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'},
|
||||||
{ .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
|
|
||||||
{ .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'},
|
{ .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'},
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
@@ -80,7 +57,6 @@ const struct freq_units def_units[] = {
|
|||||||
static void print_unknown_arg(void)
|
static void print_unknown_arg(void)
|
||||||
{
|
{
|
||||||
printf(_("invalid or unknown argument\n"));
|
printf(_("invalid or unknown argument\n"));
|
||||||
freq_set_help();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long string_to_frequency(const char *str)
|
static unsigned long string_to_frequency(const char *str)
|
||||||
@@ -231,14 +207,11 @@ int cmd_freq_set(int argc, char **argv)
|
|||||||
|
|
||||||
/* parameter parsing */
|
/* parameter parsing */
|
||||||
do {
|
do {
|
||||||
ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL);
|
ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case '?':
|
case '?':
|
||||||
print_unknown_arg();
|
print_unknown_arg();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case 'h':
|
|
||||||
freq_set_help();
|
|
||||||
return 0;
|
|
||||||
case -1:
|
case -1:
|
||||||
cont = 0;
|
cont = 0;
|
||||||
break;
|
break;
|
||||||
|
@@ -139,30 +139,14 @@ static void proc_cpuidle_cpu_output(unsigned int cpu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --freq / -f */
|
|
||||||
|
|
||||||
void idle_info_help(void)
|
|
||||||
{
|
|
||||||
printf(_ ("Usage: cpupower idleinfo [options]\n"));
|
|
||||||
printf(_ ("Options:\n"));
|
|
||||||
printf(_ (" -s, --silent Only show general C-state information\n"));
|
|
||||||
printf(_ (" -o, --proc Prints out information like provided by the /proc/acpi/processor/*/power\n"
|
|
||||||
" interface in older kernels\n"));
|
|
||||||
printf(_ (" -h, --help Prints out this screen\n"));
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct option info_opts[] = {
|
static struct option info_opts[] = {
|
||||||
{ .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'},
|
{ .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'},
|
||||||
{ .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
|
{ .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
|
||||||
{ .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
|
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void cpuidle_exit(int fail)
|
static inline void cpuidle_exit(int fail)
|
||||||
{
|
{
|
||||||
idle_info_help();
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +158,7 @@ int cmd_idle_info(int argc, char **argv)
|
|||||||
unsigned int cpu = 0;
|
unsigned int cpu = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = getopt_long(argc, argv, "hos", info_opts, NULL);
|
ret = getopt_long(argc, argv, "os", info_opts, NULL);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
break;
|
break;
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
@@ -182,10 +166,6 @@ int cmd_idle_info(int argc, char **argv)
|
|||||||
output_param = '?';
|
output_param = '?';
|
||||||
cont = 0;
|
cont = 0;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
|
||||||
output_param = 'h';
|
|
||||||
cont = 0;
|
|
||||||
break;
|
|
||||||
case 's':
|
case 's':
|
||||||
verbose = 0;
|
verbose = 0;
|
||||||
break;
|
break;
|
||||||
@@ -211,8 +191,6 @@ int cmd_idle_info(int argc, char **argv)
|
|||||||
case '?':
|
case '?':
|
||||||
printf(_("invalid or unknown argument\n"));
|
printf(_("invalid or unknown argument\n"));
|
||||||
cpuidle_exit(EXIT_FAILURE);
|
cpuidle_exit(EXIT_FAILURE);
|
||||||
case 'h':
|
|
||||||
cpuidle_exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default is: show output of CPU 0 only */
|
/* Default is: show output of CPU 0 only */
|
||||||
|
@@ -16,31 +16,16 @@
|
|||||||
#include "helpers/helpers.h"
|
#include "helpers/helpers.h"
|
||||||
#include "helpers/sysfs.h"
|
#include "helpers/sysfs.h"
|
||||||
|
|
||||||
void info_help(void)
|
|
||||||
{
|
|
||||||
printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"));
|
|
||||||
printf(_("Options:\n"));
|
|
||||||
printf(_(" -b, --perf-bias Gets CPU's power vs performance policy on some\n"
|
|
||||||
" Intel models [0-15], see manpage for details\n"));
|
|
||||||
printf(_(" -m, --sched-mc Gets the kernel's multi core scheduler policy.\n"));
|
|
||||||
printf(_(" -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n"));
|
|
||||||
printf(_(" -h, --help Prints out this screen\n"));
|
|
||||||
printf(_("\nPassing no option will show all info, by default only on core 0\n"));
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct option set_opts[] = {
|
static struct option set_opts[] = {
|
||||||
{ .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
|
{ .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
|
||||||
{ .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
|
{ .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
|
||||||
{ .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
|
{ .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
|
||||||
{ .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
|
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void print_wrong_arg_exit(void)
|
static void print_wrong_arg_exit(void)
|
||||||
{
|
{
|
||||||
printf(_("invalid or unknown argument\n"));
|
printf(_("invalid or unknown argument\n"));
|
||||||
info_help();
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,11 +49,8 @@ int cmd_info(int argc, char **argv)
|
|||||||
textdomain(PACKAGE);
|
textdomain(PACKAGE);
|
||||||
|
|
||||||
/* parameter parsing */
|
/* parameter parsing */
|
||||||
while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) {
|
while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) {
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case 'h':
|
|
||||||
info_help();
|
|
||||||
return 0;
|
|
||||||
case 'b':
|
case 'b':
|
||||||
if (params.perf_bias)
|
if (params.perf_bias)
|
||||||
print_wrong_arg_exit();
|
print_wrong_arg_exit();
|
||||||
|
@@ -17,30 +17,16 @@
|
|||||||
#include "helpers/sysfs.h"
|
#include "helpers/sysfs.h"
|
||||||
#include "helpers/bitmask.h"
|
#include "helpers/bitmask.h"
|
||||||
|
|
||||||
void set_help(void)
|
|
||||||
{
|
|
||||||
printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"));
|
|
||||||
printf(_("Options:\n"));
|
|
||||||
printf(_(" -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n"
|
|
||||||
" Intel models [0-15], see manpage for details\n"));
|
|
||||||
printf(_(" -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n"));
|
|
||||||
printf(_(" -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler policy.\n"));
|
|
||||||
printf(_(" -h, --help Prints out this screen\n"));
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct option set_opts[] = {
|
static struct option set_opts[] = {
|
||||||
{ .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
|
{ .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
|
||||||
{ .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
|
{ .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
|
||||||
{ .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
|
{ .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
|
||||||
{ .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
|
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void print_wrong_arg_exit(void)
|
static void print_wrong_arg_exit(void)
|
||||||
{
|
{
|
||||||
printf(_("invalid or unknown argument\n"));
|
printf(_("invalid or unknown argument\n"));
|
||||||
set_help();
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,12 +52,9 @@ int cmd_set(int argc, char **argv)
|
|||||||
|
|
||||||
params.params = 0;
|
params.params = 0;
|
||||||
/* parameter parsing */
|
/* parameter parsing */
|
||||||
while ((ret = getopt_long(argc, argv, "m:s:b:h",
|
while ((ret = getopt_long(argc, argv, "m:s:b:",
|
||||||
set_opts, NULL)) != -1) {
|
set_opts, NULL)) != -1) {
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case 'h':
|
|
||||||
set_help();
|
|
||||||
return 0;
|
|
||||||
case 'b':
|
case 'b':
|
||||||
if (params.perf_bias)
|
if (params.perf_bias)
|
||||||
print_wrong_arg_exit();
|
print_wrong_arg_exit();
|
||||||
@@ -110,10 +93,8 @@ int cmd_set(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!params.params) {
|
if (!params.params)
|
||||||
set_help();
|
print_wrong_arg_exit();
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.sched_mc) {
|
if (params.sched_mc) {
|
||||||
ret = sysfs_set_sched("mc", sched_mc);
|
ret = sysfs_set_sched("mc", sched_mc);
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "helpers/helpers.h"
|
#include "helpers/helpers.h"
|
||||||
@@ -19,13 +20,12 @@
|
|||||||
struct cmd_struct {
|
struct cmd_struct {
|
||||||
const char *cmd;
|
const char *cmd;
|
||||||
int (*main)(int, const char **);
|
int (*main)(int, const char **);
|
||||||
void (*usage)(void);
|
|
||||||
int needs_root;
|
int needs_root;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||||
|
|
||||||
int cmd_help(int argc, const char **argv);
|
static int cmd_help(int argc, const char **argv);
|
||||||
|
|
||||||
/* Global cpu_info object available for all binaries
|
/* Global cpu_info object available for all binaries
|
||||||
* Info only retrieved from CPU 0
|
* Info only retrieved from CPU 0
|
||||||
@@ -44,55 +44,66 @@ int be_verbose;
|
|||||||
static void print_help(void);
|
static void print_help(void);
|
||||||
|
|
||||||
static struct cmd_struct commands[] = {
|
static struct cmd_struct commands[] = {
|
||||||
{ "frequency-info", cmd_freq_info, freq_info_help, 0 },
|
{ "frequency-info", cmd_freq_info, 0 },
|
||||||
{ "frequency-set", cmd_freq_set, freq_set_help, 1 },
|
{ "frequency-set", cmd_freq_set, 1 },
|
||||||
{ "idle-info", cmd_idle_info, idle_info_help, 0 },
|
{ "idle-info", cmd_idle_info, 0 },
|
||||||
{ "set", cmd_set, set_help, 1 },
|
{ "set", cmd_set, 1 },
|
||||||
{ "info", cmd_info, info_help, 0 },
|
{ "info", cmd_info, 0 },
|
||||||
{ "monitor", cmd_monitor, monitor_help, 0 },
|
{ "monitor", cmd_monitor, 0 },
|
||||||
{ "help", cmd_help, print_help, 0 },
|
{ "help", cmd_help, 0 },
|
||||||
/* { "bench", cmd_bench, NULL, 1 }, */
|
/* { "bench", cmd_bench, 1 }, */
|
||||||
};
|
};
|
||||||
|
|
||||||
int cmd_help(int argc, const char **argv)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
|
||||||
struct cmd_struct *p = commands + i;
|
|
||||||
if (strcmp(p->cmd, argv[1]))
|
|
||||||
continue;
|
|
||||||
if (p->usage) {
|
|
||||||
p->usage();
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print_help();
|
|
||||||
if (argc == 1)
|
|
||||||
return EXIT_SUCCESS; /* cpupower help */
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_help(void)
|
static void print_help(void)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n"));
|
printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n"));
|
||||||
printf(_(" -d, --debug May increase output (stderr) on some subcommands\n"));
|
|
||||||
#else
|
#else
|
||||||
printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n"));
|
printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n"));
|
||||||
#endif
|
#endif
|
||||||
printf(_("cpupower --version\n"));
|
printf(_("Supported commands are:\n"));
|
||||||
printf(_("Supported subcommands are:\n"));
|
|
||||||
for (i = 0; i < ARRAY_SIZE(commands); i++)
|
for (i = 0; i < ARRAY_SIZE(commands); i++)
|
||||||
printf("\t%s\n", commands[i].cmd);
|
printf("\t%s\n", commands[i].cmd);
|
||||||
printf(_("\nSome subcommands can make use of the -c cpulist option.\n"));
|
printf(_("\nNot all commands can make use of the -c cpulist option.\n"));
|
||||||
printf(_("Look at the general cpupower manpage how to use it\n"));
|
printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n"));
|
||||||
printf(_("and read up the subcommand's manpage whether it is supported.\n"));
|
}
|
||||||
printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n"));
|
|
||||||
|
static int print_man_page(const char *subpage)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
char *page;
|
||||||
|
|
||||||
|
len = 10; /* enough for "cpupower-" */
|
||||||
|
if (subpage != NULL)
|
||||||
|
len += strlen(subpage);
|
||||||
|
|
||||||
|
page = malloc(len);
|
||||||
|
if (!page)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
sprintf(page, "cpupower");
|
||||||
|
if ((subpage != NULL) && strcmp(subpage, "help")) {
|
||||||
|
strcat(page, "-");
|
||||||
|
strcat(page, subpage);
|
||||||
|
}
|
||||||
|
|
||||||
|
execlp("man", "man", page, NULL);
|
||||||
|
|
||||||
|
/* should not be reached */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_help(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
if (argc > 1) {
|
||||||
|
print_man_page(argv[1]); /* exits within execlp() */
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_help();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_version(void)
|
static void print_version(void)
|
||||||
|
@@ -16,11 +16,20 @@
|
|||||||
#include "helpers/bitmask.h"
|
#include "helpers/bitmask.h"
|
||||||
|
|
||||||
/* Internationalization ****************************/
|
/* Internationalization ****************************/
|
||||||
|
#ifdef NLS
|
||||||
|
|
||||||
#define _(String) gettext(String)
|
#define _(String) gettext(String)
|
||||||
#ifndef gettext_noop
|
#ifndef gettext_noop
|
||||||
#define gettext_noop(String) String
|
#define gettext_noop(String) String
|
||||||
#endif
|
#endif
|
||||||
#define N_(String) gettext_noop(String)
|
#define N_(String) gettext_noop(String)
|
||||||
|
|
||||||
|
#else /* !NLS */
|
||||||
|
|
||||||
|
#define _(String) String
|
||||||
|
#define N_(String) String
|
||||||
|
|
||||||
|
#endif
|
||||||
/* Internationalization ****************************/
|
/* Internationalization ****************************/
|
||||||
|
|
||||||
extern int run_as_root;
|
extern int run_as_root;
|
||||||
@@ -96,6 +105,9 @@ struct cpupower_topology {
|
|||||||
int pkg;
|
int pkg;
|
||||||
int core;
|
int core;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
unsigned int is_online:1;
|
||||||
} *core_info;
|
} *core_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -56,6 +56,56 @@ static unsigned int sysfs_write_file(const char *path,
|
|||||||
return (unsigned int) numwrite;
|
return (unsigned int) numwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detect whether a CPU is online
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 1 -> if CPU is online
|
||||||
|
* 0 -> if CPU is offline
|
||||||
|
* negative errno values in error case
|
||||||
|
*/
|
||||||
|
int sysfs_is_cpu_online(unsigned int cpu)
|
||||||
|
{
|
||||||
|
char path[SYSFS_PATH_MAX];
|
||||||
|
int fd;
|
||||||
|
ssize_t numread;
|
||||||
|
unsigned long long value;
|
||||||
|
char linebuf[MAX_LINE_LEN];
|
||||||
|
char *endp;
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
|
||||||
|
|
||||||
|
if (stat(path, &statbuf) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kernel without CONFIG_HOTPLUG_CPU
|
||||||
|
* -> cpuX directory exists, but not cpuX/online file
|
||||||
|
*/
|
||||||
|
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
|
||||||
|
if (stat(path, &statbuf) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
numread = read(fd, linebuf, MAX_LINE_LEN - 1);
|
||||||
|
if (numread < 1) {
|
||||||
|
close(fd);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
linebuf[numread] = '\0';
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
value = strtoull(linebuf, &endp, 0);
|
||||||
|
if (value > 1 || value < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
|
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
|
extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
|
||||||
|
|
||||||
|
extern int sysfs_is_cpu_online(unsigned int cpu);
|
||||||
|
|
||||||
extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
|
extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
|
||||||
unsigned int idlestate);
|
unsigned int idlestate);
|
||||||
extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
|
extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
|
||||||
|
@@ -41,6 +41,8 @@ struct cpuid_core_info {
|
|||||||
unsigned int pkg;
|
unsigned int pkg;
|
||||||
unsigned int thread;
|
unsigned int thread;
|
||||||
unsigned int cpu;
|
unsigned int cpu;
|
||||||
|
/* flags */
|
||||||
|
unsigned int is_online:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __compare(const void *t1, const void *t2)
|
static int __compare(const void *t1, const void *t2)
|
||||||
@@ -78,6 +80,8 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
cpu_top->pkgs = cpu_top->cores = 0;
|
cpu_top->pkgs = cpu_top->cores = 0;
|
||||||
for (cpu = 0; cpu < cpus; cpu++) {
|
for (cpu = 0; cpu < cpus; cpu++) {
|
||||||
|
cpu_top->core_info[cpu].cpu = cpu;
|
||||||
|
cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
|
||||||
cpu_top->core_info[cpu].pkg =
|
cpu_top->core_info[cpu].pkg =
|
||||||
sysfs_topology_read_file(cpu, "physical_package_id");
|
sysfs_topology_read_file(cpu, "physical_package_id");
|
||||||
if ((int)cpu_top->core_info[cpu].pkg != -1 &&
|
if ((int)cpu_top->core_info[cpu].pkg != -1 &&
|
||||||
@@ -85,7 +89,6 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
|
|||||||
cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
|
cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
|
||||||
cpu_top->core_info[cpu].core =
|
cpu_top->core_info[cpu].core =
|
||||||
sysfs_topology_read_file(cpu, "core_id");
|
sysfs_topology_read_file(cpu, "core_id");
|
||||||
cpu_top->core_info[cpu].cpu = cpu;
|
|
||||||
}
|
}
|
||||||
cpu_top->pkgs++;
|
cpu_top->pkgs++;
|
||||||
|
|
||||||
|
@@ -134,7 +134,7 @@ static struct cpuidle_monitor *cpuidle_register(void)
|
|||||||
/* Assume idle state count is the same for all CPUs */
|
/* Assume idle state count is the same for all CPUs */
|
||||||
cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
|
cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
|
||||||
|
|
||||||
if (cpuidle_sysfs_monitor.hw_states_num == 0)
|
if (cpuidle_sysfs_monitor.hw_states_num <= 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
|
for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
|
||||||
|
@@ -43,6 +43,12 @@ static struct cpupower_topology cpu_top;
|
|||||||
/* ToDo: Document this in the manpage */
|
/* ToDo: Document this in the manpage */
|
||||||
static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
|
static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
|
||||||
|
|
||||||
|
static void print_wrong_arg_exit(void)
|
||||||
|
{
|
||||||
|
printf(_("invalid or unknown argument\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
long long timespec_diff_us(struct timespec start, struct timespec end)
|
long long timespec_diff_us(struct timespec start, struct timespec end)
|
||||||
{
|
{
|
||||||
struct timespec temp;
|
struct timespec temp;
|
||||||
@@ -56,21 +62,6 @@ long long timespec_diff_us(struct timespec start, struct timespec end)
|
|||||||
return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);
|
return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void monitor_help(void)
|
|
||||||
{
|
|
||||||
printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n"));
|
|
||||||
printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n"));
|
|
||||||
printf(_("cpupower monitor: -l\n"));
|
|
||||||
printf(_("\t command: pass an arbitrary command to measure specific workload\n"));
|
|
||||||
printf(_("\t -i: time intervall to measure for in seconds (default 1)\n"));
|
|
||||||
printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n"));
|
|
||||||
printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n"));
|
|
||||||
printf(_("\t -h: print this help\n"));
|
|
||||||
printf("\n");
|
|
||||||
printf(_("only one of: -l, -m are allowed\nIf none of them is passed,"));
|
|
||||||
printf(_(" all supported monitors are shown\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_n_spaces(int n)
|
void print_n_spaces(int n)
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
@@ -149,6 +140,10 @@ void print_results(int topology_depth, int cpu)
|
|||||||
unsigned long long result;
|
unsigned long long result;
|
||||||
cstate_t s;
|
cstate_t s;
|
||||||
|
|
||||||
|
/* Be careful CPUs may got resorted for pkg value do not just use cpu */
|
||||||
|
if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu))
|
||||||
|
return;
|
||||||
|
|
||||||
if (topology_depth > 2)
|
if (topology_depth > 2)
|
||||||
printf("%4d|", cpu_top.core_info[cpu].pkg);
|
printf("%4d|", cpu_top.core_info[cpu].pkg);
|
||||||
if (topology_depth > 1)
|
if (topology_depth > 1)
|
||||||
@@ -190,9 +185,13 @@ void print_results(int topology_depth, int cpu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* cpu offline */
|
/*
|
||||||
if (cpu_top.core_info[cpu].pkg == -1 ||
|
* The monitor could still provide useful data, for example
|
||||||
cpu_top.core_info[cpu].core == -1) {
|
* AMD HW counters partly sit in PCI config space.
|
||||||
|
* It's up to the monitor plug-in to check .is_online, this one
|
||||||
|
* is just for additional info.
|
||||||
|
*/
|
||||||
|
if (!cpu_top.core_info[cpu].is_online) {
|
||||||
printf(_(" *is offline\n"));
|
printf(_(" *is offline\n"));
|
||||||
return;
|
return;
|
||||||
} else
|
} else
|
||||||
@@ -238,7 +237,6 @@ static void parse_monitor_param(char *param)
|
|||||||
if (hits == 0) {
|
if (hits == 0) {
|
||||||
printf(_("No matching monitor found in %s, "
|
printf(_("No matching monitor found in %s, "
|
||||||
"try -l option\n"), param);
|
"try -l option\n"), param);
|
||||||
monitor_help();
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
/* Override detected/registerd monitors array with requested one */
|
/* Override detected/registerd monitors array with requested one */
|
||||||
@@ -335,37 +333,27 @@ static void cmdline(int argc, char *argv[])
|
|||||||
int opt;
|
int opt;
|
||||||
progname = basename(argv[0]);
|
progname = basename(argv[0]);
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "+hli:m:")) != -1) {
|
while ((opt = getopt(argc, argv, "+li:m:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
|
||||||
monitor_help();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
case 'l':
|
case 'l':
|
||||||
if (mode) {
|
if (mode)
|
||||||
monitor_help();
|
print_wrong_arg_exit();
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
mode = list;
|
mode = list;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
/* only allow -i with -m or no option */
|
/* only allow -i with -m or no option */
|
||||||
if (mode && mode != show) {
|
if (mode && mode != show)
|
||||||
monitor_help();
|
print_wrong_arg_exit();
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
interval = atoi(optarg);
|
interval = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
if (mode) {
|
if (mode)
|
||||||
monitor_help();
|
print_wrong_arg_exit();
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
mode = show;
|
mode = show;
|
||||||
show_monitors_param = optarg;
|
show_monitors_param = optarg;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
monitor_help();
|
print_wrong_arg_exit();
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mode)
|
if (!mode)
|
||||||
@@ -385,6 +373,10 @@ int cmd_monitor(int argc, char **argv)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Default is: monitor all CPUs */
|
||||||
|
if (bitmask_isallclear(cpus_chosen))
|
||||||
|
bitmask_setall(cpus_chosen);
|
||||||
|
|
||||||
dprint("System has up to %d CPU cores\n", cpu_count);
|
dprint("System has up to %d CPU cores\n", cpu_count);
|
||||||
|
|
||||||
for (num = 0; all_monitors[num]; num++) {
|
for (num = 0; all_monitors[num]; num++) {
|
||||||
|
@@ -22,12 +22,15 @@
|
|||||||
|
|
||||||
#define MSR_TSC 0x10
|
#define MSR_TSC 0x10
|
||||||
|
|
||||||
|
#define MSR_AMD_HWCR 0xc0010015
|
||||||
|
|
||||||
enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };
|
enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };
|
||||||
|
|
||||||
static int mperf_get_count_percent(unsigned int self_id, double *percent,
|
static int mperf_get_count_percent(unsigned int self_id, double *percent,
|
||||||
unsigned int cpu);
|
unsigned int cpu);
|
||||||
static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
|
static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
|
||||||
unsigned int cpu);
|
unsigned int cpu);
|
||||||
|
static struct timespec time_start, time_end;
|
||||||
|
|
||||||
static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
|
static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
|
||||||
{
|
{
|
||||||
@@ -54,19 +57,33 @@ static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF };
|
||||||
|
static int max_freq_mode;
|
||||||
|
/*
|
||||||
|
* The max frequency mperf is ticking at (in C0), either retrieved via:
|
||||||
|
* 1) calculated after measurements if we know TSC ticks at mperf/P0 frequency
|
||||||
|
* 2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time
|
||||||
|
* 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen)
|
||||||
|
*/
|
||||||
|
static unsigned long max_frequency;
|
||||||
|
|
||||||
static unsigned long long tsc_at_measure_start;
|
static unsigned long long tsc_at_measure_start;
|
||||||
static unsigned long long tsc_at_measure_end;
|
static unsigned long long tsc_at_measure_end;
|
||||||
static unsigned long max_frequency;
|
|
||||||
static unsigned long long *mperf_previous_count;
|
static unsigned long long *mperf_previous_count;
|
||||||
static unsigned long long *aperf_previous_count;
|
static unsigned long long *aperf_previous_count;
|
||||||
static unsigned long long *mperf_current_count;
|
static unsigned long long *mperf_current_count;
|
||||||
static unsigned long long *aperf_current_count;
|
static unsigned long long *aperf_current_count;
|
||||||
|
|
||||||
/* valid flag for all CPUs. If a MSR read failed it will be zero */
|
/* valid flag for all CPUs. If a MSR read failed it will be zero */
|
||||||
static int *is_valid;
|
static int *is_valid;
|
||||||
|
|
||||||
static int mperf_get_tsc(unsigned long long *tsc)
|
static int mperf_get_tsc(unsigned long long *tsc)
|
||||||
{
|
{
|
||||||
return read_msr(0, MSR_TSC, tsc);
|
int ret;
|
||||||
|
ret = read_msr(0, MSR_TSC, tsc);
|
||||||
|
if (ret)
|
||||||
|
dprint("Reading TSC MSR failed, returning %llu\n", *tsc);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mperf_init_stats(unsigned int cpu)
|
static int mperf_init_stats(unsigned int cpu)
|
||||||
@@ -97,36 +114,11 @@ static int mperf_measure_stats(unsigned int cpu)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* get_average_perf()
|
|
||||||
*
|
|
||||||
* Returns the average performance (also considers boosted frequencies)
|
|
||||||
*
|
|
||||||
* Input:
|
|
||||||
* aperf_diff: Difference of the aperf register over a time period
|
|
||||||
* mperf_diff: Difference of the mperf register over the same time period
|
|
||||||
* max_freq: Maximum frequency (P0)
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Average performance over the time period
|
|
||||||
*/
|
|
||||||
static unsigned long get_average_perf(unsigned long long aperf_diff,
|
|
||||||
unsigned long long mperf_diff)
|
|
||||||
{
|
|
||||||
unsigned int perf_percent = 0;
|
|
||||||
if (((unsigned long)(-1) / 100) < aperf_diff) {
|
|
||||||
int shift_count = 7;
|
|
||||||
aperf_diff >>= shift_count;
|
|
||||||
mperf_diff >>= shift_count;
|
|
||||||
}
|
|
||||||
perf_percent = (aperf_diff * 100) / mperf_diff;
|
|
||||||
return (max_frequency * perf_percent) / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mperf_get_count_percent(unsigned int id, double *percent,
|
static int mperf_get_count_percent(unsigned int id, double *percent,
|
||||||
unsigned int cpu)
|
unsigned int cpu)
|
||||||
{
|
{
|
||||||
unsigned long long aperf_diff, mperf_diff, tsc_diff;
|
unsigned long long aperf_diff, mperf_diff, tsc_diff;
|
||||||
|
unsigned long long timediff;
|
||||||
|
|
||||||
if (!is_valid[cpu])
|
if (!is_valid[cpu])
|
||||||
return -1;
|
return -1;
|
||||||
@@ -136,11 +128,19 @@ static int mperf_get_count_percent(unsigned int id, double *percent,
|
|||||||
|
|
||||||
mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
|
mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
|
||||||
aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
|
aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
|
||||||
tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
|
|
||||||
|
|
||||||
*percent = 100.0 * mperf_diff / tsc_diff;
|
if (max_freq_mode == MAX_FREQ_TSC_REF) {
|
||||||
dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n",
|
tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
|
||||||
mperf_cstates[id].name, mperf_diff, tsc_diff);
|
*percent = 100.0 * mperf_diff / tsc_diff;
|
||||||
|
dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n",
|
||||||
|
mperf_cstates[id].name, mperf_diff, tsc_diff);
|
||||||
|
} else if (max_freq_mode == MAX_FREQ_SYSFS) {
|
||||||
|
timediff = timespec_diff_us(time_start, time_end);
|
||||||
|
*percent = 100.0 * mperf_diff / timediff;
|
||||||
|
dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n",
|
||||||
|
mperf_cstates[id].name, mperf_diff, timediff);
|
||||||
|
} else
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (id == Cx)
|
if (id == Cx)
|
||||||
*percent = 100.0 - *percent;
|
*percent = 100.0 - *percent;
|
||||||
@@ -154,7 +154,7 @@ static int mperf_get_count_percent(unsigned int id, double *percent,
|
|||||||
static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
|
static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
|
||||||
unsigned int cpu)
|
unsigned int cpu)
|
||||||
{
|
{
|
||||||
unsigned long long aperf_diff, mperf_diff;
|
unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff;
|
||||||
|
|
||||||
if (id != AVG_FREQ)
|
if (id != AVG_FREQ)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -165,11 +165,21 @@ static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
|
|||||||
mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
|
mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
|
||||||
aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
|
aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
|
||||||
|
|
||||||
/* Return MHz for now, might want to return KHz if column width is more
|
if (max_freq_mode == MAX_FREQ_TSC_REF) {
|
||||||
generic */
|
/* Calculate max_freq from TSC count */
|
||||||
*count = get_average_perf(aperf_diff, mperf_diff) / 1000;
|
tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
|
||||||
dprint("%s: %llu\n", mperf_cstates[id].name, *count);
|
time_diff = timespec_diff_us(time_start, time_end);
|
||||||
|
max_frequency = tsc_diff / time_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
*count = max_frequency * ((double)aperf_diff / mperf_diff);
|
||||||
|
dprint("%s: Average freq based on %s maximum frequency:\n",
|
||||||
|
mperf_cstates[id].name,
|
||||||
|
(max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read");
|
||||||
|
dprint("%max_frequency: %lu", max_frequency);
|
||||||
|
dprint("aperf_diff: %llu\n", aperf_diff);
|
||||||
|
dprint("mperf_diff: %llu\n", mperf_diff);
|
||||||
|
dprint("avg freq: %llu\n", *count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +188,7 @@ static int mperf_start(void)
|
|||||||
int cpu;
|
int cpu;
|
||||||
unsigned long long dbg;
|
unsigned long long dbg;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_REALTIME, &time_start);
|
||||||
mperf_get_tsc(&tsc_at_measure_start);
|
mperf_get_tsc(&tsc_at_measure_start);
|
||||||
|
|
||||||
for (cpu = 0; cpu < cpu_count; cpu++)
|
for (cpu = 0; cpu < cpu_count; cpu++)
|
||||||
@@ -193,32 +204,104 @@ static int mperf_stop(void)
|
|||||||
unsigned long long dbg;
|
unsigned long long dbg;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
mperf_get_tsc(&tsc_at_measure_end);
|
|
||||||
|
|
||||||
for (cpu = 0; cpu < cpu_count; cpu++)
|
for (cpu = 0; cpu < cpu_count; cpu++)
|
||||||
mperf_measure_stats(cpu);
|
mperf_measure_stats(cpu);
|
||||||
|
|
||||||
|
mperf_get_tsc(&tsc_at_measure_end);
|
||||||
|
clock_gettime(CLOCK_REALTIME, &time_end);
|
||||||
|
|
||||||
mperf_get_tsc(&dbg);
|
mperf_get_tsc(&dbg);
|
||||||
dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
|
dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cpuidle_monitor mperf_monitor;
|
/*
|
||||||
|
* Mperf register is defined to tick at P0 (maximum) frequency
|
||||||
struct cpuidle_monitor *mperf_register(void)
|
*
|
||||||
|
* Instead of reading out P0 which can be tricky to read out from HW,
|
||||||
|
* we use TSC counter if it reliably ticks at P0/mperf frequency.
|
||||||
|
*
|
||||||
|
* Still try to fall back to:
|
||||||
|
* /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
|
||||||
|
* on older Intel HW without invariant TSC feature.
|
||||||
|
* Or on AMD machines where TSC does not tick at P0 (do not exist yet, but
|
||||||
|
* it's still double checked (MSR_AMD_HWCR)).
|
||||||
|
*
|
||||||
|
* On these machines the user would still get useful mperf
|
||||||
|
* stats when acpi-cpufreq driver is loaded.
|
||||||
|
*/
|
||||||
|
static int init_maxfreq_mode(void)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned long long hwcr;
|
||||||
unsigned long min;
|
unsigned long min;
|
||||||
|
|
||||||
if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
|
if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC)
|
||||||
return NULL;
|
goto use_sysfs;
|
||||||
|
|
||||||
/* Assume min/max all the same on all cores */
|
if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) {
|
||||||
|
/* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf
|
||||||
|
* freq.
|
||||||
|
* A test whether hwcr is accessable/available would be:
|
||||||
|
* (cpupower_cpu_info.family > 0x10 ||
|
||||||
|
* cpupower_cpu_info.family == 0x10 &&
|
||||||
|
* cpupower_cpu_info.model >= 0x2))
|
||||||
|
* This should be the case for all aperf/mperf
|
||||||
|
* capable AMD machines and is therefore safe to test here.
|
||||||
|
* Compare with Linus kernel git commit: acf01734b1747b1ec4
|
||||||
|
*/
|
||||||
|
ret = read_msr(0, MSR_AMD_HWCR, &hwcr);
|
||||||
|
/*
|
||||||
|
* If the MSR read failed, assume a Xen system that did
|
||||||
|
* not explicitly provide access to it and assume TSC works
|
||||||
|
*/
|
||||||
|
if (ret != 0) {
|
||||||
|
dprint("TSC read 0x%x failed - assume TSC working\n",
|
||||||
|
MSR_AMD_HWCR);
|
||||||
|
return 0;
|
||||||
|
} else if (1 & (hwcr >> 24)) {
|
||||||
|
max_freq_mode = MAX_FREQ_TSC_REF;
|
||||||
|
return 0;
|
||||||
|
} else { /* Use sysfs max frequency if available */ }
|
||||||
|
} else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) {
|
||||||
|
/*
|
||||||
|
* On Intel we assume mperf (in C0) is ticking at same
|
||||||
|
* rate than TSC
|
||||||
|
*/
|
||||||
|
max_freq_mode = MAX_FREQ_TSC_REF;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
use_sysfs:
|
||||||
if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) {
|
if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) {
|
||||||
dprint("Cannot retrieve max freq from cpufreq kernel "
|
dprint("Cannot retrieve max freq from cpufreq kernel "
|
||||||
"subsystem\n");
|
"subsystem\n");
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
max_freq_mode = MAX_FREQ_SYSFS;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This monitor provides:
|
||||||
|
*
|
||||||
|
* 1) Average frequency a CPU resided in
|
||||||
|
* This always works if the CPU has aperf/mperf capabilities
|
||||||
|
*
|
||||||
|
* 2) C0 and Cx (any sleep state) time a CPU resided in
|
||||||
|
* Works if mperf timer stops ticking in sleep states which
|
||||||
|
* seem to be the case on all current HW.
|
||||||
|
* Both is directly retrieved from HW registers and is independent
|
||||||
|
* from kernel statistics.
|
||||||
|
*/
|
||||||
|
struct cpuidle_monitor mperf_monitor;
|
||||||
|
struct cpuidle_monitor *mperf_register(void)
|
||||||
|
{
|
||||||
|
if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (init_maxfreq_mode())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* Free this at program termination */
|
/* Free this at program termination */
|
||||||
is_valid = calloc(cpu_count, sizeof(int));
|
is_valid = calloc(cpu_count, sizeof(int));
|
||||||
|
Reference in New Issue
Block a user