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 <namhyung@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: kernel-team@lge.com Link: http://lkml.kernel.org/r/20170618142302.25390-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
29681bc5bb
commit
78b83e8b12
@ -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
|
||||
--------
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user