Commit 9581e24c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge tag 'linux-cpupower-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux

Pull cpupower utility updates for v5.5 from Shuah Khan:

"This cpupower update for Linux 5.5-rc1 consists of bug fixes and
 improvements to make it more accurate by removing the userspace
 to kernel transition and read_msr initiated IPI delays."

* tag 'linux-cpupower-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux:
  cpupower: ToDo: Update ToDo with ideas for per_cpu_schedule handling
  cpupower: mperf_monitor: Update cpupower to use the RDPRU instruction
  cpupower: mperf_monitor: Introduce per_cpu_schedule flag
  cpupower: Move needs_root variable into a sub-struct
  cpupower : Handle set and info subcommands correctly
  tools/power/cpupower: Fix initializer override in hsw_ext_cstates
parents fef4ac87 4611a4fb
...@@ -8,3 +8,17 @@ ToDos sorted by priority: ...@@ -8,3 +8,17 @@ ToDos sorted by priority:
- Add another c1e debug idle monitor - Add another c1e debug idle monitor
-> Is by design racy with BIOS, but could be added -> Is by design racy with BIOS, but could be added
with a --force option and some "be careful" messages with a --force option and some "be careful" messages
- Add cpu_start()/cpu_stop() callbacks for monitor
-> This is to move the per_cpu logic from inside the
monitor to outside it. This can be given higher
priority in fork_it.
- Fork as many processes as there are CPUs in case the
per_cpu_schedule flag is set.
-> Bind forked process to each cpu.
-> Execute start measures via the forked processes on
each cpu.
-> Run test executable in a forked process.
-> Execute stop measures via the forked processes on
each cpu.
This would be ideal as it will not introduce noise in the
tested executable.
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <getopt.h> #include <getopt.h>
#include <sys/utsname.h>
#include "helpers/helpers.h" #include "helpers/helpers.h"
#include "helpers/sysfs.h" #include "helpers/sysfs.h"
...@@ -30,6 +31,7 @@ int cmd_info(int argc, char **argv) ...@@ -30,6 +31,7 @@ int cmd_info(int argc, char **argv)
extern char *optarg; extern char *optarg;
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
unsigned int cpu; unsigned int cpu;
struct utsname uts;
union { union {
struct { struct {
...@@ -39,6 +41,13 @@ int cmd_info(int argc, char **argv) ...@@ -39,6 +41,13 @@ int cmd_info(int argc, char **argv)
} params = {}; } params = {};
int ret = 0; int ret = 0;
ret = uname(&uts);
if (!ret && (!strcmp(uts.machine, "ppc64le") ||
!strcmp(uts.machine, "ppc64"))) {
fprintf(stderr, _("Subcommand not supported on POWER.\n"));
return ret;
}
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
textdomain(PACKAGE); textdomain(PACKAGE);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <getopt.h> #include <getopt.h>
#include <sys/utsname.h>
#include "helpers/helpers.h" #include "helpers/helpers.h"
#include "helpers/sysfs.h" #include "helpers/sysfs.h"
...@@ -31,6 +32,7 @@ int cmd_set(int argc, char **argv) ...@@ -31,6 +32,7 @@ int cmd_set(int argc, char **argv)
extern char *optarg; extern char *optarg;
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
unsigned int cpu; unsigned int cpu;
struct utsname uts;
union { union {
struct { struct {
...@@ -41,6 +43,13 @@ int cmd_set(int argc, char **argv) ...@@ -41,6 +43,13 @@ int cmd_set(int argc, char **argv)
int perf_bias = 0; int perf_bias = 0;
int ret = 0; int ret = 0;
ret = uname(&uts);
if (!ret && (!strcmp(uts.machine, "ppc64le") ||
!strcmp(uts.machine, "ppc64"))) {
fprintf(stderr, _("Subcommand not supported on POWER.\n"));
return ret;
}
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
textdomain(PACKAGE); textdomain(PACKAGE);
......
...@@ -131,6 +131,10 @@ int get_cpu_info(struct cpupower_cpu_info *cpu_info) ...@@ -131,6 +131,10 @@ int get_cpu_info(struct cpupower_cpu_info *cpu_info)
if (ext_cpuid_level >= 0x80000007 && if (ext_cpuid_level >= 0x80000007 &&
(cpuid_edx(0x80000007) & (1 << 9))) (cpuid_edx(0x80000007) & (1 << 9)))
cpu_info->caps |= CPUPOWER_CAP_AMD_CBP; cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;
if (ext_cpuid_level >= 0x80000008 &&
cpuid_ebx(0x80000008) & (1 << 4))
cpu_info->caps |= CPUPOWER_CAP_AMD_RDPRU;
} }
if (cpu_info->vendor == X86_VENDOR_INTEL) { if (cpu_info->vendor == X86_VENDOR_INTEL) {
......
...@@ -69,6 +69,7 @@ enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL, ...@@ -69,6 +69,7 @@ enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
#define CPUPOWER_CAP_HAS_TURBO_RATIO 0x00000010 #define CPUPOWER_CAP_HAS_TURBO_RATIO 0x00000010
#define CPUPOWER_CAP_IS_SNB 0x00000020 #define CPUPOWER_CAP_IS_SNB 0x00000020
#define CPUPOWER_CAP_INTEL_IDA 0x00000040 #define CPUPOWER_CAP_INTEL_IDA 0x00000040
#define CPUPOWER_CAP_AMD_RDPRU 0x00000080
#define CPUPOWER_AMD_CPBDIS 0x02000000 #define CPUPOWER_AMD_CPBDIS 0x02000000
......
...@@ -328,7 +328,7 @@ struct cpuidle_monitor amd_fam14h_monitor = { ...@@ -328,7 +328,7 @@ struct cpuidle_monitor amd_fam14h_monitor = {
.stop = amd_fam14h_stop, .stop = amd_fam14h_stop,
.do_register = amd_fam14h_register, .do_register = amd_fam14h_register,
.unregister = amd_fam14h_unregister, .unregister = amd_fam14h_unregister,
.needs_root = 1, .flags.needs_root = 1,
.overflow_s = OVERFLOW_MS / 1000, .overflow_s = OVERFLOW_MS / 1000,
}; };
#endif /* #if defined(__i386__) || defined(__x86_64__) */ #endif /* #if defined(__i386__) || defined(__x86_64__) */
...@@ -207,6 +207,6 @@ struct cpuidle_monitor cpuidle_sysfs_monitor = { ...@@ -207,6 +207,6 @@ struct cpuidle_monitor cpuidle_sysfs_monitor = {
.stop = cpuidle_stop, .stop = cpuidle_stop,
.do_register = cpuidle_register, .do_register = cpuidle_register,
.unregister = cpuidle_unregister, .unregister = cpuidle_unregister,
.needs_root = 0, .flags.needs_root = 0,
.overflow_s = UINT_MAX, .overflow_s = UINT_MAX,
}; };
...@@ -408,7 +408,7 @@ int cmd_monitor(int argc, char **argv) ...@@ -408,7 +408,7 @@ int cmd_monitor(int argc, char **argv)
dprint("Try to register: %s\n", all_monitors[num]->name); dprint("Try to register: %s\n", all_monitors[num]->name);
test_mon = all_monitors[num]->do_register(); test_mon = all_monitors[num]->do_register();
if (test_mon) { if (test_mon) {
if (test_mon->needs_root && !run_as_root) { if (test_mon->flags.needs_root && !run_as_root) {
fprintf(stderr, _("Available monitor %s needs " fprintf(stderr, _("Available monitor %s needs "
"root access\n"), test_mon->name); "root access\n"), test_mon->name);
continue; continue;
......
...@@ -60,7 +60,10 @@ struct cpuidle_monitor { ...@@ -60,7 +60,10 @@ struct cpuidle_monitor {
struct cpuidle_monitor* (*do_register) (void); struct cpuidle_monitor* (*do_register) (void);
void (*unregister)(void); void (*unregister)(void);
unsigned int overflow_s; unsigned int overflow_s;
int needs_root; struct {
unsigned int needs_root:1;
unsigned int per_cpu_schedule:1;
} flags;
}; };
extern long long timespec_diff_us(struct timespec start, struct timespec end); extern long long timespec_diff_us(struct timespec start, struct timespec end);
......
...@@ -39,7 +39,6 @@ static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = { ...@@ -39,7 +39,6 @@ static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = {
{ {
.name = "PC9", .name = "PC9",
.desc = N_("Processor Package C9"), .desc = N_("Processor Package C9"),
.desc = N_("Processor Package C2"),
.id = PC9, .id = PC9,
.range = RANGE_PACKAGE, .range = RANGE_PACKAGE,
.get_count_percent = hsw_ext_get_count_percent, .get_count_percent = hsw_ext_get_count_percent,
...@@ -188,7 +187,7 @@ struct cpuidle_monitor intel_hsw_ext_monitor = { ...@@ -188,7 +187,7 @@ struct cpuidle_monitor intel_hsw_ext_monitor = {
.stop = hsw_ext_stop, .stop = hsw_ext_stop,
.do_register = hsw_ext_register, .do_register = hsw_ext_register,
.unregister = hsw_ext_unregister, .unregister = hsw_ext_unregister,
.needs_root = 1, .flags.needs_root = 1,
.overflow_s = 922000000 /* 922337203 seconds TSC overflow .overflow_s = 922000000 /* 922337203 seconds TSC overflow
at 20GHz */ at 20GHz */
}; };
......
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
#define MSR_APERF 0xE8 #define MSR_APERF 0xE8
#define MSR_MPERF 0xE7 #define MSR_MPERF 0xE7
#define RDPRU ".byte 0x0f, 0x01, 0xfd"
#define RDPRU_ECX_MPERF 0
#define RDPRU_ECX_APERF 1
#define MSR_TSC 0x10 #define MSR_TSC 0x10
#define MSR_AMD_HWCR 0xc0010015 #define MSR_AMD_HWCR 0xc0010015
...@@ -86,15 +90,51 @@ static int mperf_get_tsc(unsigned long long *tsc) ...@@ -86,15 +90,51 @@ static int mperf_get_tsc(unsigned long long *tsc)
return ret; return ret;
} }
static int get_aperf_mperf(int cpu, unsigned long long *aval,
unsigned long long *mval)
{
unsigned long low_a, high_a;
unsigned long low_m, high_m;
int ret;
/*
* Running on the cpu from which we read the registers will
* prevent APERF/MPERF from going out of sync because of IPI
* latency introduced by read_msr()s.
*/
if (mperf_monitor.flags.per_cpu_schedule) {
if (bind_cpu(cpu))
return 1;
}
if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_RDPRU) {
asm volatile(RDPRU
: "=a" (low_a), "=d" (high_a)
: "c" (RDPRU_ECX_APERF));
asm volatile(RDPRU
: "=a" (low_m), "=d" (high_m)
: "c" (RDPRU_ECX_MPERF));
*aval = ((low_a) | (high_a) << 32);
*mval = ((low_m) | (high_m) << 32);
return 0;
}
ret = read_msr(cpu, MSR_APERF, aval);
ret |= read_msr(cpu, MSR_MPERF, mval);
return ret;
}
static int mperf_init_stats(unsigned int cpu) static int mperf_init_stats(unsigned int cpu)
{ {
unsigned long long val; unsigned long long aval, mval;
int ret; int ret;
ret = read_msr(cpu, MSR_APERF, &val); ret = get_aperf_mperf(cpu, &aval, &mval);
aperf_previous_count[cpu] = val; aperf_previous_count[cpu] = aval;
ret |= read_msr(cpu, MSR_MPERF, &val); mperf_previous_count[cpu] = mval;
mperf_previous_count[cpu] = val;
is_valid[cpu] = !ret; is_valid[cpu] = !ret;
return 0; return 0;
...@@ -102,13 +142,12 @@ static int mperf_init_stats(unsigned int cpu) ...@@ -102,13 +142,12 @@ static int mperf_init_stats(unsigned int cpu)
static int mperf_measure_stats(unsigned int cpu) static int mperf_measure_stats(unsigned int cpu)
{ {
unsigned long long val; unsigned long long aval, mval;
int ret; int ret;
ret = read_msr(cpu, MSR_APERF, &val); ret = get_aperf_mperf(cpu, &aval, &mval);
aperf_current_count[cpu] = val; aperf_current_count[cpu] = aval;
ret |= read_msr(cpu, MSR_MPERF, &val); mperf_current_count[cpu] = mval;
mperf_current_count[cpu] = val;
is_valid[cpu] = !ret; is_valid[cpu] = !ret;
return 0; return 0;
...@@ -305,6 +344,9 @@ struct cpuidle_monitor *mperf_register(void) ...@@ -305,6 +344,9 @@ struct cpuidle_monitor *mperf_register(void)
if (init_maxfreq_mode()) if (init_maxfreq_mode())
return NULL; return NULL;
if (cpupower_cpu_info.vendor == X86_VENDOR_AMD)
mperf_monitor.flags.per_cpu_schedule = 1;
/* Free this at program termination */ /* Free this at program termination */
is_valid = calloc(cpu_count, sizeof(int)); is_valid = calloc(cpu_count, sizeof(int));
mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long)); mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long));
...@@ -333,7 +375,7 @@ struct cpuidle_monitor mperf_monitor = { ...@@ -333,7 +375,7 @@ struct cpuidle_monitor mperf_monitor = {
.stop = mperf_stop, .stop = mperf_stop,
.do_register = mperf_register, .do_register = mperf_register,
.unregister = mperf_unregister, .unregister = mperf_unregister,
.needs_root = 1, .flags.needs_root = 1,
.overflow_s = 922000000 /* 922337203 seconds TSC overflow .overflow_s = 922000000 /* 922337203 seconds TSC overflow
at 20GHz */ at 20GHz */
}; };
......
...@@ -208,7 +208,7 @@ struct cpuidle_monitor intel_nhm_monitor = { ...@@ -208,7 +208,7 @@ struct cpuidle_monitor intel_nhm_monitor = {
.stop = nhm_stop, .stop = nhm_stop,
.do_register = intel_nhm_register, .do_register = intel_nhm_register,
.unregister = intel_nhm_unregister, .unregister = intel_nhm_unregister,
.needs_root = 1, .flags.needs_root = 1,
.overflow_s = 922000000 /* 922337203 seconds TSC overflow .overflow_s = 922000000 /* 922337203 seconds TSC overflow
at 20GHz */ at 20GHz */
}; };
......
...@@ -192,7 +192,7 @@ struct cpuidle_monitor intel_snb_monitor = { ...@@ -192,7 +192,7 @@ struct cpuidle_monitor intel_snb_monitor = {
.stop = snb_stop, .stop = snb_stop,
.do_register = snb_register, .do_register = snb_register,
.unregister = snb_unregister, .unregister = snb_unregister,
.needs_root = 1, .flags.needs_root = 1,
.overflow_s = 922000000 /* 922337203 seconds TSC overflow .overflow_s = 922000000 /* 922337203 seconds TSC overflow
at 20GHz */ at 20GHz */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment