tools/power turbostat: show IRQs per CPU
The new IRQ column shows how many interrupts have occurred on each CPU during the measurement inteval. This information comes from the difference between /proc/interrupts shapshots made before and after the measurement interval. The first row, the system summary, shows the sum of the IRQS for all CPUs during that interval. Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
36229897ba
commit
562a2d377b
|
@ -75,6 +75,7 @@ unsigned int extra_msr_offset64;
|
||||||
unsigned int extra_delta_offset32;
|
unsigned int extra_delta_offset32;
|
||||||
unsigned int extra_delta_offset64;
|
unsigned int extra_delta_offset64;
|
||||||
unsigned int aperf_mperf_multiplier = 1;
|
unsigned int aperf_mperf_multiplier = 1;
|
||||||
|
int do_irq = 1;
|
||||||
int do_smi;
|
int do_smi;
|
||||||
double bclk;
|
double bclk;
|
||||||
double base_hz;
|
double base_hz;
|
||||||
|
@ -154,6 +155,7 @@ struct thread_data {
|
||||||
unsigned long long extra_delta64;
|
unsigned long long extra_delta64;
|
||||||
unsigned long long extra_msr32;
|
unsigned long long extra_msr32;
|
||||||
unsigned long long extra_delta32;
|
unsigned long long extra_delta32;
|
||||||
|
unsigned int irq_count;
|
||||||
unsigned int smi_count;
|
unsigned int smi_count;
|
||||||
unsigned int cpu_id;
|
unsigned int cpu_id;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
@ -221,6 +223,9 @@ struct topo_params {
|
||||||
|
|
||||||
struct timeval tv_even, tv_odd, tv_delta;
|
struct timeval tv_even, tv_odd, tv_delta;
|
||||||
|
|
||||||
|
int *irq_column_2_cpu; /* /proc/interrupts column numbers */
|
||||||
|
int *irqs_per_cpu; /* indexed by cpu_num */
|
||||||
|
|
||||||
void setup_all_buffers(void);
|
void setup_all_buffers(void);
|
||||||
|
|
||||||
int cpu_is_not_present(int cpu)
|
int cpu_is_not_present(int cpu)
|
||||||
|
@ -306,8 +311,8 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
|
||||||
/*
|
/*
|
||||||
* Example Format w/ field column widths:
|
* Example Format w/ field column widths:
|
||||||
*
|
*
|
||||||
* Package Core CPU Avg_MHz Bzy_MHz TSC_MHz SMI Busy% CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
|
* Package Core CPU Avg_MHz Bzy_MHz TSC_MHz IRQ SMI Busy% CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
|
||||||
* 123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678
|
* 12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void print_header(void)
|
void print_header(void)
|
||||||
|
@ -338,6 +343,8 @@ void print_header(void)
|
||||||
if (!debug)
|
if (!debug)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
if (do_irq)
|
||||||
|
outp += sprintf(outp, " IRQ");
|
||||||
if (do_smi)
|
if (do_smi)
|
||||||
outp += sprintf(outp, " SMI");
|
outp += sprintf(outp, " SMI");
|
||||||
|
|
||||||
|
@ -429,6 +436,8 @@ int dump_counters(struct thread_data *t, struct core_data *c,
|
||||||
extra_msr_offset32, t->extra_msr32);
|
extra_msr_offset32, t->extra_msr32);
|
||||||
outp += sprintf(outp, "msr0x%x: %016llX\n",
|
outp += sprintf(outp, "msr0x%x: %016llX\n",
|
||||||
extra_msr_offset64, t->extra_msr64);
|
extra_msr_offset64, t->extra_msr64);
|
||||||
|
if (do_irq)
|
||||||
|
outp += sprintf(outp, "IRQ: %08X\n", t->irq_count);
|
||||||
if (do_smi)
|
if (do_smi)
|
||||||
outp += sprintf(outp, "SMI: %08X\n", t->smi_count);
|
outp += sprintf(outp, "SMI: %08X\n", t->smi_count);
|
||||||
}
|
}
|
||||||
|
@ -562,6 +571,10 @@ int format_counters(struct thread_data *t, struct core_data *c,
|
||||||
if (!debug)
|
if (!debug)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
/* IRQ */
|
||||||
|
if (do_irq)
|
||||||
|
outp += sprintf(outp, "%8d", t->irq_count);
|
||||||
|
|
||||||
/* SMI */
|
/* SMI */
|
||||||
if (do_smi)
|
if (do_smi)
|
||||||
outp += sprintf(outp, "%8d", t->smi_count);
|
outp += sprintf(outp, "%8d", t->smi_count);
|
||||||
|
@ -827,6 +840,9 @@ delta_thread(struct thread_data *new, struct thread_data *old,
|
||||||
old->extra_msr32 = new->extra_msr32;
|
old->extra_msr32 = new->extra_msr32;
|
||||||
old->extra_msr64 = new->extra_msr64;
|
old->extra_msr64 = new->extra_msr64;
|
||||||
|
|
||||||
|
if (do_irq)
|
||||||
|
old->irq_count = new->irq_count - old->irq_count;
|
||||||
|
|
||||||
if (do_smi)
|
if (do_smi)
|
||||||
old->smi_count = new->smi_count - old->smi_count;
|
old->smi_count = new->smi_count - old->smi_count;
|
||||||
}
|
}
|
||||||
|
@ -856,10 +872,12 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
|
||||||
t->mperf = 0;
|
t->mperf = 0;
|
||||||
t->c1 = 0;
|
t->c1 = 0;
|
||||||
|
|
||||||
t->smi_count = 0;
|
|
||||||
t->extra_delta32 = 0;
|
t->extra_delta32 = 0;
|
||||||
t->extra_delta64 = 0;
|
t->extra_delta64 = 0;
|
||||||
|
|
||||||
|
t->irq_count = 0;
|
||||||
|
t->smi_count = 0;
|
||||||
|
|
||||||
/* tells format_counters to dump all fields from this set */
|
/* tells format_counters to dump all fields from this set */
|
||||||
t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
|
t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
|
||||||
|
|
||||||
|
@ -903,6 +921,9 @@ int sum_counters(struct thread_data *t, struct core_data *c,
|
||||||
average.threads.extra_delta32 += t->extra_delta32;
|
average.threads.extra_delta32 += t->extra_delta32;
|
||||||
average.threads.extra_delta64 += t->extra_delta64;
|
average.threads.extra_delta64 += t->extra_delta64;
|
||||||
|
|
||||||
|
average.threads.irq_count += t->irq_count;
|
||||||
|
average.threads.smi_count += t->smi_count;
|
||||||
|
|
||||||
/* sum per-core values only for 1st thread in core */
|
/* sum per-core values only for 1st thread in core */
|
||||||
if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
|
if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1000,7 +1021,6 @@ static unsigned long long rdtsc(void)
|
||||||
return low | ((unsigned long long)high) << 32;
|
return low | ((unsigned long long)high) << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get_counters(...)
|
* get_counters(...)
|
||||||
* migrate to cpu
|
* migrate to cpu
|
||||||
|
@ -1027,6 +1047,8 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
|
||||||
t->mperf = t->mperf * aperf_mperf_multiplier;
|
t->mperf = t->mperf * aperf_mperf_multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (do_irq)
|
||||||
|
t->irq_count = irqs_per_cpu[cpu];
|
||||||
if (do_smi) {
|
if (do_smi) {
|
||||||
if (get_msr(cpu, MSR_SMI_COUNT, &msr))
|
if (get_msr(cpu, MSR_SMI_COUNT, &msr))
|
||||||
return -5;
|
return -5;
|
||||||
|
@ -1515,6 +1537,9 @@ void free_all_buffers(void)
|
||||||
outp = NULL;
|
outp = NULL;
|
||||||
|
|
||||||
free_fd_percpu();
|
free_fd_percpu();
|
||||||
|
|
||||||
|
free(irq_column_2_cpu);
|
||||||
|
free(irqs_per_cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1737,6 +1762,83 @@ int mark_cpu_present(int cpu)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* snapshot_proc_interrupts()
|
||||||
|
*
|
||||||
|
* read and record summary of /proc/interrupts
|
||||||
|
*
|
||||||
|
* return 1 if config change requires a restart, else return 0
|
||||||
|
*/
|
||||||
|
int snapshot_proc_interrupts(void)
|
||||||
|
{
|
||||||
|
static FILE *fp;
|
||||||
|
int column, retval;
|
||||||
|
|
||||||
|
if (fp == NULL)
|
||||||
|
fp = fopen_or_die("/proc/interrupts", "r");
|
||||||
|
else
|
||||||
|
rewind(fp);
|
||||||
|
|
||||||
|
/* read 1st line of /proc/interrupts to get cpu* name for each column */
|
||||||
|
for (column = 0; column < topo.num_cpus; ++column) {
|
||||||
|
int cpu_number;
|
||||||
|
|
||||||
|
retval = fscanf(fp, " CPU%d", &cpu_number);
|
||||||
|
if (retval != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (cpu_number > topo.max_cpu_num) {
|
||||||
|
warn("/proc/interrupts: cpu%d: > %d", cpu_number, topo.max_cpu_num);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_column_2_cpu[column] = cpu_number;
|
||||||
|
irqs_per_cpu[cpu_number] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read /proc/interrupt count lines and sum up irqs per cpu */
|
||||||
|
while (1) {
|
||||||
|
int column;
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
|
retval = fscanf(fp, " %s:", buf); /* flush irq# "N:" */
|
||||||
|
if (retval != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* read the count per cpu */
|
||||||
|
for (column = 0; column < topo.num_cpus; ++column) {
|
||||||
|
|
||||||
|
int cpu_number, irq_count;
|
||||||
|
|
||||||
|
retval = fscanf(fp, " %d", &irq_count);
|
||||||
|
if (retval != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
cpu_number = irq_column_2_cpu[column];
|
||||||
|
irqs_per_cpu[cpu_number] += irq_count;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
while (getc(fp) != '\n')
|
||||||
|
; /* flush interrupt description */
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* snapshot /proc and /sys files
|
||||||
|
*
|
||||||
|
* return 1 if configuration restart needed, else return 0
|
||||||
|
*/
|
||||||
|
int snapshot_proc_sysfs_files(void)
|
||||||
|
{
|
||||||
|
if (snapshot_proc_interrupts())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void turbostat_loop()
|
void turbostat_loop()
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -1745,6 +1847,7 @@ void turbostat_loop()
|
||||||
restart:
|
restart:
|
||||||
restarted++;
|
restarted++;
|
||||||
|
|
||||||
|
snapshot_proc_sysfs_files();
|
||||||
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
|
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
|
||||||
if (retval < -1) {
|
if (retval < -1) {
|
||||||
exit(retval);
|
exit(retval);
|
||||||
|
@ -1764,6 +1867,8 @@ restart:
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
nanosleep(&interval_ts, NULL);
|
nanosleep(&interval_ts, NULL);
|
||||||
|
if (snapshot_proc_sysfs_files())
|
||||||
|
goto restart;
|
||||||
retval = for_all_cpus(get_counters, ODD_COUNTERS);
|
retval = for_all_cpus(get_counters, ODD_COUNTERS);
|
||||||
if (retval < -1) {
|
if (retval < -1) {
|
||||||
exit(retval);
|
exit(retval);
|
||||||
|
@ -1778,6 +1883,8 @@ restart:
|
||||||
format_all_counters(EVEN_COUNTERS);
|
format_all_counters(EVEN_COUNTERS);
|
||||||
flush_output_stdout();
|
flush_output_stdout();
|
||||||
nanosleep(&interval_ts, NULL);
|
nanosleep(&interval_ts, NULL);
|
||||||
|
if (snapshot_proc_sysfs_files())
|
||||||
|
goto restart;
|
||||||
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
|
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
|
||||||
if (retval < -1) {
|
if (retval < -1) {
|
||||||
exit(retval);
|
exit(retval);
|
||||||
|
@ -3233,9 +3340,20 @@ void allocate_fd_percpu(void)
|
||||||
if (fd_percpu == NULL)
|
if (fd_percpu == NULL)
|
||||||
err(-1, "calloc fd_percpu");
|
err(-1, "calloc fd_percpu");
|
||||||
}
|
}
|
||||||
|
void allocate_irq_buffers(void)
|
||||||
|
{
|
||||||
|
irq_column_2_cpu = calloc(topo.num_cpus, sizeof(int));
|
||||||
|
if (irq_column_2_cpu == NULL)
|
||||||
|
err(-1, "calloc %d", topo.num_cpus);
|
||||||
|
|
||||||
|
irqs_per_cpu = calloc(topo.max_cpu_num, sizeof(int));
|
||||||
|
if (irqs_per_cpu == NULL)
|
||||||
|
err(-1, "calloc %d", topo.max_cpu_num);
|
||||||
|
}
|
||||||
void setup_all_buffers(void)
|
void setup_all_buffers(void)
|
||||||
{
|
{
|
||||||
topology_probe();
|
topology_probe();
|
||||||
|
allocate_irq_buffers();
|
||||||
allocate_fd_percpu();
|
allocate_fd_percpu();
|
||||||
allocate_counters(&thread_even, &core_even, &package_even);
|
allocate_counters(&thread_even, &core_even, &package_even);
|
||||||
allocate_counters(&thread_odd, &core_odd, &package_odd);
|
allocate_counters(&thread_odd, &core_odd, &package_odd);
|
||||||
|
|
Loading…
Reference in a new issue