On 2/27/25 17:41, zhenwei pi wrote: > Does the '--input IRQFILE' change? > > irqtop reads 'IRQFILE' and uses the current one to calculate the increment from the previous one, I'm curious about this case ... > > But I guess lsirq would work fine. Make sense, I'll remove this option from irqtop. Thanks, Joe > > On 2/27/25 12:49, Joe Jin wrote: >> This is helpful for analyzng data saved from other system. >> >> Signed-off-by: Joe Jin <joe.jin@xxxxxxxxxx> >> Cc: Zhenwei Pi <pizhenwei@xxxxxxxxxxxxx> >> Cc: Sami Kerola <kerolasa@xxxxxx> >> --- >> bash-completion/irqtop | 4 ++++ >> bash-completion/lsirq | 4 ++++ >> sys-utils/irq-common.c | 19 +++++++++---------- >> sys-utils/irq-common.h | 3 ++- >> sys-utils/irqtop.1.adoc | 3 +++ >> sys-utils/irqtop.c | 28 +++++++++++++++++++++++++--- >> sys-utils/lsirq.1.adoc | 3 +++ >> sys-utils/lsirq.c | 28 ++++++++++++++++++++++++---- >> 8 files changed, 74 insertions(+), 18 deletions(-) >> >> diff --git a/bash-completion/irqtop b/bash-completion/irqtop >> index 47b7b0af6..3bea5fc0e 100644 >> --- a/bash-completion/irqtop >> +++ b/bash-completion/irqtop >> @@ -15,6 +15,9 @@ _irqtop_module() >> '-C'|'--cpu-list') >> return 0 >> ;; >> + '-i'|'--input') >> + COMPREPLY=( $(compgen -W "input file" -- $cur) ) >> + ;; >> '-t'|'--threshold') >> return 0 >> ;; >> @@ -51,6 +54,7 @@ _irqtop_module() >> --cpu-stat >> --cpu-list >> --delay >> + --input >> --number >> --sort >> --output >> diff --git a/bash-completion/lsirq b/bash-completion/lsirq >> index 4c3c9f04f..b913eecd0 100644 >> --- a/bash-completion/lsirq >> +++ b/bash-completion/lsirq >> @@ -5,6 +5,9 @@ _lsirq_module() >> cur="${COMP_WORDS[COMP_CWORD]}" >> prev="${COMP_WORDS[COMP_CWORD-1]}" >> case $prev in >> + '-i'|'--input') >> + COMPREPLY=( $(compgen -W "input file" -- $cur) ) >> + ;; >> '-o'|'--output') >> local prefix realcur OUTPUT >> realcur="${cur##*,}" >> @@ -35,6 +38,7 @@ _lsirq_module() >> OPTS=" --json >> --pairs >> --noheadings >> + --input >> --output >> --softirq >> --sort >> diff --git a/sys-utils/irq-common.c b/sys-utils/irq-common.c >> index f069d8a63..560dd4b82 100644 >> --- a/sys-utils/irq-common.c >> +++ b/sys-utils/irq-common.c >> @@ -233,7 +233,8 @@ static bool cpu_in_list(int cpu, size_t setsize, cpu_set_t *cpuset) >> /* >> * irqinfo - parse the system's interrupts >> */ >> -static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpuset) >> +static struct irq_stat *get_irqinfo(const char *input_file, int softirq, >> + size_t setsize, cpu_set_t *cpuset) >> { >> FILE *irqfile; >> char *line = NULL, *tmp; >> @@ -247,18 +248,15 @@ static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpus >> stat->irq_info = xmalloc(sizeof(*stat->irq_info) * IRQ_INFO_LEN); >> stat->nr_irq_info = IRQ_INFO_LEN; >> - if (softirq) >> - irqfile = fopen(_PATH_PROC_SOFTIRQS, "r"); >> - else >> - irqfile = fopen(_PATH_PROC_INTERRUPTS, "r"); >> + irqfile = fopen(input_file, "r"); >> if (!irqfile) { >> - warn(_("cannot open %s"), _PATH_PROC_INTERRUPTS); >> + warn(_("cannot open %s"), input_file); >> goto free_stat; >> } >> /* read header firstly */ >> if (getline(&line, &len, irqfile) < 0) { >> - warn(_("cannot read %s"), _PATH_PROC_INTERRUPTS); >> + warn(_("cannot read %s"), input_file); >> goto close_file; >> } >> @@ -270,7 +268,7 @@ static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpus >> stat->cpus = xcalloc(stat->nr_active_cpu, sizeof(struct irq_cpu)); >> - /* parse each line of _PATH_PROC_INTERRUPTS */ >> + /* parse each line of input file */ >> while (getline(&line, &len, irqfile) >= 0) { >> unsigned long count; >> size_t index; >> @@ -527,7 +525,8 @@ struct libscols_table *get_scols_cpus_table(struct irq_output *out, >> return NULL; >> } >> -struct libscols_table *get_scols_table(struct irq_output *out, >> +struct libscols_table *get_scols_table(const char *input_file, >> + struct irq_output *out, >> struct irq_stat *prev, >> struct irq_stat **xstat, >> int softirq, >> @@ -542,7 +541,7 @@ struct libscols_table *get_scols_table(struct irq_output *out, >> size_t i; >> /* the stats */ >> - stat = get_irqinfo(softirq, setsize, cpuset); >> + stat = get_irqinfo(input_file, softirq, setsize, cpuset); >> if (!stat) >> return NULL; >> diff --git a/sys-utils/irq-common.h b/sys-utils/irq-common.h >> index 02b72d752..b9cf72d2a 100644 >> --- a/sys-utils/irq-common.h >> +++ b/sys-utils/irq-common.h >> @@ -73,7 +73,8 @@ void irq_print_columns(FILE *f, int nodelta); >> void set_sort_func_by_name(struct irq_output *out, const char *name); >> void set_sort_func_by_key(struct irq_output *out, const char c); >> -struct libscols_table *get_scols_table(struct irq_output *out, >> +struct libscols_table *get_scols_table(const char *input_file, >> + struct irq_output *out, >> struct irq_stat *prev, >> struct irq_stat **xstat, >> int softirq, >> diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc >> index 75cfe2e41..715008d07 100644 >> --- a/sys-utils/irqtop.1.adoc >> +++ b/sys-utils/irqtop.1.adoc >> @@ -37,6 +37,9 @@ Specify cpus in list format to show. >> *-d*, *--delay* _seconds_:: >> Update interrupt output every _seconds_ intervals. >> +*-i*, *--input* _file_:: >> +Read data from _file_ (Which was created by other tools, e.g. sosreport). >> + >> *-n*, *--number* _number_:: >> Specifies the maximum _number_ of iterations before quitting. >> diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c >> index ba5680671..4cf1dc79a 100644 >> --- a/sys-utils/irqtop.c >> +++ b/sys-utils/irqtop.c >> @@ -87,6 +87,8 @@ struct irqtop_ctl { >> bool batch; >> bool request_exit, >> softirq; >> + >> + char *input; >> }; >> #define irqtop_batch_mode(ctl) ((ctl)->batch == true) >> @@ -122,8 +124,9 @@ 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, >> - ctl->threshold, ctl->setsize, ctl->cpuset); >> + table = get_scols_table(ctl->input, out, ctl->prev_stat, &stat, >> + ctl->softirq, ctl->threshold, ctl->setsize, >> + ctl->cpuset); >> if (!table) { >> ctl->request_exit = 1; >> return 1; >> @@ -292,6 +295,7 @@ static void __attribute__((__noreturn__)) usage(void) >> 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(_(" -i, --input <file> read data from file\n"), stdout); >> fputs(_(" -n, --number <number> the maximum number of iterations\n"), stdout); >> fputs(_(" -o, --output <list> define which output columns to use\n"), stdout); >> fputs(_(" -s, --sort <column> specify sort column\n"), stdout); >> @@ -325,6 +329,7 @@ static void parse_args( struct irqtop_ctl *ctl, >> {"cpu-stat", required_argument, NULL, 'c'}, >> {"cpu-list", required_argument, NULL, 'C'}, >> {"delay", required_argument, NULL, 'd'}, >> + {"input", required_argument, NULL, 'i'}, >> {"number", required_argument, NULL, 'n'}, >> {"sort", required_argument, NULL, 's'}, >> {"output", required_argument, NULL, 'o'}, >> @@ -336,7 +341,7 @@ static void parse_args( struct irqtop_ctl *ctl, >> }; >> int o; >> - while ((o = getopt_long(argc, argv, "bc:C:d:n:o:s:St:hV", longopts, NULL)) != -1) { >> + while ((o = getopt_long(argc, argv, "bc:C:d:i:n:o:s:St:hV", longopts, NULL)) != -1) { >> switch (o) { >> case 'b': >> ctl->batch = true; >> @@ -376,6 +381,13 @@ static void parse_args( struct irqtop_ctl *ctl, >> ctl->timer.it_value = ctl->timer.it_interval; >> } >> break; >> + case 'i': >> + ctl->input = strdup(optarg); >> + if (!ctl->input) >> + err_oom(); >> + ctl->number = 1; >> + ctl->batch = true; >> + break; >> case 'n': >> ctl->number = str2num_or_err(optarg, 10, >> _("failed to parse number argument"), >> @@ -402,6 +414,15 @@ static void parse_args( struct irqtop_ctl *ctl, >> } >> } >> + if (ctl->input == NULL) { >> + if (ctl->softirq == 1) >> + ctl->input = strdup(_PATH_PROC_SOFTIRQS); >> + else >> + ctl->input = strdup(_PATH_PROC_INTERRUPTS); >> + if (!ctl->input) >> + err_oom(); >> + } >> + >> /* default */ >> if (!out->ncolumns) { >> out->columns[out->ncolumns++] = COL_IRQ; >> @@ -453,6 +474,7 @@ int main(int argc, char **argv) >> free_irqstat(ctl.prev_stat); >> free(ctl.hostname); >> + free(ctl.input); >> cpuset_free(ctl.cpuset); >> if (ctl.batch == false) { >> diff --git a/sys-utils/lsirq.1.adoc b/sys-utils/lsirq.1.adoc >> index 02aea16b3..dd265710c 100644 >> --- a/sys-utils/lsirq.1.adoc >> +++ b/sys-utils/lsirq.1.adoc >> @@ -25,6 +25,9 @@ The default output is subject to change. So whenever possible, you should avoid >> *-n*, *--noheadings*:: >> Don't print headings. >> +*-i*, *--input* _file_:: >> +Read data from _file_ (Which was created by other tools, e.g. sosreport). >> + >> *-o*, *--output* _list_:: >> Specify which output columns to print. Use *--help* to get a list of all supported columns. The default list of columns may be extended if list is specified in the format _+list_. >> diff --git a/sys-utils/lsirq.c b/sys-utils/lsirq.c >> index e31addaf5..45d542919 100644 >> --- a/sys-utils/lsirq.c >> +++ b/sys-utils/lsirq.c >> @@ -29,16 +29,17 @@ >> #include "optutils.h" >> #include "strutils.h" >> #include "xalloc.h" >> +#include "pathnames.h" >> #include "irq-common.h" >> -static int print_irq_data(struct irq_output *out, >> +static int print_irq_data(const char *input_file, struct irq_output *out, >> int softirq, unsigned long threshold, >> size_t setsize, cpu_set_t *cpuset) >> { >> struct libscols_table *table; >> - table = get_scols_table(out, NULL, NULL, softirq, threshold, setsize, cpuset); >> + table = get_scols_table(input_file, out, NULL, NULL, softirq, threshold, setsize, cpuset); >> if (!table) >> return -1; >> @@ -58,6 +59,7 @@ static void __attribute__((__noreturn__)) usage(void) >> fputs(USAGE_OPTIONS, stdout); >> fputs(_(" -J, --json use JSON output format\n"), stdout); >> fputs(_(" -P, --pairs use key=\"value\" output format\n"), stdout); >> + fputs(_(" -i, --input read data from input file\n"), stdout); >> fputs(_(" -n, --noheadings don't print headings\n"), stdout); >> fputs(_(" -o, --output <list> define which output columns to use\n"), stdout); >> fputs(_(" -s, --sort <column> specify sort column\n"), stdout); >> @@ -82,6 +84,7 @@ int main(int argc, char **argv) >> static const struct option longopts[] = { >> {"sort", required_argument, NULL, 's'}, >> {"noheadings", no_argument, NULL, 'n'}, >> + {"input", required_argument, NULL, 'i'}, >> {"output", required_argument, NULL, 'o'}, >> {"threshold", required_argument, NULL, 't'}, >> {"cpu-list", required_argument, NULL, 'C'}, >> @@ -103,10 +106,11 @@ int main(int argc, char **argv) >> cpu_set_t *cpuset = NULL; >> size_t setsize = 0; >> int softirq = 0; >> + char *input = NULL; >> setlocale(LC_ALL, ""); >> - while ((c = getopt_long(argc, argv, "no:s:t:C:ShJPV", longopts, NULL)) != -1) { >> + while ((c = getopt_long(argc, argv, "i:no:s:t:C:ShJPV", longopts, NULL)) != -1) { >> err_exclusive_options(c, longopts, excl, excl_st); >> switch (c) { >> @@ -116,6 +120,11 @@ int main(int argc, char **argv) >> case 'P': >> out.pairs = 1; >> break; >> + case 'i': >> + input = strdup(optarg); >> + if (!input) >> + err_oom(); >> + break; >> case 'n': >> out.no_headings = 1; >> break; >> @@ -157,6 +166,15 @@ int main(int argc, char **argv) >> } >> } >> + if (input == NULL) { >> + if (softirq == 1) >> + input = strdup(_PATH_PROC_SOFTIRQS); >> + else >> + input = strdup(_PATH_PROC_INTERRUPTS); >> + if (!input) >> + err_oom(); >> + } >> + >> /* default */ >> if (!out.ncolumns) { >> out.columns[out.ncolumns++] = COL_IRQ; >> @@ -171,8 +189,10 @@ int main(int argc, char **argv) >> irq_column_name_to_id) < 0) >> exit(EXIT_FAILURE); >> - if (print_irq_data(&out, softirq, threshold, setsize, cpuset) < 0) >> + if (print_irq_data(input, &out, softirq, threshold, setsize, cpuset) < 0) >> return EXIT_FAILURE; >> + free(input); >> + >> return EXIT_SUCCESS; >> } >