* [RFC PATCH 0/2]lsirq,irqtop: Add filter support
@ 2025-03-07 2:51 Joe Jin
2025-03-07 2:52 ` [RFC PATCH 1/2] lsirq: add " Joe Jin
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Joe Jin @ 2025-03-07 2:51 UTC (permalink / raw)
To: Karel Zak, Zhenwei Pi, Sami Kerola; +Cc: util-linux, Joe Jin
Sometimes people may only be interested in a specific IRQ, adding regular
expression support can help engineers find/monitor IRQs easily.
Joe Jin (2):
lsirq: Add filter support
irqtop: add filter support
sys-utils/irq-common.c | 88 +++++++++++++++++++++++++++++++++++++++--
sys-utils/irq-common.h | 3 +-
sys-utils/irqtop.1.adoc | 4 +-
sys-utils/irqtop.c | 29 +++++++++++++-
sys-utils/lsirq.1.adoc | 4 +-
sys-utils/lsirq.c | 29 ++++++++++++--
6 files changed, 145 insertions(+), 12 deletions(-)
--
2.43.5
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC PATCH 1/2] lsirq: add filter support
2025-03-07 2:51 [RFC PATCH 0/2]lsirq,irqtop: Add filter support Joe Jin
@ 2025-03-07 2:52 ` Joe Jin
2025-03-07 2:52 ` [RFC PATCH 2/2] irqtop: " Joe Jin
2025-03-10 12:14 ` [RFC PATCH 0/2]lsirq,irqtop: Add " Karel Zak
2 siblings, 0 replies; 8+ messages in thread
From: Joe Jin @ 2025-03-07 2:52 UTC (permalink / raw)
To: Karel Zak, Zhenwei Pi, Sami Kerola; +Cc: util-linux, Joe Jin
Signed-off-by: Joe Jin <joe.jin@oracle.com>
Cc: Zhenwei Pi <pizhenwei@bytedance.com>
Cc: Sami Kerola <kerolasa@iki.fi>
Cc: Karel Zak <kzak@redhat.com>
---
sys-utils/irq-common.c | 88 ++++++++++++++++++++++++++++++++++++++++--
sys-utils/irq-common.h | 3 +-
sys-utils/irqtop.c | 2 +-
sys-utils/lsirq.1.adoc | 4 +-
sys-utils/lsirq.c | 29 ++++++++++++--
5 files changed, 116 insertions(+), 10 deletions(-)
diff --git a/sys-utils/irq-common.c b/sys-utils/irq-common.c
index 560dd4b82..059f57e3a 100644
--- a/sys-utils/irq-common.c
+++ b/sys-utils/irq-common.c
@@ -21,6 +21,7 @@
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
+#include <regex.h>
#include <libsmartcols.h>
@@ -230,11 +231,67 @@ static bool cpu_in_list(int cpu, size_t setsize, cpu_set_t *cpuset)
return CPU_ISSET_S(cpu, setsize, cpuset);
}
+static bool match_irqname_by_regex(char *regex_str, const char *irqname)
+{
+ regex_t re;
+ int ret;
+ char *expr = NULL;
+ int i, j;
+
+ /* Exactly matches the string */
+ if (strcmp(regex_str, irqname) == 0 || strcmp(regex_str, "*") == 0)
+ return true;
+
+ /*
+ * To generate ls-style regex we need:
+ * - Add '^' at the beginning.
+ * - Replace '*' with '.*'
+ * - Append '$' to the end.
+ */
+ expr = xmalloc(strlen(regex_str) + 3);
+ memset(expr, 0, strlen(regex_str) + 3);
+ /* Add '^' at the beginning */
+ expr[0] = '^';
+
+ /* Replace '*' with '.*' */
+ for (i = 0, j = 1; regex_str[i] != '\0'; i++, j++) {
+ if (regex_str[i] == '*') {
+ if ((i > 0 && regex_str[i-1] != '.') || i == 0) {
+ expr = realloc(expr, strlen(regex_str) + (j - i) + 1);
+ expr[j] = '.';
+ expr[++j] = '*';
+ } else {
+ expr[j] = regex_str[i];
+ }
+ } else {
+ expr[j] = regex_str[i];
+ }
+ }
+
+ /* Append '$' to the end if necessary */
+ if (regex_str[strlen(regex_str)-1] != '$') {
+ expr[j] = '$';
+ expr[j+1] = '\0';
+ } else {
+ expr[j] = '\0';
+ }
+
+ /* Try regex */
+ if (regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0)
+ return false;
+
+ ret = regexec(&re, irqname, 0, NULL, 0) == 0 ? true : false;
+ regfree(&re);
+
+ free(expr);
+ return ret;
+}
+
/*
* irqinfo - parse the system's interrupts
*/
static struct irq_stat *get_irqinfo(const char *input_file, int softirq,
- size_t setsize, cpu_set_t *cpuset)
+ size_t setsize, cpu_set_t *cpuset, char **filters)
{
FILE *irqfile;
char *line = NULL, *tmp;
@@ -280,7 +337,7 @@ static struct irq_stat *get_irqinfo(const char *input_file, int softirq,
length = strlen(line);
- curr = stat->irq_info + stat->nr_irq++;
+ curr = stat->irq_info + stat->nr_irq;
memset(curr, 0, sizeof(*curr));
*tmp = '\0';
curr->irq = xstrdup(line);
@@ -316,6 +373,28 @@ static struct irq_stat *get_irqinfo(const char *input_file, int softirq,
curr->name = xstrdup("");
}
+ /* Match filter */
+ if (filters) {
+ int matched = 0;
+ char **saved = filters;
+
+ while (*saved) {
+ if (strcmp(curr->irq, *saved) == 0 ||
+ match_irqname_by_regex(*saved, curr->name) == true) {
+ matched = 1;
+ break;
+ }
+ saved++;
+ }
+
+ if (!matched) {
+ memset(curr, 0, sizeof(*curr));
+ continue;
+ }
+ }
+
+ stat->nr_irq++;
+
if (stat->nr_irq == stat->nr_irq_info) {
stat->nr_irq_info *= 2;
stat->irq_info = xreallocarray(stat->irq_info, stat->nr_irq_info,
@@ -532,7 +611,8 @@ struct libscols_table *get_scols_table(const char *input_file,
int softirq,
uintmax_t threshold,
size_t setsize,
- cpu_set_t *cpuset)
+ cpu_set_t *cpuset,
+ char **filters)
{
struct libscols_table *table;
struct irq_info *result;
@@ -541,7 +621,7 @@ struct libscols_table *get_scols_table(const char *input_file,
size_t i;
/* the stats */
- stat = get_irqinfo(input_file, softirq, setsize, cpuset);
+ stat = get_irqinfo(input_file, softirq, setsize, cpuset, filters);
if (!stat)
return NULL;
diff --git a/sys-utils/irq-common.h b/sys-utils/irq-common.h
index b9cf72d2a..ec6c89d01 100644
--- a/sys-utils/irq-common.h
+++ b/sys-utils/irq-common.h
@@ -80,7 +80,8 @@ struct libscols_table *get_scols_table(const char *input_file,
int softirq,
uintmax_t threshold,
size_t setsize,
- cpu_set_t *cpuset);
+ cpu_set_t *cpuset,
+ char **filters);
struct libscols_table *get_scols_cpus_table(struct irq_output *out,
struct irq_stat *prev,
diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c
index 6d001cb10..dc59f4829 100644
--- a/sys-utils/irqtop.c
+++ b/sys-utils/irqtop.c
@@ -140,7 +140,7 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
table = get_scols_table(input_file, out, ctl->prev_stat, &stat,
ctl->softirq, ctl->threshold, ctl->setsize,
- ctl->cpuset);
+ ctl->cpuset, NULL);
free(input_file);
if (!table) {
ctl->request_exit = 1;
diff --git a/sys-utils/lsirq.1.adoc b/sys-utils/lsirq.1.adoc
index dd265710c..7a3bfb69e 100644
--- a/sys-utils/lsirq.1.adoc
+++ b/sys-utils/lsirq.1.adoc
@@ -12,7 +12,7 @@ lsirq - utility to display kernel interrupt information
== SYNOPSIS
-*lsirq* [options]
+*lsirq* [options]... [IRQ] [PATTERN] ...
== DESCRIPTION
@@ -20,6 +20,8 @@ Display kernel interrupt counter information.
The default output is subject to change. So whenever possible, you should avoid using default outputs in your scripts. Always explicitly define expected columns by using *--output*.
+Displays interrupt counter information only for the specified _IRQ_ or for irqnames matching _PATTERN_ when given.
+
== OPTIONS
*-n*, *--noheadings*::
diff --git a/sys-utils/lsirq.c b/sys-utils/lsirq.c
index fa2dcaaf3..a6528889f 100644
--- a/sys-utils/lsirq.c
+++ b/sys-utils/lsirq.c
@@ -35,11 +35,11 @@
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)
+ size_t setsize, cpu_set_t *cpuset, char **filters)
{
struct libscols_table *table;
- table = get_scols_table(input_file, out, NULL, NULL, softirq, threshold, setsize, cpuset);
+ table = get_scols_table(input_file, out, NULL, NULL, softirq, threshold, setsize, cpuset, filters);
if (!table)
return -1;
@@ -78,6 +78,8 @@ static void __attribute__((__noreturn__)) usage(void)
int main(int argc, char **argv)
{
+ char **filters = NULL;
+ int filters_len;
struct irq_output out = {
.ncolumns = 0
};
@@ -171,6 +173,18 @@ int main(int argc, char **argv)
input_file = xstrdup(_PATH_PROC_INTERRUPTS);
}
+ if (optind < argc) {
+ int i;
+
+ filters_len = argc - optind + 1;
+ filters = (char **)xmalloc(filters_len * sizeof(void *));
+ memset(filters, 0, filters_len * sizeof(void *));
+
+ for (i = optind; i < argc; i++)
+ filters[i - optind] = xstrdup(argv[i]);
+ filters[i - optind] = NULL;
+ }
+
/* default */
if (!out.ncolumns) {
out.columns[out.ncolumns++] = COL_IRQ;
@@ -185,9 +199,18 @@ int main(int argc, char **argv)
irq_column_name_to_id) < 0)
exit(EXIT_FAILURE);
- if (print_irq_data(input_file, &out, softirq, threshold, setsize, cpuset) < 0)
+ if (print_irq_data(input_file, &out, softirq, threshold, setsize, cpuset, filters) < 0)
return EXIT_FAILURE;
+ if (filters) {
+ char **saved = filters;
+
+ while(*filters) {
+ free(*filters);
+ filters++;
+ }
+ free(saved);
+ }
free(input_file);
return EXIT_SUCCESS;
--
2.43.5
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC PATCH 2/2] irqtop: add filter support
2025-03-07 2:51 [RFC PATCH 0/2]lsirq,irqtop: Add filter support Joe Jin
2025-03-07 2:52 ` [RFC PATCH 1/2] lsirq: add " Joe Jin
@ 2025-03-07 2:52 ` Joe Jin
2025-03-07 11:45 ` Benno Schulenberg
2025-03-09 11:39 ` Benno Schulenberg
2025-03-10 12:14 ` [RFC PATCH 0/2]lsirq,irqtop: Add " Karel Zak
2 siblings, 2 replies; 8+ messages in thread
From: Joe Jin @ 2025-03-07 2:52 UTC (permalink / raw)
To: Karel Zak, Zhenwei Pi, Sami Kerola; +Cc: util-linux, Joe Jin
Signed-off-by: Joe Jin <joe.jin@oracle.com>
Cc: Zhenwei Pi <pizhenwei@bytedance.com>
Cc: Sami Kerola <kerolasa@iki.fi>
Cc: Karel Zak <kzak@redhat.com>
---
sys-utils/irqtop.1.adoc | 4 +++-
sys-utils/irqtop.c | 29 +++++++++++++++++++++++++++--
2 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc
index 880ee1906..b9962ce1c 100644
--- a/sys-utils/irqtop.1.adoc
+++ b/sys-utils/irqtop.1.adoc
@@ -12,7 +12,7 @@ irqtop - utility to display kernel interrupt information
== SYNOPSIS
-*irqtop* [options]
+*irqtop* [options]... [IRQ] [PATTERN] ...
== DESCRIPTION
@@ -20,6 +20,8 @@ Display kernel interrupt counter information in *top*(1) style view.
The default output is subject to change. So whenever possible, you should avoid using default outputs in your scripts. Always explicitly define expected columns by using *--output*.
+Displays interrupt counter information only for the specified _IRQ_ or for irqnames matching _PATTERN_ when given.
+
== OPTIONS
*-o*, *--output* _list_::
diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c
index dc59f4829..c5deb840b 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 **filters;
};
static inline int irqtop_printf(struct irqtop_ctl *ctl, const char *fmt, ...)
@@ -140,7 +142,7 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
table = get_scols_table(input_file, out, ctl->prev_stat, &stat,
ctl->softirq, ctl->threshold, ctl->setsize,
- ctl->cpuset, NULL);
+ ctl->cpuset, ctl->filters);
free(input_file);
if (!table) {
ctl->request_exit = 1;
@@ -426,6 +428,19 @@ static void parse_args( struct irqtop_ctl *ctl,
}
}
+ if (optind < argc) {
+ int i;
+ int filters_len;
+
+ filters_len = argc - optind + 1;
+ ctl->filters = (char **)xmalloc(filters_len * sizeof(void *));
+ memset(ctl->filters, 0, filters_len * sizeof(void *));
+
+ for (i = optind; i < argc; i++)
+ ctl->filters[i - optind] = xstrdup(argv[i]);
+ ctl->filters[i - optind] = NULL;
+ }
+
/* default */
if (!out->ncolumns) {
out->columns[out->ncolumns++] = COL_IRQ;
@@ -452,7 +467,8 @@ int main(int argc, char **argv)
struct irqtop_ctl ctl = {
.timer.it_interval = {3, 0},
.timer.it_value = {3, 0},
- .iter = -1
+ .iter = -1,
+ .filters = NULL
};
setlocale(LC_ALL, "");
@@ -478,6 +494,15 @@ int main(int argc, char **argv)
free_irqstat(ctl.prev_stat);
free(ctl.hostname);
cpuset_free(ctl.cpuset);
+ if (ctl.filters) {
+ char **saved = ctl.filters;
+
+ while(*(ctl.filters)) {
+ free(*(ctl.filters));
+ (ctl.filters)++;
+ }
+ free(saved);
+ }
if (!ctl.batch) {
if (is_tty)
--
2.43.5
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 2/2] irqtop: add filter support
2025-03-07 2:52 ` [RFC PATCH 2/2] irqtop: " Joe Jin
@ 2025-03-07 11:45 ` Benno Schulenberg
2025-03-07 15:30 ` Joe Jin
2025-03-09 11:39 ` Benno Schulenberg
1 sibling, 1 reply; 8+ messages in thread
From: Benno Schulenberg @ 2025-03-07 11:45 UTC (permalink / raw)
To: Joe Jin; +Cc: util-linux
[-- Attachment #1.1: Type: text/plain, Size: 542 bytes --]
Op 07-03-2025 om 03:52 schreef Joe Jin:
> -*irqtop* [options]
> +*irqtop* [options]... [IRQ] [PATTERN] ...
There should be no dots after "[options]", as the "options"
word already implies that it can be multiple ones.
(True, it's not fully precise -- better would have been:
"[option...]". But don't use that. Please use what all
the other synopses use: "[options]", sans dots.)
Also, the convention nowadays is to put placeholder words
in lower case and between angular brackets:
"[<irq>] [<pattern>]..."
Benno
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 2/2] irqtop: add filter support
2025-03-07 11:45 ` Benno Schulenberg
@ 2025-03-07 15:30 ` Joe Jin
0 siblings, 0 replies; 8+ messages in thread
From: Joe Jin @ 2025-03-07 15:30 UTC (permalink / raw)
To: Benno Schulenberg; +Cc: util-linux
On 3/7/25 03:45, Benno Schulenberg wrote:
>
> Op 07-03-2025 om 03:52 schreef Joe Jin:
>
>> -*irqtop* [options]
>> +*irqtop* [options]... [IRQ] [PATTERN] ...
>
> There should be no dots after "[options]", as the "options"
> word already implies that it can be multiple ones.
>
> (True, it's not fully precise -- better would have been:
> "[option...]". But don't use that. Please use what all
> the other synopses use: "[options]", sans dots.)
>
> Also, the convention nowadays is to put placeholder words
> in lower case and between angular brackets:
> "[<irq>] [<pattern>]..."
Thanks for your suggestion, I'll make the change.
Bests,
Joe
>
>
> Benno
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 2/2] irqtop: add filter support
2025-03-07 2:52 ` [RFC PATCH 2/2] irqtop: " Joe Jin
2025-03-07 11:45 ` Benno Schulenberg
@ 2025-03-09 11:39 ` Benno Schulenberg
1 sibling, 0 replies; 8+ messages in thread
From: Benno Schulenberg @ 2025-03-09 11:39 UTC (permalink / raw)
To: Joe Jin; +Cc: util-linux
[-- Attachment #1.1: Type: text/plain, Size: 945 bytes --]
Op 07-03-2025 om 03:52 schreef Joe Jin:
> --- a/sys-utils/irqtop.1.adoc
> +++ b/sys-utils/irqtop.1.adoc
> @@ -12,7 +12,7 @@ irqtop - utility to display kernel interrupt information
>
> == SYNOPSIS
>
> -*irqtop* [options]
> +*irqtop* [options]... [IRQ] [PATTERN] ...
Oh -- I failed to notice that this change is for the man page,
not for the usage help text.
In a man page, the convention is to put placeholder words in
lowercase italics. That is: mark them with underscores:
*irqtop* [options] [_irq_] [_pattern_] ...
If, however, it is possible to specify multiple irq numbers and
irq names, and one can mix them, then I would write:
*irqtop* [options] [_irq_|_pattern_]...
> +Displays interrupt counter information only for the specified _IRQ_ or for irqnames matching _PATTERN_ when given.
Here, lowercase the underscored words, and "irq names" is better
as two separate words.
Benno
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 0/2]lsirq,irqtop: Add filter support
2025-03-07 2:51 [RFC PATCH 0/2]lsirq,irqtop: Add filter support Joe Jin
2025-03-07 2:52 ` [RFC PATCH 1/2] lsirq: add " Joe Jin
2025-03-07 2:52 ` [RFC PATCH 2/2] irqtop: " Joe Jin
@ 2025-03-10 12:14 ` Karel Zak
2025-03-10 15:27 ` Joe Jin
2 siblings, 1 reply; 8+ messages in thread
From: Karel Zak @ 2025-03-10 12:14 UTC (permalink / raw)
To: Joe Jin; +Cc: Zhenwei Pi, Sami Kerola, util-linux
On Thu, Mar 06, 2025 at 06:51:59PM GMT, Joe Jin wrote:
> Sometimes people may only be interested in a specific IRQ, adding regular
> expression support can help engineers find/monitor IRQs easily.
Ah, the libsmartcols provides a filter. See, for example, misc-utils/lsblk.c and
the "-Q" command line option, and also "man scols-filter".
scols_new_filter()
scols_line_apply_filter()
scols_line_is_filled()
... etc.
https://www.kernel.org/pub/linux/utils/util-linux/v2.41/libsmartcols-docs/libsmartcols-Filters-and-counters.html
The filter allows the creation of complex queries, so if we integrate
it into lsirq and irqtop, it will be possible to use things like:
irqtop -Q 'NAME ~= "PCI\-.*" && TOTAL > 100'
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 0/2]lsirq,irqtop: Add filter support
2025-03-10 12:14 ` [RFC PATCH 0/2]lsirq,irqtop: Add " Karel Zak
@ 2025-03-10 15:27 ` Joe Jin
0 siblings, 0 replies; 8+ messages in thread
From: Joe Jin @ 2025-03-10 15:27 UTC (permalink / raw)
To: Karel Zak; +Cc: Zhenwei Pi, Sami Kerola, util-linux
On 3/10/25 05:14, Karel Zak wrote:
> On Thu, Mar 06, 2025 at 06:51:59PM GMT, Joe Jin wrote:
>> Sometimes people may only be interested in a specific IRQ, adding regular
>> expression support can help engineers find/monitor IRQs easily.
> Ah, the libsmartcols provides a filter. See, for example, misc-utils/lsblk.c and
> the "-Q" command line option, and also "man scols-filter".
>
> scols_new_filter()
> scols_line_apply_filter()
> scols_line_is_filled()
> ... etc.
>
> https://www.kernel.org/pub/linux/utils/util-linux/v2.41/libsmartcols-docs/libsmartcols-Filters-and-counters.html
>
> The filter allows the creation of complex queries, so if we integrate
> it into lsirq and irqtop, it will be possible to use things like:
>
> irqtop -Q 'NAME ~= "PCI\-.*" && TOTAL > 100'
This looks more powerful, thanks for your suggestions.
Best Regards,
Joe
>
>
> Karel
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-03-10 15:27 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-07 2:51 [RFC PATCH 0/2]lsirq,irqtop: Add filter support Joe Jin
2025-03-07 2:52 ` [RFC PATCH 1/2] lsirq: add " Joe Jin
2025-03-07 2:52 ` [RFC PATCH 2/2] irqtop: " Joe Jin
2025-03-07 11:45 ` Benno Schulenberg
2025-03-07 15:30 ` Joe Jin
2025-03-09 11:39 ` Benno Schulenberg
2025-03-10 12:14 ` [RFC PATCH 0/2]lsirq,irqtop: Add " Karel Zak
2025-03-10 15:27 ` Joe Jin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).