[RFC PATCH 1/2] lsirq: add filter support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Joe Jin <joe.jin@xxxxxxxxxx>
Cc: Zhenwei Pi <pizhenwei@xxxxxxxxxxxxx>
Cc: Sami Kerola <kerolasa@xxxxxx>
Cc: Karel Zak <kzak@xxxxxxxxxx>
---
 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





[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux