Skip to contentSkip to conversation

perf/core improvements and fixes

GIT PULL New Arnaldo Carvalho de Melo 2 participants 13 messages Jul 6, 2015

Subsystems (2)
lore
Share & tools
lore

Arnaldo Carvalho de Melo

author maintainer
#0 lore raw

Hi Ingo,

Please consider pulling,

- Arnaldo

The following changes since commit d2d61ed55f8375a10ff606e83e2196880a775fb4:

Merge branch 'perf/rbtree_copy' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent (2015-07-06 09:24:41 +0200)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo

for you to fetch changes up to ab85785aa13c36440a91a8e9f7616357de411a1f:

tools lib api debugfs: Check for tracefs when reporting errors (2015-07-06 12:22:14 -0300)

----------------------------------------------------------------
perf/core improvements and fixes:

User visible:

- Take tracefs into account when reporting errors about accessing tracepoint information in tools like 'perf trace' (Arnaldo Carvalho de Melo)

- Let user have timestamps with per-thread recording in 'perf record' (Adrian Hunter)

Infrastructure:

- Introduce series of functions to build event filters so that we can set them in just one ioctl call, useful to set up common_pid, raw_syscalls:sys_{enter,exit}'s "id" filters to use with 'perf trace' (Arnaldo Carvalho de Melo)

- Delete an unnecessary check before calling strfilter__delete() (Markus Elfring)

----------------------------------------------------------------
Adrian Hunter (1):
perf record: Let user have timestamps with per-thread recording

Arnaldo Carvalho de Melo (9):
perf tools: Asprintf like functions to format integer filter expression perf trace: Remember what are the syscalls tracepoint evsels perf trace: Store the syscall ids for the event qualifiers in a table perf evsel: Rename set_filter to apply_filter
perf evsel: Introduce set_filter method
perf evlist: Make perf_evlist__set_filter use perf_evsel__set_filter perf evsel: Introduce append_filter() method
perf trace: Use event filters for the event qualifier list tools lib api debugfs: Check for tracefs when reporting errors

Markus Elfring (1):
perf probe: Delete an unnecessary check before the function call "strfilter__delete"

 tools/lib/api/fs/debugfs.c     |  15 +++-
 tools/perf/builtin-probe.c     |   3 +-
 tools/perf/builtin-record.c    |   4 +-
 tools/perf/builtin-trace.c     | 178 ++++++++++++++++++++++++++---------------
 tools/perf/perf.h              |   1 +
 tools/perf/util/evlist.c       |   6 +-
 tools/perf/util/evsel.c        |  37 ++++++++-
 tools/perf/util/evsel.h        |   7 +-
 tools/perf/util/parse-events.c |   3 +-
 tools/perf/util/string.c       |  39 +++++++++
 tools/perf/util/util.h         |  12 +++
 11 files changed, 224 insertions(+), 81 deletions(-)
author maintainer
#1 lore raw

PATCH 1/11 perf tools: Asprintf like functions to format integer filter expression

From: Arnaldo Carvalho de Melo <[email protected]>

  char *asprintf_expr_in_ints(const char *var, size_t nints, int *ints);
  char *asprintf_expr_not_in_ints(const char *var, size_t nints, int *ints);

Example of output formatted with those functions:

  # ./tp_filter 6 12 2015
  asprintf_expr_in_ints:     id == 6 || id == 12 || id == 2015
  asprintf_expr_not_in_ints: id != 6 && id != 12 && id != 2015
  #

It'll be used with, for instance, perf_evsel__set_filter_in_ints(), that will be used in turn to ask the kernel to filter out all raw_syscalls:* except for the ones specified by the user via:

 $ perf trace -e some,list,of,syscalls
Cc Adrian Hunter <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/util/string.c | 39 +++++++++++++++++++++++++++++++++++++++
 tools/perf/util/util.h   | 12 ++++++++++++
 2 files changed, 51 insertions(+)
tools/perf/util/string.c +39 -0
index 6afd6106ceb5..fc8781de62db 100644
@@ -357,3 +357,42 @@ void *memdup(const void *src, size_t len)
 
 	return p;
 }
+
+char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
+{
+	/*
+	 * FIXME: replace this with an expression using log10() when we
+	 * find a suitable implementation, maybe the one in the dvb drivers...
+	 *
+	 * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
+	 */
+	size_t size = nints * 28 + 1; /* \0 */
+	size_t i, printed = 0;
+	char *expr = malloc(size);
+
+	if (expr) {
+		const char *or_and = "||", *eq_neq = "==";
+		char *e = expr;
+
+		if (!in) {
+			or_and = "&&";
+			eq_neq = "!=";
+		}
+
+		for (i = 0; i < nints; ++i) {
+			if (printed == size)
+				goto out_err_overflow;
+
+			if (i > 0)
+				printed += snprintf(e + printed, size - printed, " %s ", or_and);
+			printed += scnprintf(e + printed, size - printed,
+					     "%s %s %d", var, eq_neq, ints[i]);
+		}
+	}
+
+	return expr;
+
+out_err_overflow:
+	free(expr);
+	return NULL;
+}
tools/perf/util/util.h +12 -0
index 8bce58b47a82..20d625a4cacf 100644
@@ -339,4 +339,16 @@ int gzip_decompress_to_file(const char *input, int output_fd);
 int lzma_decompress_to_file(const char *input, int output_fd);
 #endif
 
+char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints);
+
+static inline char *asprintf_expr_in_ints(const char *var, size_t nints, int *ints)
+{
+	return asprintf_expr_inout_ints(var, true, nints, ints);
+}
+
+static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int *ints)
+{
+	return asprintf_expr_inout_ints(var, false, nints, ints);
+}
+
 #endif /* GIT_COMPAT_UTIL_H */
Signature · 1 line
2.1.0
author maintainer
#2 lore raw

PATCH 2/11 perf trace: Remember what are the syscalls tracepoint evsels

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

We will need to set filters on then.

Cc Adrian Hunter <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/builtin-trace.c | 82 ++++++++++++++++++++++++----------------------
 1 file changed, 43 insertions(+), 39 deletions(-)
tools/perf/builtin-trace.c +43 -39
index 39ad4d0ca884..431e297b0e3a 100644
@@ -247,42 +247,6 @@ out_delete:
 	({ struct syscall_tp *fields = evsel->priv; \
 	   fields->name.pointer(&fields->name, sample); })
 
-static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
-					  void *sys_enter_handler,
-					  void *sys_exit_handler)
-{
-	int ret = -1;
-	struct perf_evsel *sys_enter, *sys_exit;
-
-	sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
-	if (sys_enter == NULL)
-		goto out;
-
-	if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
-		goto out_delete_sys_enter;
-
-	sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
-	if (sys_exit == NULL)
-		goto out_delete_sys_enter;
-
-	if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
-		goto out_delete_sys_exit;
-
-	perf_evlist__add(evlist, sys_enter);
-	perf_evlist__add(evlist, sys_exit);
-
-	ret = 0;
-out:
-	return ret;
-
-out_delete_sys_exit:
-	perf_evsel__delete_priv(sys_exit);
-out_delete_sys_enter:
-	perf_evsel__delete_priv(sys_enter);
-	goto out;
-}
-
-
 struct syscall_arg {
 	unsigned long val;
 	struct thread *thread;
@@ -1307,6 +1271,10 @@ struct trace {
 	struct {
 		int		max;
 		struct syscall  *table;
+		struct {
+			struct perf_evsel *enter,
+					  *exit;
+		}		events;
 	} syscalls;
 	struct record_opts	opts;
 	struct perf_evlist	*evlist;
@@ -2283,6 +2251,44 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st
 	}
 }
 
+static int trace__add_syscall_newtp(struct trace *trace)
+{
+	int ret = -1;
+	struct perf_evlist *evlist = trace->evlist;
+	struct perf_evsel *sys_enter, *sys_exit;
+
+	sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
+	if (sys_enter == NULL)
+		goto out;
+
+	if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
+		goto out_delete_sys_enter;
+
+	sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
+	if (sys_exit == NULL)
+		goto out_delete_sys_enter;
+
+	if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
+		goto out_delete_sys_exit;
+
+	perf_evlist__add(evlist, sys_enter);
+	perf_evlist__add(evlist, sys_exit);
+
+	trace->syscalls.events.enter = sys_enter;
+	trace->syscalls.events.exit  = sys_exit;
+
+	ret = 0;
+out:
+	return ret;
+
+out_delete_sys_exit:
+	perf_evsel__delete_priv(sys_exit);
+out_delete_sys_enter:
+	perf_evsel__delete_priv(sys_enter);
+	goto out;
+}
+
+
 static int trace__run(struct trace *trace, int argc, const char **argv)
 {
 	struct perf_evlist *evlist = trace->evlist;
@@ -2293,9 +2299,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 
 	trace->live = true;
 
-	if (trace->trace_syscalls &&
-	    perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
-					   trace__sys_exit))
+	if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
 		goto out_error_raw_syscalls;
 
 	if (trace->trace_syscalls)
Signature · 1 line
2.1.0
author maintainer
#3 lore raw

PATCH 3/11 perf trace: Store the syscall ids for the event qualifiers in a table

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

That we will use to set a filter on raw_syscalls:sys_{enter,exit} events.

Cc Adrian Hunter <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/builtin-trace.c | 36 +++++++++++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 7 deletions(-)
tools/perf/builtin-trace.c +29 -7
index 431e297b0e3a..b10608680c01 100644
@@ -1272,8 +1272,8 @@ struct trace {
 		int		max;
 		struct syscall  *table;
 		struct {
-			struct perf_evsel *enter,
-					  *exit;
+			struct perf_evsel *sys_enter,
+					  *sys_exit;
 		}		events;
 	} syscalls;
 	struct record_opts	opts;
@@ -1284,6 +1284,10 @@ struct trace {
 	FILE			*output;
 	unsigned long		nr_events;
 	struct strlist		*ev_qualifier;
+	struct {
+		size_t		nr;
+		int		*entries;
+	}			ev_qualifier_ids;
 	const char 		*last_vfs_getname;
 	struct intlist		*tid_list;
 	struct intlist		*pid_list;
@@ -1587,13 +1591,27 @@ static int trace__read_syscall_info(struct trace *trace, int id)
 
 static int trace__validate_ev_qualifier(struct trace *trace)
 {
-	int err = 0;
+	int err = 0, i;
 	struct str_node *pos;
 
+	trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
+	trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
+						 sizeof(trace->ev_qualifier_ids.entries[0]));
+
+	if (trace->ev_qualifier_ids.entries == NULL) {
+		fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
+		       trace->output);
+		err = -EINVAL;
+		goto out;
+	}
+
+	i = 0;
+
 	strlist__for_each(pos, trace->ev_qualifier) {
 		const char *sc = pos->s;
+		int id = audit_name_to_syscall(sc, trace->audit.machine);
 
-		if (audit_name_to_syscall(sc, trace->audit.machine) < 0) {
+		if (id < 0) {
 			if (err == 0) {
 				fputs("Error:\tInvalid syscall ", trace->output);
 				err = -EINVAL;
@@ -1603,13 +1621,17 @@ static int trace__validate_ev_qualifier(struct trace *trace)
 
 			fputs(sc, trace->output);
 		}
+
+		trace->ev_qualifier_ids.entries[i++] = id;
 	}
 
 	if (err < 0) {
 		fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
 		      "\nHint:\tand: 'man syscalls'\n", trace->output);
+		zfree(&trace->ev_qualifier_ids.entries);
+		trace->ev_qualifier_ids.nr = 0;
 	}
-
+out:
 	return err;
 }
 
@@ -2274,8 +2296,8 @@ static int trace__add_syscall_newtp(struct trace *trace)
 	perf_evlist__add(evlist, sys_enter);
 	perf_evlist__add(evlist, sys_exit);
 
-	trace->syscalls.events.enter = sys_enter;
-	trace->syscalls.events.exit  = sys_exit;
+	trace->syscalls.events.sys_enter = sys_enter;
+	trace->syscalls.events.sys_exit  = sys_exit;
 
 	ret = 0;
 out:
Signature · 1 line
2.1.0
author maintainer
#4 lore raw

PATCH 4/11 perf evsel: Rename set_filter to apply_filter

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

We need to be able to go on constructing a complex filter in multiple stages, since we can only set one filter per event.

For instance, we need to be able, in 'perf trace' to filter by the 'common_pid' field all the time, if only for the tracer itself, to avoid a feedback loop, and, in addition, we may want to filter the raw_syscalls:sys_{enter,exit} events by its 'id' filter, when using 'perf trace -e open,close' or 'perf trace -e !open,close', i.e. when we are interested in just a subset of syscalls or when we are not interested in it.

So we will have:

perf_evsel__set_filter(evsel, char *filter)

       Replaces whatever is in evsel->filter.

perf_evsel__append_filter(evsel, const char *op, char *filter)

       Appends, using op ("&&" or "||") with what is in evsel->filter.

perf_evsel__apply_filter(evsel, filter):

That actually applies a filter, be it the one being constructed in evsel->filter, or any other, for tools with more specific ways to build the filter, issuing the appropriate ioctl for all the evsel fds.

The same changes will be made to the evlist__{set,apply} variants to keep everything consistent.

Cc Adrian Hunter <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/util/evlist.c | 4 ++--
 tools/perf/util/evsel.c  | 4 ++--
 tools/perf/util/evsel.h  | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)
tools/perf/util/evlist.c +2 -2
index 6cfdee68e763..51913284e8e3 100644
@@ -1161,7 +1161,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e
 		if (evsel->filter == NULL)
 			continue;
 
-		err = perf_evsel__set_filter(evsel, ncpus, nthreads, evsel->filter);
+		err = perf_evsel__apply_filter(evsel, ncpus, nthreads, evsel->filter);
 		if (err) {
 			*err_evsel = evsel;
 			break;
@@ -1179,7 +1179,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
 		  nthreads = thread_map__nr(evlist->threads);
 
 	evlist__for_each(evlist, evsel) {
-		err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
+		err = perf_evsel__apply_filter(evsel, ncpus, nthreads, filter);
 		if (err)
 			break;
 	}
tools/perf/util/evsel.c +2 -2
index 2936b3080722..667677495fb0 100644
@@ -815,8 +815,8 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
 	return 0;
 }
 
-int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
-			   const char *filter)
+int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
+			     const char *filter)
 {
 	return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
 				     PERF_EVENT_IOC_SET_FILTER,
tools/perf/util/evsel.h +2 -2
index 4a7ed5656cf0..a3ebb83d767e 100644
@@ -182,8 +182,8 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
 void perf_evsel__set_sample_id(struct perf_evsel *evsel,
 			       bool use_sample_identifier);
 
-int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
-			   const char *filter);
+int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
+			     const char *filter);
 int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads);
 
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
Signature · 1 line
2.1.0
author maintainer
#5 lore raw

PATCH 5/11 perf evsel: Introduce set_filter method

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

Replaces existing filter string with the one provided.

Cc Adrian Hunter <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/util/evsel.c        | 13 +++++++++++++
 tools/perf/util/evsel.h        |  1 +
 tools/perf/util/parse-events.c |  3 +--
 3 files changed, 15 insertions(+), 2 deletions(-)
tools/perf/util/evsel.c +13 -0
index 667677495fb0..ae925b9ce6dd 100644
@@ -823,6 +823,19 @@ int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
 				     (void *)filter);
 }
 
+int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter)
+{
+	char *new_filter = strdup(filter);
+
+	if (new_filter != NULL) {
+		free(evsel->filter);
+		evsel->filter = new_filter;
+		return 0;
+	}
+
+	return -1;
+}
+
 int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
 	return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
tools/perf/util/evsel.h +1 -0
index a3ebb83d767e..8aea4baca080 100644
@@ -182,6 +182,7 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
 void perf_evsel__set_sample_id(struct perf_evsel *evsel,
 			       bool use_sample_identifier);
 
+int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter);
 int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
 			     const char *filter);
 int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads);
tools/perf/util/parse-events.c +1 -2
index 09f8d2357108..a71eeb279ed2 100644
@@ -1177,8 +1177,7 @@ int parse_filter(const struct option *opt, const char *str,
 		return -1;
 	}
 
-	last->filter = strdup(str);
-	if (last->filter == NULL) {
+	if (perf_evsel__set_filter(last, str) < 0) {
 		fprintf(stderr, "not enough memory to hold filter string\n");
 		return -1;
 	}
Signature · 1 line
2.1.0
#6 lore raw
In reply to Arnaldo Carvalho de Melo
Quoted 57 lines · Arnaldo Carvalho de Melo

Hi Ingo,

Please consider pulling,

- Arnaldo

The following changes since commit d2d61ed55f8375a10ff606e83e2196880a775fb4:

Merge branch 'perf/rbtree_copy' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent (2015-07-06 09:24:41 +0200)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo

for you to fetch changes up to ab85785aa13c36440a91a8e9f7616357de411a1f:

tools lib api debugfs: Check for tracefs when reporting errors (2015-07-06 12:22:14 -0300)

----------------------------------------------------------------
perf/core improvements and fixes:

User visible:

- Take tracefs into account when reporting errors about accessing tracepoint information in tools like 'perf trace' (Arnaldo Carvalho de Melo)

- Let user have timestamps with per-thread recording in 'perf record' (Adrian Hunter)

Infrastructure:

- Introduce series of functions to build event filters so that we can set them in just one ioctl call, useful to set up common_pid, raw_syscalls:sys_{enter,exit}'s "id" filters to use with 'perf trace' (Arnaldo Carvalho de Melo)

- Delete an unnecessary check before calling strfilter__delete() (Markus Elfring)

----------------------------------------------------------------
Adrian Hunter (1):
perf record: Let user have timestamps with per-thread recording

Arnaldo Carvalho de Melo (9):
perf tools: Asprintf like functions to format integer filter expression perf trace: Remember what are the syscalls tracepoint evsels perf trace: Store the syscall ids for the event qualifiers in a table perf evsel: Rename set_filter to apply_filter
perf evsel: Introduce set_filter method
perf evlist: Make perf_evlist__set_filter use perf_evsel__set_filter perf evsel: Introduce append_filter() method
perf trace: Use event filters for the event qualifier list tools lib api debugfs: Check for tracefs when reporting errors

Markus Elfring (1):
perf probe: Delete an unnecessary check before the function call "strfilter__delete"

Quoted 12 lines
 tools/lib/api/fs/debugfs.c     |  15 +++-
 tools/perf/builtin-probe.c     |   3 +-
 tools/perf/builtin-record.c    |   4 +-
 tools/perf/builtin-trace.c     | 178 ++++++++++++++++++++++++++---------------
 tools/perf/perf.h              |   1 +
 tools/perf/util/evlist.c       |   6 +-
 tools/perf/util/evsel.c        |  37 ++++++++-
 tools/perf/util/evsel.h        |   7 +-
 tools/perf/util/parse-events.c |   3 +-
 tools/perf/util/string.c       |  39 +++++++++
 tools/perf/util/util.h         |  12 +++
 11 files changed, 224 insertions(+), 81 deletions(-)

Pulled, thanks a lot Arnaldo!

Ingo

author maintainer
#7 lore raw

PATCH 6/11 perf evlist: Make perf_evlist__set_filter use perf_evsel__set_filter

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

Instead of calling perf_evsel__apply_filter straight away, so that we can, in the next patches, expand the filter with more conditions before actually calling the ioctl to pass the end result filter to the kernel.

Now we need to call perf_evlist__apply_filters() after the filter is completely setup, i.e. do the ioctl calls.

The perf_evlist__apply_filters() method was already in place, because that is the model for the other tools that receives filters in the command line: go on setting then in the evsel->filter and only at the end, after parsing the whole command line, apply them.

We get, as a bonus, a more expressive message that states which event, if any, failed to have the filter applied to, with an error message stating what happened.

Cc Adrian Hunter <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/builtin-trace.c | 18 ++++++++++++++----
 tools/perf/util/evlist.c   |  4 +---
 2 files changed, 15 insertions(+), 7 deletions(-)
tools/perf/builtin-trace.c +14 -4
index b10608680c01..c02b65a72410 100644
@@ -2314,6 +2314,7 @@ out_delete_sys_enter:
 static int trace__run(struct trace *trace, int argc, const char **argv)
 {
 	struct perf_evlist *evlist = trace->evlist;
+	struct perf_evsel *evsel;
 	int err = -1, i;
 	unsigned long before;
 	const bool forks = argc > 0;
@@ -2382,10 +2383,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 	else if (thread_map__pid(evlist->threads, 0) == -1)
 		err = perf_evlist__set_filter_pid(evlist, getpid());
 
-	if (err < 0) {
-		printf("err=%d,%s\n", -err, strerror(-err));
-		exit(1);
-	}
+	if (err < 0)
+		goto out_error_mem;
+
+	err = perf_evlist__apply_filters(evlist, &evsel);
+	if (err < 0)
+		goto out_error_apply_filters;
 
 	err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
 	if (err < 0)
@@ -2488,6 +2491,13 @@ out_error_open:
 out_error:
 	fprintf(trace->output, "%s\n", errbuf);
 	goto out_delete_evlist;
+
+out_error_apply_filters:
+	fprintf(trace->output,
+		"Failed to set filter \"%s\" on event %s with %d (%s)\n",
+		evsel->filter, perf_evsel__name(evsel), errno,
+		strerror_r(errno, errbuf, sizeof(errbuf)));
+	goto out_delete_evlist;
 }
 out_error_mem:
 	fprintf(trace->output, "Not enough memory to run!\n");
tools/perf/util/evlist.c +1 -3
index 51913284e8e3..f7d9c77ee31b 100644
@@ -1175,11 +1175,9 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
 {
 	struct perf_evsel *evsel;
 	int err = 0;
-	const int ncpus = cpu_map__nr(evlist->cpus),
-		  nthreads = thread_map__nr(evlist->threads);
 
 	evlist__for_each(evlist, evsel) {
-		err = perf_evsel__apply_filter(evsel, ncpus, nthreads, filter);
+		err = perf_evsel__set_filter(evsel, filter);
 		if (err)
 			break;
 	}
Signature · 1 line
2.1.0
author maintainer
#8 lore raw

PATCH 7/11 perf evsel: Introduce append_filter() method

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

To allow building filters in evsel->filter, that will eventually be applied via perf_evsel__apply_filter().

Cc Adrian Hunter <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/util/evsel.c | 17 +++++++++++++++++
 tools/perf/util/evsel.h |  2 ++
 2 files changed, 19 insertions(+)
tools/perf/util/evsel.c +17 -0
index ae925b9ce6dd..6cc97f37887d 100644
@@ -836,6 +836,23 @@ int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter)
 	return -1;
 }
 
+int perf_evsel__append_filter(struct perf_evsel *evsel,
+			      const char *op, const char *filter)
+{
+	char *new_filter;
+
+	if (evsel->filter == NULL)
+		return perf_evsel__set_filter(evsel, filter);
+
+	if (asprintf(&new_filter,"(%s) %s (%s)", evsel->filter, op, filter) > 0) {
+		free(evsel->filter);
+		evsel->filter = new_filter;
+		return 0;
+	}
+
+	return -1;
+}
+
 int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
 	return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
tools/perf/util/evsel.h +2 -0
index 8aea4baca080..fe9f3279632b 100644
@@ -183,6 +183,8 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel,
 			       bool use_sample_identifier);
 
 int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter);
+int perf_evsel__append_filter(struct perf_evsel *evsel,
+			      const char *op, const char *filter);
 int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
 			     const char *filter);
 int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads);
Signature · 1 line
2.1.0
author maintainer
#9 lore raw

PATCH 8/11 perf trace: Use event filters for the event qualifier list

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

We use raw_syscalls:sys_{enter,exit} events to show the syscalls, but were using a rather lazy/inneficient way to implement our 'strace -e' equivalent:
filter out after reading the events in the ring buffer.

Deflect more work to the kernel by appending a filter expression for that, that, together with the pid list, that is always present, if only to filter the tracer itself, reduces pressure on the ring buffer and otherwise use infrastructure already in place in the kernel to do early filtering.

If we use it with -v we can see the filter passed to the kernel, for instance, for this contrieved case:

  # trace -v -e \!open,close,write,poll,recvfrom,select,recvmsg,writev,sendmsg,read,futex,epoll_wait,ioctl,eventfd --filter-pids 2189,2566,1398,2692,4475,4532
<SNIP>
  (common_pid != 2514 && common_pid != 1398 && common_pid != 2189 && common_pid != 2566 && common_pid != 2692 && common_pid != 4475 && common_pid != 4532) && (id != 3 && id != 232 && id != 284 && id != 202 && id != 16 && id != 2 && id != 7 && id != 0 && id != 45 && id != 47 && id != 23 && id != 46 && id != 1 && id != 20)
     0.011 (0.011 ms): caribou/2295 eventfd2(flags: CLOEXEC|NONBLOCK) = 18
    16.946 (0.019 ms): caribou/2295 eventfd2(flags: CLOEXEC|NONBLOCK) = 18
    38.598 (0.167 ms): chronyd/794 socket(family: INET, type: DGRAM ) = 4
    38.603 (0.002 ms): chronyd/794 fcntl(fd: 4<socket:[239307]>, cmd: GETFD) = 0
    38.605 (0.001 ms): chronyd/794 fcntl(fd: 4<socket:[239307]>, cmd: SETFD, arg: 1) = 0
^C
 #
Cc Adrian Hunter <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/builtin-trace.c | 52 ++++++++++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 20 deletions(-)
tools/perf/builtin-trace.c +32 -20
index c02b65a72410..0ebf55bf20b3 100644
@@ -1187,7 +1187,6 @@ struct syscall {
 	int		    nr_args;
 	struct format_field *args;
 	const char	    *name;
-	bool		    filtered;
 	bool		    is_exit;
 	struct syscall_fmt  *fmt;
 	size_t		    (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
@@ -1550,19 +1549,6 @@ static int trace__read_syscall_info(struct trace *trace, int id)
 	sc = trace->syscalls.table + id;
 	sc->name = name;
 
-	if (trace->ev_qualifier) {
-		bool in = strlist__find(trace->ev_qualifier, name) != NULL;
-
-		if (!(in ^ trace->not_ev_qualifier)) {
-			sc->filtered = true;
-			/*
-			 * No need to do read tracepoint information since this will be
-			 * filtered out.
-			 */
-			return 0;
-		}
-	}
-
 	sc->fmt  = syscall_fmt__find(sc->name);
 
 	snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
@@ -1823,9 +1809,6 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
 	if (sc == NULL)
 		return -1;
 
-	if (sc->filtered)
-		return 0;
-
 	thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
 	ttrace = thread__trace(thread, trace->output);
 	if (ttrace == NULL)
@@ -1881,9 +1864,6 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
 	if (sc == NULL)
 		return -1;
 
-	if (sc->filtered)
-		return 0;
-
 	thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
 	ttrace = thread__trace(thread, trace->output);
 	if (ttrace == NULL)
@@ -2310,6 +2290,26 @@ out_delete_sys_enter:
 	goto out;
 }
 
+static int trace__set_ev_qualifier_filter(struct trace *trace)
+{
+	int err = -1;
+	char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
+						trace->ev_qualifier_ids.nr,
+						trace->ev_qualifier_ids.entries);
+
+	if (filter == NULL)
+		goto out_enomem;
+
+	if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
+		err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
+
+	free(filter);
+out:
+	return err;
+out_enomem:
+	errno = ENOMEM;
+	goto out;
+}
 
 static int trace__run(struct trace *trace, int argc, const char **argv)
 {
@@ -2386,6 +2386,14 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 	if (err < 0)
 		goto out_error_mem;
 
+	if (trace->ev_qualifier_ids.nr > 0) {
+		err = trace__set_ev_qualifier_filter(trace);
+		if (err < 0)
+			goto out_errno;
+	}
+
+	pr_debug("%s\n", trace->syscalls.events.sys_exit->filter);
+
 	err = perf_evlist__apply_filters(evlist, &evsel);
 	if (err < 0)
 		goto out_error_apply_filters;
@@ -2502,6 +2510,10 @@ out_error_apply_filters:
 out_error_mem:
 	fprintf(trace->output, "Not enough memory to run!\n");
 	goto out_delete_evlist;
+
+out_errno:
+	fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
+	goto out_delete_evlist;
 }
 
 static int trace__replay(struct trace *trace)
Signature · 1 line
2.1.0
author maintainer
#10 lore raw

PATCH 9/11 perf probe: Delete an unnecessary check before the function call "strfilter__delete"

In reply to Arnaldo Carvalho de Melo

From: Markus Elfring <[email protected]>

The strfilter__delete() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed.

This issue was detected by using the Coccinelle software.

---
 tools/perf/builtin-probe.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
tools/perf/builtin-probe.c +1 -2
index 1272559fa22d..b81cec33b4b2 100644
@@ -297,8 +297,7 @@ static void cleanup_params(void)
 		clear_perf_probe_event(params.events + i);
 	line_range__clear(&params.line_range);
 	free(params.target);
-	if (params.filter)
-		strfilter__delete(params.filter);
+	strfilter__delete(params.filter);
 	memset(&params, 0, sizeof(params));
 }
 
Signature · 1 line
2.1.0
author maintainer
#11 lore raw

PATCH 10/11 perf record: Let user have timestamps with per-thread recording

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

If the option -T is used with option --per-thread, then time is still not sampled. Fix that by using OPT_BOOLEAN_SET to distinguish when the user used the -T option as opposed to the default case when timestamps are enabled but only for per-cpu recording.

---
 tools/perf/builtin-record.c | 4 +++-
 tools/perf/perf.h           | 1 +
 tools/perf/util/evsel.c     | 3 ++-
 3 files changed, 6 insertions(+), 2 deletions(-)
tools/perf/builtin-record.c +3 -1
index de165a1b9240..283fe96bdfc1 100644
@@ -1030,7 +1030,9 @@ struct option __record_options[] = {
 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
 		    "per thread counts"),
 	OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"),
-	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Record the sample timestamps"),
+	OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time,
+			&record.opts.sample_time_set,
+			"Record the sample timestamps"),
 	OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
 		    "don't sample"),
tools/perf/perf.h +1 -0
index 4a5827fff799..937b16aa0300 100644
@@ -51,6 +51,7 @@ struct record_opts {
 	bool	     sample_address;
 	bool	     sample_weight;
 	bool	     sample_time;
+	bool	     sample_time_set;
 	bool	     period;
 	bool	     sample_intr_regs;
 	bool	     running_time;
tools/perf/util/evsel.c +2 -1
index 6cc97f37887d..83c08037e7e2 100644
@@ -707,7 +707,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 	 */
 	if (opts->sample_time &&
 	    (!perf_missing_features.sample_id_all &&
-	    (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu)))
+	    (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu ||
+	     opts->sample_time_set)))
 		perf_evsel__set_sample_bit(evsel, TIME);
 
 	if (opts->raw_samples && !evsel->no_aux_samples) {
Signature · 1 line
2.1.0
author maintainer
#12 lore raw

PATCH 11/11 tools lib api debugfs: Check for tracefs when reporting errors

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

Now that we have two mountpoints, one for debugfs and another, for tracefs, we end up needing to check permissions for both, so, on a system with default config we were always asking the user to check the permission of the debugfs mountpoint, even when it was already sufficient. Fix it.

E.g.:

  $ trace -e nanosleep usleep 1
  Error: No permissions to read /sys/kernel/debug/tracing/events/raw_syscalls/sys_(enter|exit)
  Hint:  Try 'sudo mount -o remount,mode=755 /sys/kernel/debug'
  $ sudo mount -o remount,mode=755 /sys/kernel/debug
  $ trace -e nanosleep usleep 1
  Error: No permissions to read /sys/kernel/debug/tracing/events/raw_syscalls/sys_(enter|exit)
  Hint:  Try 'sudo mount -o remount,mode=755 /sys/kernel/debug/tracing'
  $ sudo mount -o remount,mode=755 /sys/kernel/debug/tracing
  $ trace -e nanosleep usleep 1
     0.326 ( 0.061 ms): usleep/11961 nanosleep(rqtp: 0x7ffef1081c50) = 0
  $
---
 tools/lib/api/fs/debugfs.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)
tools/lib/api/fs/debugfs.c +13 -2
index 8305b3e9d48e..eb7cf4d18f8a 100644
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 
 #include "debugfs.h"
+#include "tracefs.h"
 
 #ifndef DEBUGFS_DEFAULT_PATH
 #define DEBUGFS_DEFAULT_PATH		"/sys/kernel/debug"
@@ -94,11 +95,21 @@ int debugfs__strerror_open(int err, char *buf, size_t size, const char *filename
 			 "Hint:\tIs the debugfs filesystem mounted?\n"
 			 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
 		break;
-	case EACCES:
+	case EACCES: {
+		const char *mountpoint = debugfs_mountpoint;
+
+		if (!access(debugfs_mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) {
+			const char *tracefs_mntpoint = tracefs_find_mountpoint();
+
+			if (tracefs_mntpoint)
+				mountpoint = tracefs_mntpoint;
+		}
+
 		snprintf(buf, size,
 			 "Error:\tNo permissions to read %s/%s\n"
 			 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
-			 debugfs_mountpoint, filename, debugfs_mountpoint);
+			 debugfs_mountpoint, filename, mountpoint);
+	}
 		break;
 	default:
 		snprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf)));
Signature · 1 line
2.1.0