Merge branch 'pm-tools'
* pm-tools: cpupower: IvyBridge (0x3a and 0x3e models) support cpupower: Provide -c param for cpupower monitor to schedule process on all cores cpupower tools: Fix warning and a bug with the cpu package count cpupower tools: Fix malloc of cpu_info structure cpupower tools: Fix issues with sysfs_topology_read_file cpupower tools: Fix minor warnings cpupower tools: Update .gitignore for files created in the debug directories cpupower tools: Remove brace expansion from clean target
This commit is contained in:
commit
ad063fbbdd
tools/power/cpupower
7
tools/power/cpupower/.gitignore
vendored
7
tools/power/cpupower/.gitignore
vendored
@ -20,3 +20,10 @@ utils/cpufreq-set.o
|
||||
utils/cpufreq-aperf.o
|
||||
cpupower
|
||||
bench/cpufreq-bench
|
||||
debug/kernel/Module.symvers
|
||||
debug/i386/centrino-decode
|
||||
debug/i386/dump_psb
|
||||
debug/i386/intel_gsic
|
||||
debug/i386/powernow-k8-decode
|
||||
debug/x86_64/centrino-decode
|
||||
debug/x86_64/powernow-k8-decode
|
||||
|
@ -253,7 +253,8 @@ clean:
|
||||
| xargs rm -f
|
||||
-rm -f $(OUTPUT)cpupower
|
||||
-rm -f $(OUTPUT)libcpupower.so*
|
||||
-rm -rf $(OUTPUT)po/*.{gmo,pot}
|
||||
-rm -rf $(OUTPUT)po/*.gmo
|
||||
-rm -rf $(OUTPUT)po/*.pot
|
||||
$(MAKE) -C bench O=$(OUTPUT) clean
|
||||
|
||||
|
||||
|
@ -26,7 +26,10 @@ $(OUTPUT)powernow-k8-decode: powernow-k8-decode.c
|
||||
all: $(OUTPUT)centrino-decode $(OUTPUT)dump_psb $(OUTPUT)intel_gsic $(OUTPUT)powernow-k8-decode
|
||||
|
||||
clean:
|
||||
rm -rf $(OUTPUT){centrino-decode,dump_psb,intel_gsic,powernow-k8-decode}
|
||||
rm -rf $(OUTPUT)centrino-decode
|
||||
rm -rf $(OUTPUT)dump_psb
|
||||
rm -rf $(OUTPUT)intel_gsic
|
||||
rm -rf $(OUTPUT)powernow-k8-decode
|
||||
|
||||
install:
|
||||
$(INSTALL) -d $(DESTDIR)${bindir}
|
||||
|
@ -7,11 +7,11 @@ cpupower\-monitor \- Report processor frequency and idle statistics
|
||||
.RB "\-l"
|
||||
|
||||
.B cpupower monitor
|
||||
.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
|
||||
.RB [ -c ] [ "\-m <mon1>," [ "<mon2>,..." ] ]
|
||||
.RB [ "\-i seconds" ]
|
||||
.br
|
||||
.B cpupower monitor
|
||||
.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
|
||||
.RB [ -c ][ "\-m <mon1>," [ "<mon2>,..." ] ]
|
||||
.RB command
|
||||
.br
|
||||
.SH DESCRIPTION
|
||||
@ -64,6 +64,17 @@ Only display specific monitors. Use the monitor string(s) provided by \-l option
|
||||
Measure intervall.
|
||||
.RE
|
||||
.PP
|
||||
\-c
|
||||
.RS 4
|
||||
Schedule the process on every core before starting and ending measuring.
|
||||
This could be needed for the Idle_Stats monitor when no other MSR based
|
||||
monitor (has to be run on the core that is measured) is run in parallel.
|
||||
This is to wake up the processors from deeper sleep states and let the
|
||||
kernel re
|
||||
-account its cpuidle (C-state) information before reading the
|
||||
cpuidle timings from sysfs.
|
||||
.RE
|
||||
.PP
|
||||
command
|
||||
.RS 4
|
||||
Measure idle and frequency characteristics of an arbitrary command/workload.
|
||||
|
@ -158,6 +158,8 @@ out:
|
||||
cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
|
||||
case 0x2A: /* SNB */
|
||||
case 0x2D: /* SNB Xeon */
|
||||
case 0x3A: /* IVB */
|
||||
case 0x3E: /* IVB Xeon */
|
||||
cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
|
||||
cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
|
||||
break;
|
||||
|
@ -92,6 +92,14 @@ extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info);
|
||||
extern struct cpupower_cpu_info cpupower_cpu_info;
|
||||
/* cpuid and cpuinfo helpers **************************/
|
||||
|
||||
struct cpuid_core_info {
|
||||
int pkg;
|
||||
int core;
|
||||
int cpu;
|
||||
|
||||
/* flags */
|
||||
unsigned int is_online:1;
|
||||
};
|
||||
|
||||
/* CPU topology/hierarchy parsing ******************/
|
||||
struct cpupower_topology {
|
||||
@ -101,18 +109,12 @@ struct cpupower_topology {
|
||||
unsigned int threads; /* per core */
|
||||
|
||||
/* Array gets mallocated with cores entries, holding per core info */
|
||||
struct {
|
||||
int pkg;
|
||||
int core;
|
||||
int cpu;
|
||||
|
||||
/* flags */
|
||||
unsigned int is_online:1;
|
||||
} *core_info;
|
||||
struct cpuid_core_info *core_info;
|
||||
};
|
||||
|
||||
extern int get_cpu_topology(struct cpupower_topology *cpu_top);
|
||||
extern void cpu_topology_release(struct cpupower_topology cpu_top);
|
||||
|
||||
/* CPU topology/hierarchy parsing ******************/
|
||||
|
||||
/* X86 ONLY ****************************************/
|
||||
|
@ -37,25 +37,6 @@ unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
|
||||
return (unsigned int) numread;
|
||||
}
|
||||
|
||||
static unsigned int sysfs_write_file(const char *path,
|
||||
const char *value, size_t len)
|
||||
{
|
||||
int fd;
|
||||
ssize_t numwrite;
|
||||
|
||||
fd = open(path, O_WRONLY);
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
|
||||
numwrite = write(fd, value, len);
|
||||
if (numwrite < 1) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
return (unsigned int) numwrite;
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect whether a CPU is online
|
||||
*
|
||||
|
@ -20,9 +20,8 @@
|
||||
#include <helpers/sysfs.h>
|
||||
|
||||
/* returns -1 on failure, 0 on success */
|
||||
int sysfs_topology_read_file(unsigned int cpu, const char *fname)
|
||||
static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result)
|
||||
{
|
||||
unsigned long value;
|
||||
char linebuf[MAX_LINE_LEN];
|
||||
char *endp;
|
||||
char path[SYSFS_PATH_MAX];
|
||||
@ -31,20 +30,12 @@ int sysfs_topology_read_file(unsigned int cpu, const char *fname)
|
||||
cpu, fname);
|
||||
if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
|
||||
return -1;
|
||||
value = strtoul(linebuf, &endp, 0);
|
||||
*result = strtol(linebuf, &endp, 0);
|
||||
if (endp == linebuf || errno == ERANGE)
|
||||
return -1;
|
||||
return value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cpuid_core_info {
|
||||
unsigned int pkg;
|
||||
unsigned int thread;
|
||||
unsigned int cpu;
|
||||
/* flags */
|
||||
unsigned int is_online:1;
|
||||
};
|
||||
|
||||
static int __compare(const void *t1, const void *t2)
|
||||
{
|
||||
struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
|
||||
@ -53,9 +44,9 @@ static int __compare(const void *t1, const void *t2)
|
||||
return -1;
|
||||
else if (top1->pkg > top2->pkg)
|
||||
return 1;
|
||||
else if (top1->thread < top2->thread)
|
||||
else if (top1->core < top2->core)
|
||||
return -1;
|
||||
else if (top1->thread > top2->thread)
|
||||
else if (top1->core > top2->core)
|
||||
return 1;
|
||||
else if (top1->cpu < top2->cpu)
|
||||
return -1;
|
||||
@ -73,28 +64,42 @@ static int __compare(const void *t1, const void *t2)
|
||||
*/
|
||||
int get_cpu_topology(struct cpupower_topology *cpu_top)
|
||||
{
|
||||
int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
|
||||
cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus);
|
||||
cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
|
||||
if (cpu_top->core_info == NULL)
|
||||
return -ENOMEM;
|
||||
cpu_top->pkgs = cpu_top->cores = 0;
|
||||
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 =
|
||||
sysfs_topology_read_file(cpu, "physical_package_id");
|
||||
if ((int)cpu_top->core_info[cpu].pkg != -1 &&
|
||||
cpu_top->core_info[cpu].pkg > cpu_top->pkgs)
|
||||
cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
|
||||
cpu_top->core_info[cpu].core =
|
||||
sysfs_topology_read_file(cpu, "core_id");
|
||||
if(sysfs_topology_read_file(
|
||||
cpu,
|
||||
"physical_package_id",
|
||||
&(cpu_top->core_info[cpu].pkg)) < 0)
|
||||
return -1;
|
||||
if(sysfs_topology_read_file(
|
||||
cpu,
|
||||
"core_id",
|
||||
&(cpu_top->core_info[cpu].core)) < 0)
|
||||
return -1;
|
||||
}
|
||||
cpu_top->pkgs++;
|
||||
|
||||
qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
|
||||
__compare);
|
||||
|
||||
/* Count the number of distinct pkgs values. This works
|
||||
because the primary sort of the core_info struct was just
|
||||
done by pkg value. */
|
||||
last_pkg = cpu_top->core_info[0].pkg;
|
||||
for(cpu = 1; cpu < cpus; cpu++) {
|
||||
if(cpu_top->core_info[cpu].pkg != last_pkg) {
|
||||
last_pkg = cpu_top->core_info[cpu].pkg;
|
||||
cpu_top->pkgs++;
|
||||
}
|
||||
}
|
||||
cpu_top->pkgs++;
|
||||
|
||||
/* Intel's cores count is not consecutively numbered, there may
|
||||
* be a core_id of 3, but none of 2. Assume there always is 0
|
||||
* Get amount of cores by counting duplicates in a package
|
||||
|
@ -39,6 +39,7 @@ static int mode;
|
||||
static int interval = 1;
|
||||
static char *show_monitors_param;
|
||||
static struct cpupower_topology cpu_top;
|
||||
static unsigned int wake_cpus;
|
||||
|
||||
/* ToDo: Document this in the manpage */
|
||||
static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
|
||||
@ -84,7 +85,7 @@ int fill_string_with_spaces(char *s, int n)
|
||||
void print_header(int topology_depth)
|
||||
{
|
||||
int unsigned mon;
|
||||
int state, need_len, pr_mon_len;
|
||||
int state, need_len;
|
||||
cstate_t s;
|
||||
char buf[128] = "";
|
||||
int percent_width = 4;
|
||||
@ -93,7 +94,6 @@ void print_header(int topology_depth)
|
||||
printf("%s|", buf);
|
||||
|
||||
for (mon = 0; mon < avail_monitors; mon++) {
|
||||
pr_mon_len = 0;
|
||||
need_len = monitors[mon]->hw_states_num * (percent_width + 3)
|
||||
- 1;
|
||||
if (mon != 0) {
|
||||
@ -315,16 +315,28 @@ int fork_it(char **argv)
|
||||
int do_interval_measure(int i)
|
||||
{
|
||||
unsigned int num;
|
||||
int cpu;
|
||||
|
||||
if (wake_cpus)
|
||||
for (cpu = 0; cpu < cpu_count; cpu++)
|
||||
bind_cpu(cpu);
|
||||
|
||||
for (num = 0; num < avail_monitors; num++) {
|
||||
dprint("HW C-state residency monitor: %s - States: %d\n",
|
||||
monitors[num]->name, monitors[num]->hw_states_num);
|
||||
monitors[num]->start();
|
||||
}
|
||||
|
||||
sleep(i);
|
||||
|
||||
if (wake_cpus)
|
||||
for (cpu = 0; cpu < cpu_count; cpu++)
|
||||
bind_cpu(cpu);
|
||||
|
||||
for (num = 0; num < avail_monitors; num++)
|
||||
monitors[num]->stop();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -333,7 +345,7 @@ static void cmdline(int argc, char *argv[])
|
||||
int opt;
|
||||
progname = basename(argv[0]);
|
||||
|
||||
while ((opt = getopt(argc, argv, "+li:m:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "+lci:m:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'l':
|
||||
if (mode)
|
||||
@ -352,6 +364,9 @@ static void cmdline(int argc, char *argv[])
|
||||
mode = show;
|
||||
show_monitors_param = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
wake_cpus = 1;
|
||||
break;
|
||||
default:
|
||||
print_wrong_arg_exit();
|
||||
}
|
||||
|
@ -65,4 +65,21 @@ extern long long timespec_diff_us(struct timespec start, struct timespec end);
|
||||
"could be inaccurate\n"), mes, ov); \
|
||||
}
|
||||
|
||||
|
||||
/* Taken over from x86info project sources -> return 0 on success */
|
||||
#include <sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
static inline int bind_cpu(int cpu)
|
||||
{
|
||||
cpu_set_t set;
|
||||
|
||||
if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) {
|
||||
CPU_ZERO(&set);
|
||||
CPU_SET(cpu, &set);
|
||||
return sched_setaffinity(getpid(), sizeof(set), &set);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* __CPUIDLE_INFO_HW__ */
|
||||
|
@ -150,9 +150,15 @@ static struct cpuidle_monitor *snb_register(void)
|
||||
|| cpupower_cpu_info.family != 6)
|
||||
return NULL;
|
||||
|
||||
if (cpupower_cpu_info.model != 0x2A
|
||||
&& cpupower_cpu_info.model != 0x2D)
|
||||
switch (cpupower_cpu_info.model) {
|
||||
case 0x2A: /* SNB */
|
||||
case 0x2D: /* SNB Xeon */
|
||||
case 0x3A: /* IVB */
|
||||
case 0x3E: /* IVB Xeon */
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
is_valid = calloc(cpu_count, sizeof(int));
|
||||
for (num = 0; num < SNB_CSTATE_COUNT; num++) {
|
||||
|
Loading…
Reference in New Issue
Block a user