]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
irqtop: add per-cpu stats
authorKarel Zak <kzak@redhat.com>
Wed, 24 Feb 2021 19:10:56 +0000 (20:10 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 24 Feb 2021 19:11:05 +0000 (20:11 +0100)
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>
sys-utils/irq-common.c
sys-utils/irq-common.h
sys-utils/irqtop.c

index dac2e546ea36a4ecc2e9a82c34fd7fb7f87052e8..79dce481e59836ea17c20739ed482788f577c2e0 100644 (file)
@@ -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,
index f296ad06fe961fa2bee1f3af55b1aa724f52f75c..5dbc652f6434a4c235d8645474ed8f203fdeb55b 100644 (file)
@@ -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 */
index ca37c368f661b4a3dbe78c50cd69d1dd2eb6914e..1a5cec0cc98073617e4cdb83a15bc1dfc5fbca87 100644 (file)
@@ -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);