irqtop: add per-cpu stats
irqtop | total: 1245107402 delta: 7394 | ws.net.home | 2021-02-24 20:11:09+01:00 cpu0 cpu1 cpu2 cpu3 cpu4 cpu5 cpu6 cpu7 %irq: 12.9 13.0 12.8 11.9 12.4 13.4 11.6 12.0 %delta: 13.7 9.7 22.6 7.9 9.5 17.5 8.3 10.8 IRQ TOTAL DELTA NAME LOC 989162414 6111 Local timer interrupts TLB 100492740 67 TLB shootdowns CAL 95058001 321 Function call interrupts 42 23893801 241 IR-PCI-MSI 1048576-edge nvidia 30 20209392 494 IR-PCI-MSI 327680-edge xhci_hcd RES 12996335 86 Rescheduling interrupts 29 1354219 4 IR-PCI-MSI 512000-edge ahci[0000:00:1f.2] 41 682653 31 IR-PCI-MSI 409600-edge eno1 ... Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
1b889dcc07
commit
a23aecc1bf
|
@ -143,7 +143,7 @@ static struct libscols_table *new_scols_table(struct irq_output *out)
|
|||
scols_table_enable_export(table, out->pairs);
|
||||
|
||||
if (out->json)
|
||||
scols_table_set_name(table, _("interrupts"));
|
||||
scols_table_set_name(table, "interrupts");
|
||||
|
||||
for (i = 0; i < out->ncolumns; i++) {
|
||||
const struct colinfo *col = get_column_info(out, i);
|
||||
|
@ -262,10 +262,13 @@ static struct irq_stat *get_irqinfo(int softirq)
|
|||
stat->nr_active_cpu++;
|
||||
}
|
||||
|
||||
stat->cpus = xcalloc(stat->nr_active_cpu, sizeof(struct irq_cpu));
|
||||
|
||||
/* parse each line of _PATH_PROC_INTERRUPTS */
|
||||
while (getline(&line, &len, irqfile) >= 0) {
|
||||
unsigned long count;
|
||||
int index, length;
|
||||
size_t index;
|
||||
int length;
|
||||
|
||||
tmp = strchr(line, ':');
|
||||
if (!tmp)
|
||||
|
@ -281,9 +284,13 @@ static struct irq_stat *get_irqinfo(int softirq)
|
|||
|
||||
tmp += 1;
|
||||
for (index = 0; (index < stat->nr_active_cpu) && (tmp - line < length); index++) {
|
||||
struct irq_cpu *cpu = &stat->cpus[index];
|
||||
|
||||
sscanf(tmp, " %10lu", &count);
|
||||
curr->total += count;
|
||||
cpu->total += count;
|
||||
stat->total_irq += count;
|
||||
|
||||
tmp += 11;
|
||||
}
|
||||
|
||||
|
@ -316,6 +323,7 @@ static struct irq_stat *get_irqinfo(int softirq)
|
|||
fclose(irqfile);
|
||||
free_stat:
|
||||
free(stat->irq_info);
|
||||
free(stat->cpus);
|
||||
free(stat);
|
||||
free(line);
|
||||
return NULL;
|
||||
|
@ -334,6 +342,7 @@ void free_irqstat(struct irq_stat *stat)
|
|||
}
|
||||
|
||||
free(stat->irq_info);
|
||||
free(stat->cpus);
|
||||
free(stat);
|
||||
}
|
||||
|
||||
|
@ -406,6 +415,94 @@ void set_sort_func_by_key(struct irq_output *out, char c)
|
|||
}
|
||||
}
|
||||
|
||||
struct libscols_table *get_scols_cpus_table(struct irq_output *out,
|
||||
struct irq_stat *prev,
|
||||
struct irq_stat *curr)
|
||||
{
|
||||
struct libscols_table *table;
|
||||
struct libscols_column *cl;
|
||||
struct libscols_line *ln;
|
||||
char colname[sizeof(stringify_value(LONG_MAX))];
|
||||
size_t i;
|
||||
|
||||
if (prev) {
|
||||
for (i = 0; i < curr->nr_active_cpu; i++) {
|
||||
struct irq_cpu *pre = &prev->cpus[i];
|
||||
struct irq_cpu *cur = &curr->cpus[i];
|
||||
|
||||
cur->delta = cur->total - pre->total;
|
||||
}
|
||||
}
|
||||
|
||||
table = scols_new_table();
|
||||
if (!table) {
|
||||
warn(_("failed to initialize output table"));
|
||||
return NULL;
|
||||
}
|
||||
scols_table_enable_json(table, out->json);
|
||||
scols_table_enable_noheadings(table, out->no_headings);
|
||||
scols_table_enable_export(table, out->pairs);
|
||||
|
||||
if (out->json)
|
||||
scols_table_set_name(table, _("cpu-interrupts"));
|
||||
else
|
||||
scols_table_new_column(table, "", 0, SCOLS_FL_RIGHT);
|
||||
|
||||
for (i = 0; i < curr->nr_active_cpu; i++) {
|
||||
snprintf(colname, sizeof(colname), "cpu%zu", i);
|
||||
cl = scols_table_new_column(table, colname, 0, SCOLS_FL_RIGHT);
|
||||
if (cl == NULL) {
|
||||
warnx(_("failed to initialize output column"));
|
||||
goto err;
|
||||
}
|
||||
if (out->json)
|
||||
scols_column_set_json_type(cl, SCOLS_JSON_STRING);
|
||||
}
|
||||
|
||||
/* per cpu % of total */
|
||||
ln = scols_table_new_line(table, NULL);
|
||||
if (!ln) {
|
||||
warn(_("failed to add line to output"));
|
||||
goto err;
|
||||
}
|
||||
if (!out->json)
|
||||
scols_line_set_data(ln, 0, "%irq:");
|
||||
|
||||
for (i = 0; i < curr->nr_active_cpu; i++) {
|
||||
struct irq_cpu *cpu = &curr->cpus[i];
|
||||
char *str;
|
||||
|
||||
xasprintf(&str, "%0.1f", (double)((long double) cpu->total / (long double) curr->total_irq * 100.0));
|
||||
if (str && scols_line_refer_data(ln, i + 1, str) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* per cpu % of delta */
|
||||
ln = scols_table_new_line(table, NULL);
|
||||
if (!ln) {
|
||||
warn(_("failed to add line to output"));
|
||||
goto err;
|
||||
}
|
||||
if (!out->json)
|
||||
scols_line_set_data(ln, 0, "%delta:");
|
||||
|
||||
for (i = 0; i < curr->nr_active_cpu; i++) {
|
||||
struct irq_cpu *cpu = &curr->cpus[i];
|
||||
char *str;
|
||||
|
||||
if (!curr->delta_irq)
|
||||
continue;
|
||||
xasprintf(&str, "%0.1f", (double)((long double) cpu->delta / (long double) curr->delta_irq * 100.0));
|
||||
if (str && scols_line_refer_data(ln, i + 1, str) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return table;
|
||||
err:
|
||||
scols_unref_table(table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct libscols_table *get_scols_table(struct irq_output *out,
|
||||
struct irq_stat *prev,
|
||||
struct irq_stat **xstat,
|
||||
|
|
|
@ -21,16 +21,22 @@ struct irq_info {
|
|||
unsigned long delta; /* delta count since previous update */
|
||||
};
|
||||
|
||||
struct irq_cpu {
|
||||
unsigned long total;
|
||||
unsigned long delta;
|
||||
};
|
||||
|
||||
struct irq_stat {
|
||||
unsigned int nr_irq; /* number of irq vector */
|
||||
unsigned int nr_irq_info; /* number of irq info */
|
||||
struct irq_info *irq_info; /* array of irq_info */
|
||||
long nr_active_cpu; /* number of active cpu */
|
||||
struct irq_cpu *cpus; /* array of irq_cpu */
|
||||
size_t nr_active_cpu; /* number of active cpu */
|
||||
unsigned long total_irq; /* total irqs */
|
||||
unsigned long delta_irq; /* delta irqs */
|
||||
};
|
||||
|
||||
|
||||
typedef int (irq_cmp_t)(const struct irq_info *, const struct irq_info *);
|
||||
|
||||
/* output definition */
|
||||
|
@ -59,4 +65,8 @@ struct libscols_table *get_scols_table(struct irq_output *out,
|
|||
struct irq_stat **xstat,
|
||||
int softirq);
|
||||
|
||||
struct libscols_table *get_scols_cpus_table(struct irq_output *out,
|
||||
struct irq_stat *prev,
|
||||
struct irq_stat *curr);
|
||||
|
||||
#endif /* UTIL_LINUX_H_IRQ_COMMON */
|
||||
|
|
|
@ -98,33 +98,43 @@ static void parse_input(struct irqtop_ctl *ctl, struct irq_output *out, char c)
|
|||
|
||||
static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
|
||||
{
|
||||
struct libscols_table *table;
|
||||
struct libscols_table *table, *cpus;
|
||||
struct irq_stat *stat;
|
||||
time_t now = time(NULL);
|
||||
char timestr[64], *data, *data0, *p;
|
||||
|
||||
/* make irqs table */
|
||||
table = get_scols_table(out, ctl->prev_stat, &stat, ctl->softirq);
|
||||
if (!table) {
|
||||
ctl->request_exit = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
scols_table_enable_maxout(table, 1);
|
||||
scols_table_enable_nowrap(table, 1);
|
||||
scols_table_reduce_termwidth(table, 1);
|
||||
|
||||
/* header in interactive mode */
|
||||
/* make cpus table */
|
||||
cpus = get_scols_cpus_table(out, ctl->prev_stat, stat);
|
||||
scols_table_reduce_termwidth(cpus, 1);
|
||||
|
||||
/* print header */
|
||||
move(0, 0);
|
||||
strtime_iso(&now, ISO_TIMESTAMP, timestr, sizeof(timestr));
|
||||
wprintw(ctl->win, _("irqtop | total: %ld delta: %ld | %s | %s\n\n"),
|
||||
stat->total_irq, stat->delta_irq, ctl->hostname, timestr);
|
||||
|
||||
/* print cpus table */
|
||||
scols_print_table_to_string(cpus, &data);
|
||||
wprintw(ctl->win, "%s\n\n", data);
|
||||
free(data);
|
||||
|
||||
/* print irqs table */
|
||||
scols_print_table_to_string(table, &data0);
|
||||
data = data0;
|
||||
|
||||
/* print header in reverse mode */
|
||||
p = strchr(data, '\n');
|
||||
if (p) {
|
||||
/* print header in reverse mode */
|
||||
*p = '\0';
|
||||
attron(A_REVERSE);
|
||||
wprintw(ctl->win, "%s\n", data);
|
||||
|
|
Loading…
Reference in New Issue