Commit-ID:  78b83e8b12b4467540ca501c7c019e9d46051957
Gitweb:     http://git.kernel.org/tip/78b83e8b12b4467540ca501c7c019e9d46051957
Author:     Namhyung Kim <namhy...@kernel.org>
AuthorDate: Sun, 18 Jun 2017 23:23:01 +0900
Committer:  Arnaldo Carvalho de Melo <a...@redhat.com>
CommitDate: Mon, 19 Jun 2017 22:05:53 -0300

perf ftrace: Add option for function filtering

The -T/--trace-funcs and -N/--notrace-funcs options are to specify
functions to enable/disable tracing dynamically.

The -G/--graph-funcs and -g/--nograph-funcs options are to set filters
for function graph tracer.

For example, to trace fault handling functions only:

  $ sudo perf ftrace -T *fault hello
   0)               |  __do_page_fault() {
   0)               |    handle_mm_fault() {
   0)   2.117 us    |      __handle_mm_fault();
   0)   3.627 us    |    }
   0)   7.811 us    |  }
   0)               |  __do_page_fault() {
   0)               |    handle_mm_fault() {
   0)   2.014 us    |      __handle_mm_fault();
   0)   2.424 us    |    }
   0)   2.951 us    |  }
   ...

To trace all functions executed in __do_page_fault:

  $ sudo perf ftrace -G __do_page_fault hello
   2)               |  __do_page_fault() {
   3)   0.060 us    |    down_read_trylock();
   3)               |    find_vma() {
   3)   0.075 us    |      vmacache_find();
   3)   0.053 us    |      vmacache_update();
   3)   1.246 us    |    }
   3)               |    handle_mm_fault() {
   3)   0.063 us    |      __rcu_read_lock();
   3)   0.056 us    |      mem_cgroup_from_task();
   3)   0.057 us    |      __rcu_read_unlock();
   3)               |      __handle_mm_fault() {
   3)               |        filemap_map_pages() {
   3)   0.058 us    |          __rcu_read_lock();
   3)               |          alloc_set_pte() {
   ...

But don't want to show details in handle_mm_fault:

  $ sudo perf ftrace -G __do_page_fault -g handle_mm_fault hello
   3)               |  __do_page_fault() {
   3)   0.049 us    |    down_read_trylock();
   3)               |    find_vma() {
   3)   0.048 us    |      vmacache_find();
   3)   0.041 us    |      vmacache_update();
   3)   0.680 us    |    }
   3)   0.036 us    |    up_read();
   3)   4.547 us    |  } /* __do_page_fault */
   ...

Signed-off-by: Namhyung Kim <namhy...@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Frederic Weisbecker <fweis...@gmail.com>
Cc: Jiri Olsa <jo...@kernel.org>
Cc: Masami Hiramatsu <mhira...@kernel.org>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Steven Rostedt <rost...@goodmis.org>
Cc: kernel-t...@lge.com
Link: http://lkml.kernel.org/r/20170618142302.25390-3-namhy...@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <a...@redhat.com>
---
 tools/perf/Documentation/perf-ftrace.txt |  30 ++++++++
 tools/perf/builtin-ftrace.c              | 117 +++++++++++++++++++++++++++++--
 2 files changed, 141 insertions(+), 6 deletions(-)

diff --git a/tools/perf/Documentation/perf-ftrace.txt 
b/tools/perf/Documentation/perf-ftrace.txt
index 6e6a8b2..78d6126 100644
--- a/tools/perf/Documentation/perf-ftrace.txt
+++ b/tools/perf/Documentation/perf-ftrace.txt
@@ -48,6 +48,36 @@ OPTIONS
        Ranges of CPUs are specified with -: 0-2.
        Default is to trace on all online CPUs.
 
+-T::
+--trace-funcs=::
+       Only trace functions given by the argument.  Multiple functions
+       can be given by using this option more than once.  The function
+       argument also can be a glob pattern.  It will be passed to
+       'set_ftrace_filter' in tracefs.
+
+-N::
+--notrace-funcs=::
+       Do not trace functions given by the argument.  Like -T option,
+       this can be used more than once to specify multiple functions
+       (or glob patterns).  It will be passed to 'set_ftrace_notrace'
+       in tracefs.
+
+-G::
+--graph-funcs=::
+       Set graph filter on the given function (or a glob pattern).
+       This is useful for the function_graph tracer only and enables
+       tracing for functions executed from the given function.
+       This can be used more than once to specify multiple functions.
+       It will be passed to 'set_graph_function' in tracefs.
+
+-g::
+--nograph-funcs=::
+       Set graph notrace filter on the given function (or a glob pattern).
+       Like -G option, this is useful for the function_graph tracer only
+       and disables tracing for function executed from the given function.
+       This can be used more than once to specify multiple functions.
+       It will be passed to 'set_graph_notrace' in tracefs.
+
 
 SEE ALSO
 --------
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 982b98e..3285375 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -28,9 +28,18 @@
 #define DEFAULT_TRACER  "function_graph"
 
 struct perf_ftrace {
-       struct perf_evlist *evlist;
-       struct target target;
-       const char *tracer;
+       struct perf_evlist      *evlist;
+       struct target           target;
+       const char              *tracer;
+       struct list_head        filters;
+       struct list_head        notrace;
+       struct list_head        graph_funcs;
+       struct list_head        nograph_funcs;
+};
+
+struct filter_entry {
+       struct list_head        list;
+       char                    name[];
 };
 
 static bool done;
@@ -104,6 +113,7 @@ static int append_tracing_file(const char *name, const char 
*val)
 }
 
 static int reset_tracing_cpu(void);
+static void reset_tracing_filters(void);
 
 static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
 {
@@ -119,6 +129,7 @@ static int reset_tracing_files(struct perf_ftrace *ftrace 
__maybe_unused)
        if (reset_tracing_cpu() < 0)
                return -1;
 
+       reset_tracing_filters();
        return 0;
 }
 
@@ -184,6 +195,48 @@ static int reset_tracing_cpu(void)
        return ret;
 }
 
+static int __set_tracing_filter(const char *filter_file, struct list_head 
*funcs)
+{
+       struct filter_entry *pos;
+
+       list_for_each_entry(pos, funcs, list) {
+               if (append_tracing_file(filter_file, pos->name) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static int set_tracing_filters(struct perf_ftrace *ftrace)
+{
+       int ret;
+
+       ret = __set_tracing_filter("set_ftrace_filter", &ftrace->filters);
+       if (ret < 0)
+               return ret;
+
+       ret = __set_tracing_filter("set_ftrace_notrace", &ftrace->notrace);
+       if (ret < 0)
+               return ret;
+
+       ret = __set_tracing_filter("set_graph_function", &ftrace->graph_funcs);
+       if (ret < 0)
+               return ret;
+
+       /* old kernels do not have this filter */
+       __set_tracing_filter("set_graph_notrace", &ftrace->nograph_funcs);
+
+       return ret;
+}
+
+static void reset_tracing_filters(void)
+{
+       write_tracing_file("set_ftrace_filter", " ");
+       write_tracing_file("set_ftrace_notrace", " ");
+       write_tracing_file("set_graph_function", " ");
+       write_tracing_file("set_graph_notrace", " ");
+}
+
 static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char 
**argv)
 {
        char *trace_file;
@@ -226,6 +279,11 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int 
argc, const char **argv)
                goto out_reset;
        }
 
+       if (set_tracing_filters(ftrace) < 0) {
+               pr_err("failed to set tracing filters\n");
+               goto out_reset;
+       }
+
        if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
                pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
                goto out_reset;
@@ -310,6 +368,32 @@ static int perf_ftrace_config(const char *var, const char 
*value, void *cb)
        return -1;
 }
 
+static int parse_filter_func(const struct option *opt, const char *str,
+                            int unset __maybe_unused)
+{
+       struct list_head *head = opt->value;
+       struct filter_entry *entry;
+
+       entry = malloc(sizeof(*entry) + strlen(str) + 1);
+       if (entry == NULL)
+               return -ENOMEM;
+
+       strcpy(entry->name, str);
+       list_add_tail(&entry->list, head);
+
+       return 0;
+}
+
+static void delete_filter_func(struct list_head *head)
+{
+       struct filter_entry *pos, *tmp;
+
+       list_for_each_entry_safe(pos, tmp, head, list) {
+               list_del(&pos->list);
+               free(pos);
+       }
+}
+
 int cmd_ftrace(int argc, const char **argv)
 {
        int ret;
@@ -333,9 +417,22 @@ int cmd_ftrace(int argc, const char **argv)
                    "system-wide collection from all CPUs"),
        OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu",
                    "list of cpus to monitor"),
+       OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func",
+                    "trace given functions only", parse_filter_func),
+       OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func",
+                    "do not trace given functions", parse_filter_func),
+       OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func",
+                    "Set graph filter on given functions", parse_filter_func),
+       OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func",
+                    "Set nograph filter on given functions", 
parse_filter_func),
        OPT_END()
        };
 
+       INIT_LIST_HEAD(&ftrace.filters);
+       INIT_LIST_HEAD(&ftrace.notrace);
+       INIT_LIST_HEAD(&ftrace.graph_funcs);
+       INIT_LIST_HEAD(&ftrace.nograph_funcs);
+
        ret = perf_config(perf_ftrace_config, &ftrace);
        if (ret < 0)
                return -1;
@@ -351,12 +448,14 @@ int cmd_ftrace(int argc, const char **argv)
 
                target__strerror(&ftrace.target, ret, errbuf, 512);
                pr_err("%s\n", errbuf);
-               return -EINVAL;
+               goto out_delete_filters;
        }
 
        ftrace.evlist = perf_evlist__new();
-       if (ftrace.evlist == NULL)
-               return -ENOMEM;
+       if (ftrace.evlist == NULL) {
+               ret = -ENOMEM;
+               goto out_delete_filters;
+       }
 
        ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target);
        if (ret < 0)
@@ -367,5 +466,11 @@ int cmd_ftrace(int argc, const char **argv)
 out_delete_evlist:
        perf_evlist__delete(ftrace.evlist);
 
+out_delete_filters:
+       delete_filter_func(&ftrace.filters);
+       delete_filter_func(&ftrace.notrace);
+       delete_filter_func(&ftrace.graph_funcs);
+       delete_filter_func(&ftrace.nograph_funcs);
+
        return ret;
 }

Reply via email to