Re: [PATCH 1/3] irqtop: add batch mode support

zhenwei pi
2025-02-28T01:34:26Z

Hi Joe,

I'm a little confused about 'batch'...

Rather than the original terminal formatted style, the new change brings
'raw' style?

What about 'raw'? Hi Karel, what do you think of this?

On 2/27/25 12:49, Joe Jin wrote:
> Add batch mode support, which could be useful for sending output to
> other programs or to a file.
>
> Signed-off-by: Joe Jin <joe.jin@oracle.com>
> Cc: Zhenwei Pi <pizhenwei@bytedance.com>
> Cc: Sami Kerola <kerolasa@iki.fi>
> ---
> bash-completion/irqtop | 6 +++-
> sys-utils/irqtop.1.adoc | 3 ++
> sys-utils/irqtop.c | 79 ++++++++++++++++++++++++++++-------------
> 3 files changed, 63 insertions(+), 25 deletions(-)
>
> diff --git a/bash-completion/irqtop b/bash-completion/irqtop
> index b9e454d4c..215281ee8 100644
> --- a/bash-completion/irqtop
> +++ b/bash-completion/irqtop
> @@ -5,6 +5,9 @@ _irqtop_module()
> cur="${COMP_WORDS[COMP_CWORD]}"
> prev="${COMP_WORDS[COMP_CWORD-1]}"
> case $prev in
> + '-b'|'--batch')
> + return 0
> + ;;
> '-c'|'--cpu-stat')
> COMPREPLY=( $(compgen -W "auto enable disable" -- $cur) )
> return 0
> @@ -40,7 +43,8 @@ _irqtop_module()
> return 0
> ;;
> esac
> - OPTS=" --cpu-stat
> + OPTS=" --batch
> + --cpu-stat
> --cpu-list
> --delay
> --sort
> diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc
> index 443e23b84..e81f4fbb6 100644
> --- a/sys-utils/irqtop.1.adoc
> +++ b/sys-utils/irqtop.1.adoc
> @@ -25,6 +25,9 @@ The default output is subject to change. So whenever possible, you should avoid
> *-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_.
>
> +*-b*, *--batch*::
> +Starts irqtop in batch mode, which could be useful for sending output to other programs or to a file.
> +
> *-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 enough to show a full line of statistics.
>
> diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c
> index 8fbedb16a..00bf8fe50 100644
> --- a/sys-utils/irqtop.c
> +++ b/sys-utils/irqtop.c
> @@ -83,10 +83,22 @@ struct irqtop_ctl {
> cpu_set_t *cpuset;
>
> enum irqtop_cpustat_mode cpustat_mode;
> + bool batch;
> bool request_exit,
> softirq;
> };
>
> +#define irqtop_batch_mode(ctl) ((ctl)->batch == true)
> +#define irqtop_printf(ctl, fmt, args...) \
> + do { \
> + if (irqtop_batch_mode(ctl)) \
> + fprintf(stdout, fmt, ##args); \
> + else { \
> + wprintw(ctl->win, fmt, ##args); \
> + } \
> + }while(0)
> +
> +
> /* user's input parser */
> static void parse_input(struct irqtop_ctl *ctl, struct irq_output *out, char c)
> {
> @@ -128,16 +140,19 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
> scols_table_enable_nowrap(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"),
> + if (!irqtop_batch_mode(ctl))
> + move(0, 0);
> +
> + /* print header */
> + irqtop_printf(ctl, _("irqtop | total: %ld delta: %ld | %s | %s\n\n"),
> stat->total_irq, stat->delta_irq, ctl->hostname, timestr);
>
> +
> /* print cpus table or not by -c option */
> if (cpus) {
> scols_print_table_to_string(cpus, &data);
> - wprintw(ctl->win, "%s\n\n", data);
> + irqtop_printf(ctl, "%s\n\n", data);
> free(data);
> }
>
> @@ -149,13 +164,15 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
> if (p) {
> /* print header in reverse mode */
> *p = '\0';
> - attron(A_REVERSE);
> - wprintw(ctl->win, "%s\n", data);
> - attroff(A_REVERSE);
> + if (!irqtop_batch_mode(ctl))
> + attron(A_REVERSE);
> + irqtop_printf(ctl, "%s\n", data);
> + if (!irqtop_batch_mode(ctl))
> + attroff(A_REVERSE);
> data = p + 1;
> }
>
> - wprintw(ctl->win, "%s", data);
> + irqtop_printf(ctl, "%s\n", data);
> free(data0);
>
> /* clean up */
> @@ -212,7 +229,8 @@ static int event_loop(struct irqtop_ctl *ctl, struct irq_output *out)
> err(EXIT_FAILURE, _("epoll_ctl failed"));
>
> retval |= update_screen(ctl, out);
> - refresh();
> + if (!irqtop_batch_mode(ctl))
> + refresh();
>
> while (!ctl->request_exit) {
> const ssize_t nr_events = epoll_wait(efd, events, MAX_EVENTS, -1);
> @@ -227,10 +245,12 @@ static int event_loop(struct irqtop_ctl *ctl, struct irq_output *out)
> continue;
> }
> if (siginfo.ssi_signo == SIGWINCH) {
> - get_terminal_dimension(&ctl->cols, &ctl->rows);
> + if (!irqtop_batch_mode(ctl)) {
> + get_terminal_dimension(&ctl->cols, &ctl->rows);
> #if HAVE_RESIZETERM
> - resizeterm(ctl->rows, ctl->cols);
> + resizeterm(ctl->rows, ctl->cols);
> #endif
> + }
> }
> else {
> ctl->request_exit = 1;
> @@ -245,7 +265,8 @@ static int event_loop(struct irqtop_ctl *ctl, struct irq_output *out)
> } else
> abort();
> retval |= update_screen(ctl, out);
> - refresh();
> + if (!irqtop_batch_mode(ctl))
> + refresh();
> }
> }
> return retval;
> @@ -260,6 +281,7 @@ static void __attribute__((__noreturn__)) usage(void)
> puts(_("Interactive utility to display kernel interrupt information."));
>
> fputs(USAGE_OPTIONS, stdout);
> + fputs(_(" -b, --batch batch mode\n"), stdout);
> fputs(_(" -c, --cpu-stat <mode> show per-cpu stat (auto, enable, disable)\n"), stdout);
> fputs(_(" -C, --cpu-list specify cpus in list format\n"), stdout);
> fputs(_(" -d, --delay <secs> delay updates\n"), stdout);
> @@ -291,6 +313,7 @@ static void parse_args( struct irqtop_ctl *ctl,
> {
> const char *outarg = NULL;
> static const struct option longopts[] = {
> + {"batch", no_argument, NULL, 'b'},
> {"cpu-stat", required_argument, NULL, 'c'},
> {"cpu-list", required_argument, NULL, 'C'},
> {"delay", required_argument, NULL, 'd'},
> @@ -304,8 +327,11 @@ static void parse_args( struct irqtop_ctl *ctl,
> };
> int o;
>
> - while ((o = getopt_long(argc, argv, "c:C:d:o:s:St:hV", longopts, NULL)) != -1) {
> + while ((o = getopt_long(argc, argv, "bc:C:d:o:s:St:hV", longopts, NULL)) != -1) {
> switch (o) {
> + case 'b':
> + ctl->batch = true;
> + break;
> case 'c':
> if (!strcmp(optarg, "auto"))
> ctl->cpustat_mode = IRQTOP_CPUSTAT_AUTO;
> @@ -394,16 +420,18 @@ int main(int argc, char **argv)
>
> parse_args(&ctl, &out, argc, argv);
>
> - is_tty = isatty(STDIN_FILENO);
> - if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
> - fputs(_("terminal setting retrieval"), stdout);
> + if (ctl.batch == false) {
> + is_tty = isatty(STDIN_FILENO);
> + if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
> + fputs(_("terminal setting retrieval"), stdout);
>
> - ctl.win = initscr();
> - get_terminal_dimension(&ctl.cols, &ctl.rows);
> + ctl.win = initscr();
> + get_terminal_dimension(&ctl.cols, &ctl.rows);
> #if HAVE_RESIZETERM
> - resizeterm(ctl.rows, ctl.cols);
> + resizeterm(ctl.rows, ctl.cols);
> #endif
> - curs_set(0);
> + curs_set(0);
> + }
>
> ctl.hostname = xgethostname();
> event_loop(&ctl, &out);
> @@ -412,10 +440,13 @@ int main(int argc, char **argv)
> free(ctl.hostname);
> cpuset_free(ctl.cpuset);
>
> - if (is_tty)
> - tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
> - delwin(ctl.win);
> - endwin();
> + if (ctl.batch == false) {
> + if (is_tty)
> + tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
> +
> + delwin(ctl.win);
> + endwin();
> + }
>
> return EXIT_SUCCESS;
> }