Specify cpus list format to show by -C/--cpu-list parameters, for example, on an AMD server with 192 CPUs, to show statistics on NUMA node 1: ~# ./irqtop -d 1 -C 48-95,144-191 Signed-off-by: zhenwei pi <pizhenwei@xxxxxxxxxxxxx> --- bash-completion/irqtop | 4 ++++ sys-utils/irq-common.c | 46 ++++++++++++++++++++++++++++++----------- sys-utils/irq-common.h | 9 ++++++-- sys-utils/irqtop.1.adoc | 3 +++ sys-utils/irqtop.c | 29 +++++++++++++++++++++++--- sys-utils/lsirq.c | 2 +- 6 files changed, 75 insertions(+), 18 deletions(-) diff --git a/bash-completion/irqtop b/bash-completion/irqtop index a3812acbb..7688f673c 100644 --- a/bash-completion/irqtop +++ b/bash-completion/irqtop @@ -9,6 +9,9 @@ _irqtop_module() COMPREPLY=( $(compgen -W "auto enable disable" -- $cur) ) return 0 ;; + '-C'|'--cpu-list') + return 0 + ;; '-d'|'--delay') COMPREPLY=( $(compgen -W "secs" -- $cur) ) return 0 @@ -35,6 +38,7 @@ _irqtop_module() ;; esac OPTS=" --cpu-stat + --cpu-list --delay --sort --output diff --git a/sys-utils/irq-common.c b/sys-utils/irq-common.c index aa10f7e05..1bdcfad31 100644 --- a/sys-utils/irq-common.c +++ b/sys-utils/irq-common.c @@ -23,6 +23,7 @@ #include <errno.h> #include <limits.h> #include <locale.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -228,10 +229,19 @@ static char *remove_repeated_spaces(char *str) return str; } +static bool cpu_in_list(int cpu, size_t setsize, cpu_set_t *cpuset) +{ + /* no -C/--cpu-list specified, use all the CPUs */ + if (!cpuset) + return true; + + return CPU_ISSET_S(cpu, setsize, cpuset); +} + /* * irqinfo - parse the system's interrupts */ -static struct irq_stat *get_irqinfo(int softirq) +static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpuset) { FILE *irqfile; char *line = NULL, *tmp; @@ -292,9 +302,11 @@ static struct irq_stat *get_irqinfo(int softirq) if (sscanf(tmp, " %10lu", &count) != 1) continue; - curr->total += count; - cpu->total += count; - stat->total_irq += count; + if (cpu_in_list(index, setsize, cpuset)) { + curr->total += count; + cpu->total += count; + stat->total_irq += count; + } tmp += 11; } @@ -422,13 +434,15 @@ 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 irq_stat *curr, + size_t setsize, + cpu_set_t *cpuset) { struct libscols_table *table; struct libscols_column *cl; struct libscols_line *ln; char colname[sizeof(stringify_value(LONG_MAX))]; - size_t i; + size_t i, j; if (prev) { for (i = 0; i < curr->nr_active_cpu; i++) { @@ -454,6 +468,8 @@ struct libscols_table *get_scols_cpus_table(struct irq_output *out, scols_table_new_column(table, "", 0, SCOLS_FL_RIGHT); for (i = 0; i < curr->nr_active_cpu; i++) { + if (!cpu_in_list(i, setsize, cpuset)) + continue; snprintf(colname, sizeof(colname), "cpu%zu", i); cl = scols_table_new_column(table, colname, 0, SCOLS_FL_RIGHT); if (cl == NULL) { @@ -469,12 +485,14 @@ struct libscols_table *get_scols_cpus_table(struct irq_output *out, if (!ln || (!out->json && scols_line_set_data(ln, 0, "%irq:") != 0)) goto err; - for (i = 0; i < curr->nr_active_cpu; i++) { + for (i = 0, j = 0; i < curr->nr_active_cpu; i++) { struct irq_cpu *cpu = &curr->cpus[i]; char *str; + if (!cpu_in_list(i, setsize, cpuset)) + continue; 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) + if (str && scols_line_refer_data(ln, ++j, str) != 0) goto err; } @@ -484,14 +502,16 @@ struct libscols_table *get_scols_cpus_table(struct irq_output *out, if (!ln || (!out->json && scols_line_set_data(ln, 0, _("%delta:")) != 0)) goto err; - for (i = 0; i < curr->nr_active_cpu; i++) { + for (i = 0, j = 0; i < curr->nr_active_cpu; i++) { struct irq_cpu *cpu = &curr->cpus[i]; char *str; + if (!cpu_in_list(i, setsize, cpuset)) + continue; 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) + if (str && scols_line_refer_data(ln, ++j, str) != 0) goto err; } @@ -504,7 +524,9 @@ struct libscols_table *get_scols_cpus_table(struct irq_output *out, struct libscols_table *get_scols_table(struct irq_output *out, struct irq_stat *prev, struct irq_stat **xstat, - int softirq) + int softirq, + size_t setsize, + cpu_set_t *cpuset) { struct libscols_table *table; struct irq_info *result; @@ -513,7 +535,7 @@ struct libscols_table *get_scols_table(struct irq_output *out, size_t i; /* the stats */ - stat = get_irqinfo(softirq); + stat = get_irqinfo(softirq, setsize, cpuset); if (!stat) return NULL; diff --git a/sys-utils/irq-common.h b/sys-utils/irq-common.h index c4f1fa3a2..04c43207e 100644 --- a/sys-utils/irq-common.h +++ b/sys-utils/irq-common.h @@ -3,6 +3,7 @@ #include "c.h" #include "nls.h" +#include "cpuset.h" /* supported columns */ enum { @@ -63,10 +64,14 @@ void set_sort_func_by_key(struct irq_output *out, const char c); struct libscols_table *get_scols_table(struct irq_output *out, struct irq_stat *prev, struct irq_stat **xstat, - int softirq); + int softirq, + size_t setsize, + cpu_set_t *cpuset); struct libscols_table *get_scols_cpus_table(struct irq_output *out, struct irq_stat *prev, - struct irq_stat *curr); + struct irq_stat *curr, + size_t setsize, + cpu_set_t *cpuset); #endif /* UTIL_LINUX_H_IRQ_COMMON */ diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc index 3f215d2f0..a310ded9d 100644 --- a/sys-utils/irqtop.1.adoc +++ b/sys-utils/irqtop.1.adoc @@ -28,6 +28,9 @@ Specify which output columns to print. Use *--help* to get a list of all support *-c*, *--cpu-stat* _mode_:: Show per-cpu statistics by specified mode. Available modes are: *auto*, *enable*, *disable*. The default option *auto* detects the width of window, then shows the per-cpu statistics if the width of window is large enouth to show a full line of statistics. +*-C*, *--cpu-list* _list_:: +Specify cpus in list format to show. + *-d*, *--delay* _seconds_:: Update interrupt output every _seconds_ intervals. diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c index adf75591b..eb0e6bc66 100644 --- a/sys-utils/irqtop.c +++ b/sys-utils/irqtop.c @@ -57,6 +57,7 @@ #include <libsmartcols.h> #include "closestream.h" +#include "cpuset.h" #include "monotonic.h" #include "pathnames.h" #include "strutils.h" @@ -83,6 +84,8 @@ struct irqtop_ctl { struct itimerspec timer; struct irq_stat *prev_stat; + size_t setsize; + cpu_set_t *cpuset; enum irqtop_cpustat_mode cpustat_mode; unsigned int request_exit:1; @@ -111,7 +114,8 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out) char timestr[64], *data, *data0, *p; /* make irqs table */ - table = get_scols_table(out, ctl->prev_stat, &stat, ctl->softirq); + table = get_scols_table(out, ctl->prev_stat, &stat, ctl->softirq, ctl->setsize, + ctl->cpuset); if (!table) { ctl->request_exit = 1; return 1; @@ -122,7 +126,8 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out) /* make cpus table */ if (ctl->cpustat_mode != IRQTOP_CPUSTAT_DISABLE) { - cpus = get_scols_cpus_table(out, ctl->prev_stat, stat); + cpus = get_scols_cpus_table(out, ctl->prev_stat, stat, ctl->setsize, + ctl->cpuset); scols_table_reduce_termwidth(cpus, 1); if (ctl->cpustat_mode == IRQTOP_CPUSTAT_AUTO) scols_table_enable_nowrap(cpus, 1); @@ -261,6 +266,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(USAGE_OPTIONS, stdout); fputs(_(" -c, --cpu-stat <mode> show per-cpu stat (auto, enable, disable)\n"), stdout); + fputs(_(" -C, --cpu-list <list> specify cpus in list format\n"), stdout); fputs(_(" -d, --delay <secs> delay updates\n"), stdout); fputs(_(" -o, --output <list> define which output columns to use\n"), stdout); fputs(_(" -s, --sort <column> specify sort column\n"), stdout); @@ -290,6 +296,7 @@ static void parse_args( struct irqtop_ctl *ctl, const char *outarg = NULL; static const struct option longopts[] = { {"cpu-stat", required_argument, NULL, 'c'}, + {"cpu-list", required_argument, NULL, 'C'}, {"delay", required_argument, NULL, 'd'}, {"sort", required_argument, NULL, 's'}, {"output", required_argument, NULL, 'o'}, @@ -300,7 +307,7 @@ static void parse_args( struct irqtop_ctl *ctl, }; int o; - while ((o = getopt_long(argc, argv, "c:d:o:s:ShV", longopts, NULL)) != -1) { + while ((o = getopt_long(argc, argv, "c:C:d:o:s:ShV", longopts, NULL)) != -1) { switch (o) { case 'c': if (!strcmp(optarg, "auto")) @@ -312,6 +319,21 @@ static void parse_args( struct irqtop_ctl *ctl, else errx(EXIT_FAILURE, _("unsupported mode '%s'"), optarg); break; + case 'C': + { + int ncpus = get_max_number_of_cpus(); + if (ncpus <= 0) + errx(EXIT_FAILURE, _("cannot determine NR_CPUS; aborting")); + + ctl->cpuset = cpuset_alloc(ncpus, &ctl->setsize, NULL); + if (!ctl->cpuset) + err(EXIT_FAILURE, _("cpuset_alloc failed")); + + if (cpulist_parse(optarg, ctl->cpuset, ctl->setsize, 0)) + errx(EXIT_FAILURE, _("failed to parse CPU list: %s"), + optarg); + } + break; case 'd': { struct timeval delay; @@ -388,6 +410,7 @@ int main(int argc, char **argv) free_irqstat(ctl.prev_stat); free(ctl.hostname); + cpuset_free(ctl.cpuset); if (is_tty) tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty); diff --git a/sys-utils/lsirq.c b/sys-utils/lsirq.c index 1a90efe21..375476dca 100644 --- a/sys-utils/lsirq.c +++ b/sys-utils/lsirq.c @@ -42,7 +42,7 @@ static int print_irq_data(struct irq_output *out, int softirq) { struct libscols_table *table; - table = get_scols_table(out, NULL, NULL, softirq); + table = get_scols_table(out, NULL, NULL, softirq, 0, NULL); if (!table) return -1; -- 2.25.1