linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Steven Rostedt <rostedt@goodmis.org>
To: linux-trace-devel@vger.kernel.org
Cc: Sameeruddin shaik <sameeruddin.shaik8@gmail.com>
Subject: [PATCH 7/7] libtracefs: Add indexing to set functions in tracefs_function_filter()
Date: Mon, 22 Mar 2021 21:28:02 -0400	[thread overview]
Message-ID: <20210323013225.595028176@goodmis.org> (raw)
In-Reply-To: 20210323012755.155237800@goodmis.org

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Starting in Linux kernel 5.1, it is possible to write the index of the
available_filter_functions (where the first function is 1), which is a
much faster way to set functions than with the glob expressions. By
finding the matches of the available_filter_functions and using the index
of the function, this can make the function call of
tracefs_function_filter() return much faster.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 src/tracefs-tools.c | 123 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 116 insertions(+), 7 deletions(-)

diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c
index 5e80c5e196b1..f97703d5e317 100644
--- a/src/tracefs-tools.c
+++ b/src/tracefs-tools.c
@@ -418,6 +418,12 @@ static void add_errors(const char ***errs, const char *filter, int ret)
 	*errs = e;
 }
 
+struct func_list {
+	struct func_list	*next;
+	unsigned int		start;
+	unsigned int		end;
+};
+
 struct func_filter {
 	const char		*filter;
 	regex_t			re;
@@ -534,18 +540,54 @@ static int write_filter(int fd, const char *filter, const char *module)
 	return 0;
 }
 
+static int add_func(struct func_list ***next_func_ptr, unsigned int index)
+{
+	struct func_list **next_func = *next_func_ptr;
+	struct func_list *func_list = *next_func;
+
+	if (!func_list) {
+		func_list = calloc(1, sizeof(*func_list));
+		if (!func_list)
+			return -1;
+		func_list->start = index;
+		func_list->end = index;
+		*next_func = func_list;
+		return 0;
+	}
+
+	if (index == func_list->end + 1) {
+		func_list->end = index;
+		return 0;
+	}
+	*next_func_ptr = &func_list->next;
+	return add_func(next_func_ptr, index);
+}
+
+static void free_func_list(struct func_list *func_list)
+{
+	struct func_list *f;
+
+	while (func_list) {
+		f = func_list;
+		func_list = f->next;
+		free(f);
+	}
+}
+
 enum match_type {
 	FILTER_CHECK,
 	FILTER_WRITE,
 };
 
 static int match_filters(int fd, struct func_filter *func_filters,
-			 const char *module, enum match_type type)
+			 const char *module, struct func_list **func_list,
+			 enum match_type type)
 {
 	char *line = NULL;
 	size_t size = 0;
 	char *path;
 	FILE *fp;
+	int index = 0;
 	int ret = 1;
 	int mlen;
 	int i;
@@ -567,12 +609,16 @@ static int match_filters(int fd, struct func_filter *func_filters,
 		char *saveptr = NULL;
 		char *tok, *mtok;
 		int len = strlen(line);
+		bool first = true;
 
 		if (line[len - 1] == '\n')
 			line[len - 1] = '\0';
 		tok = strtok_r(line, " ", &saveptr);
 		if (!tok)
 			goto next;
+
+		index++;
+
 		if (module) {
 			mtok = strtok_r(line, " ", &saveptr);
 			if (!mtok)
@@ -585,8 +631,23 @@ static int match_filters(int fd, struct func_filter *func_filters,
 		case FILTER_CHECK:
 			/* Check, checks a list of filters */
 			for (i = 0; func_filters[i].filter; i++) {
-				if (match(tok, &func_filters[i]))
+				/*
+				 * If a match was found, still need to
+				 * check if other filters would match
+				 * to make sure that all filters have a
+				 * match, as some filters may overlap.
+				 */
+				if (!first && func_filters[i].set)
+					continue;
+				if (match(tok, &func_filters[i])) {
 					func_filters[i].set = true;
+					if (first) {
+						first = false;
+						ret = add_func(&func_list, index);
+						if (ret)
+							goto out;
+					}
+				}
 			}
 			break;
 		case FILTER_WRITE:
@@ -611,12 +672,13 @@ static int match_filters(int fd, struct func_filter *func_filters,
 }
 
 static int check_available_filters(struct func_filter *func_filters,
-				   const char *module, const char ***errs)
+				   const char *module, const char ***errs,
+				   struct func_list **func_list)
 {
 	int ret;
 	int i;
 
-	ret = match_filters(-1, func_filters, module, FILTER_CHECK);
+	ret = match_filters(-1, func_filters, module, func_list, FILTER_CHECK);
 	/* Return here if success or non filter error */
 	if (ret >= 0)
 		return ret;
@@ -633,7 +695,7 @@ static int check_available_filters(struct func_filter *func_filters,
 static int set_regex_filter(int fd, struct func_filter *func_filter,
 			    const char *module)
 {
-	return match_filters(fd, func_filter, module, FILTER_WRITE);
+	return match_filters(fd, func_filter, module, NULL, FILTER_WRITE);
 }
 
 static int controlled_write(int fd, struct func_filter *func_filters,
@@ -724,6 +786,49 @@ static struct func_filter *make_func_filters(const char **filters)
 	return NULL;
 }
 
+static int write_number(int fd, unsigned int start, unsigned int end)
+{
+	char buf[64];
+	unsigned int i;
+	int n, ret;
+
+	for (i = start; i <= end; i++) {
+		n = snprintf(buf, 64, "%d ", i);
+		ret = write(fd, buf, n);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * This will try to write the first number, if that fails, it
+ * will assume that it is not supported and return 1.
+ * If the first write succeeds, but a following write fails, then
+ * the kernel does support this, but something else went wrong,
+ * in this case, return -1.
+ */
+static int write_func_list(int fd, struct func_list *list)
+{
+	int ret;
+
+	if (!list)
+		return 0;
+
+	ret = write_number(fd, list->start, list->end);
+	if (ret)
+		return 1; // try a different way
+	list = list->next;
+	while (list) {
+		ret = write_number(fd, list->start, list->end);
+		if (ret)
+			return -1;
+		list = list->next;
+	}
+	return 0;
+}
+
 /**
  * tracefs_function_filter - write to set_ftrace_filter file to trace
  * particular functions
@@ -756,6 +861,7 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt
 			    const char *module, bool reset, const char ***errs)
 {
 	struct func_filter *func_filters;
+	struct func_list *func_list = NULL;
 	char *ftrace_filter_path;
 	int flags;
 	int ret;
@@ -772,7 +878,7 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt
 	if (errs)
 		*errs = NULL;
 
-	ret = check_available_filters(func_filters, module, errs);
+	ret = check_available_filters(func_filters, module, errs, &func_list);
 	if (ret)
 		goto out_free;
 
@@ -788,11 +894,14 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt
 	if (fd < 0)
 		goto out_free;
 
-	ret = controlled_write(fd, func_filters, module, errs);
+	ret = write_func_list(fd, func_list);
+	if (ret > 0)
+		ret = controlled_write(fd, func_filters, module, errs);
 
 	close(fd);
 
  out_free:
+	free_func_list(func_list);
 	free_func_filters(func_filters);
 
 	return ret;
-- 
2.30.1



  parent reply	other threads:[~2021-03-23  1:33 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-23  1:27 [PATCH 0/7] libtracfes: Add tracefs_function_filter() Steven Rostedt
2021-03-23  1:27 ` [PATCH 1/7] libtracefs: An API to set the filtering of functions Steven Rostedt
2021-03-23  1:27 ` [PATCH 2/7] libtracefs: Move opening of file out of controlled_write() Steven Rostedt
2021-03-23  1:27 ` [PATCH 3/7] libtracefs: Add add_errors() helper function for control_write() Steven Rostedt
2021-03-23  1:27 ` [PATCH 4/7] libtracefs: Add checking of available_filter_functions to tracefs_function_filter() Steven Rostedt
2021-03-23  1:28 ` [PATCH 5/7] libtracefs: Add write_filter() helper function Steven Rostedt
2021-03-23  1:28 ` [PATCH 6/7] libtracefs: Allow for setting filters with regex expressions Steven Rostedt
2021-03-23  1:28 ` Steven Rostedt [this message]
2021-03-23 12:52 ` [PATCH 0/7] libtracfes: Add tracefs_function_filter() Steven Rostedt
2021-03-24 10:13   ` Sameeruddin Shaik
2021-03-24 14:08     ` Steven Rostedt
2021-03-26  0:25   ` sameeruddin shaik
2021-03-25  0:35     ` Steven Rostedt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210323013225.595028176@goodmis.org \
    --to=rostedt@goodmis.org \
    --cc=linux-trace-devel@vger.kernel.org \
    --cc=sameeruddin.shaik8@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).