183 lines
4.9 KiB
Diff
183 lines
4.9 KiB
Diff
From db8893838433972feafe545117b60dca8c7318df Mon Sep 17 00:00:00 2001
|
|
From: Slavomir Kaslev <kaslevs@vmware.com>
|
|
Date: Wed, 17 Apr 2019 16:09:58 +0300
|
|
Subject: [PATCH 1/2] trace-cmd: Optimize how pid filters are expressed
|
|
|
|
Express pid filters as allowed/disallowed filter ranges
|
|
|
|
(pid>=100&&pid<=103)
|
|
|
|
instead of specifying them per pid
|
|
|
|
(pid==100||pid==101||pid==102||pid==103)
|
|
|
|
This makes the size of the resulting filter smaller (and faster) and avoids
|
|
overflowing the filter size limit of one page which we can hit on bigger
|
|
machines (say >160 CPUs).
|
|
|
|
Link: http://lore.kernel.org/linux-trace-devel/20190417130959.10064-2-kaslevs@vmware.com
|
|
|
|
Reported-by: Phil Auld <pauld@redhat.com>
|
|
Tested-by: Phil Auld <pauld@redhat.com>
|
|
Suggested-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
|
|
Signed-off-by: Slavomir Kaslev <kaslevs@vmware.com>
|
|
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
|
|
---
|
|
trace-record.c | 117 ++++++++++++++++++++++++++++++++++---------------
|
|
1 file changed, 81 insertions(+), 36 deletions(-)
|
|
|
|
diff --git a/trace-record.c b/trace-record.c
|
|
index 9479f5f8073c..e636c97d701d 100644
|
|
--- a/trace-record.c
|
|
+++ b/trace-record.c
|
|
@@ -903,10 +903,63 @@ static void update_ftrace_pids(int reset)
|
|
static void update_event_filters(struct buffer_instance *instance);
|
|
static void update_pid_event_filters(struct buffer_instance *instance);
|
|
|
|
+static void append_filter_pid_range(char **filter, int *curr_len,
|
|
+ const char *field,
|
|
+ int start_pid, int end_pid, bool exclude)
|
|
+{
|
|
+ const char *op = "", *op1, *op2, *op3;
|
|
+ int len;
|
|
+
|
|
+ if (*filter && **filter)
|
|
+ op = exclude ? "&&" : "||";
|
|
+
|
|
+ /* Handle thus case explicitly so that we get `pid==3` instead of
|
|
+ * `pid>=3&&pid<=3` for singleton ranges
|
|
+ */
|
|
+ if (start_pid == end_pid) {
|
|
+#define FMT "%s(%s%s%d)"
|
|
+ len = snprintf(NULL, 0, FMT, op,
|
|
+ field, exclude ? "!=" : "==", start_pid);
|
|
+ *filter = realloc(*filter, *curr_len + len + 1);
|
|
+ if (!*filter)
|
|
+ die("realloc");
|
|
+
|
|
+ len = snprintf(*filter + *curr_len, len + 1, FMT, op,
|
|
+ field, exclude ? "!=" : "==", start_pid);
|
|
+ *curr_len += len;
|
|
+
|
|
+ return;
|
|
+#undef FMT
|
|
+ }
|
|
+
|
|
+ if (exclude) {
|
|
+ op1 = "<";
|
|
+ op2 = "||";
|
|
+ op3 = ">";
|
|
+ } else {
|
|
+ op1 = ">=";
|
|
+ op2 = "&&";
|
|
+ op3 = "<=";
|
|
+ }
|
|
+
|
|
+#define FMT "%s(%s%s%d%s%s%s%d)"
|
|
+ len = snprintf(NULL, 0, FMT, op,
|
|
+ field, op1, start_pid, op2,
|
|
+ field, op3, end_pid);
|
|
+ *filter = realloc(*filter, *curr_len + len + 1);
|
|
+ if (!*filter)
|
|
+ die("realloc");
|
|
+
|
|
+ len = snprintf(*filter + *curr_len, len + 1, FMT, op,
|
|
+ field, op1, start_pid, op2,
|
|
+ field, op3, end_pid);
|
|
+ *curr_len += len;
|
|
+}
|
|
+
|
|
/**
|
|
* make_pid_filter - create a filter string to all pids against @field
|
|
* @curr_filter: Append to a previous filter (may realloc). Can be NULL
|
|
- * @field: The fild to compare the pids against
|
|
+ * @field: The field to compare the pids against
|
|
*
|
|
* Creates a new string or appends to an existing one if @curr_filter
|
|
* is not NULL. The new string will contain a filter with all pids
|
|
@@ -916,54 +969,46 @@ static void update_pid_event_filters(struct buffer_instance *instance);
|
|
*/
|
|
static char *make_pid_filter(char *curr_filter, const char *field)
|
|
{
|
|
+ int start_pid = -1, last_pid = -1;
|
|
+ int last_exclude = -1;
|
|
struct filter_pids *p;
|
|
- char *filter;
|
|
- char *orit;
|
|
- char *match;
|
|
- char *str;
|
|
+ char *filter = NULL;
|
|
int curr_len = 0;
|
|
- int len;
|
|
|
|
/* Use the new method if possible */
|
|
if (have_set_event_pid)
|
|
return NULL;
|
|
|
|
- len = len_filter_pids + (strlen(field) + strlen("(==)||")) * nr_filter_pids;
|
|
-
|
|
- if (curr_filter) {
|
|
- curr_len = strlen(curr_filter);
|
|
- filter = realloc(curr_filter, curr_len + len + strlen("(&&())"));
|
|
- if (!filter)
|
|
- die("realloc");
|
|
- memmove(filter+1, curr_filter, curr_len);
|
|
- filter[0] = '(';
|
|
- strcat(filter, ")&&(");
|
|
- curr_len = strlen(filter);
|
|
- } else
|
|
- filter = malloc(len);
|
|
- if (!filter)
|
|
- die("Failed to allocate pid filter");
|
|
-
|
|
- /* Last '||' that is not used will cover the \0 */
|
|
- str = filter + curr_len;
|
|
+ if (!filter_pids)
|
|
+ return curr_filter;
|
|
|
|
for (p = filter_pids; p; p = p->next) {
|
|
- if (p->exclude) {
|
|
- match = "!=";
|
|
- orit = "&&";
|
|
- } else {
|
|
- match = "==";
|
|
- orit = "||";
|
|
+ /*
|
|
+ * PIDs are inserted in `filter_pids` from the front and that's
|
|
+ * why we expect them in descending order here.
|
|
+ */
|
|
+ if (p->pid == last_pid - 1 && p->exclude == last_exclude) {
|
|
+ last_pid = p->pid;
|
|
+ continue;
|
|
}
|
|
- if (p == filter_pids)
|
|
- orit = "";
|
|
|
|
- len = sprintf(str, "%s(%s%s%d)", orit, field, match, p->pid);
|
|
- str += len;
|
|
+ if (start_pid != -1)
|
|
+ append_filter_pid_range(&filter, &curr_len, field,
|
|
+ last_pid, start_pid,
|
|
+ last_exclude);
|
|
+
|
|
+ start_pid = last_pid = p->pid;
|
|
+ last_exclude = p->exclude;
|
|
+
|
|
}
|
|
+ append_filter_pid_range(&filter, &curr_len, field,
|
|
+ last_pid, start_pid, last_exclude);
|
|
|
|
- if (curr_len)
|
|
- sprintf(str, ")");
|
|
+ if (curr_filter) {
|
|
+ char *save = filter;
|
|
+ asprintf(&filter, "(%s)&&(%s)", curr_filter, filter);
|
|
+ free(save);
|
|
+ }
|
|
|
|
return filter;
|
|
}
|
|
--
|
|
2.20.1
|
|
|