diff options
author | Steven Rostedt (VMware) <rostedt@goodmis.org> | 2019-02-11 15:00:48 -0500 |
---|---|---|
committer | Steven Rostedt (VMware) <rostedt@goodmis.org> | 2019-02-15 13:10:09 -0500 |
commit | f79b3f338564e7674dbe6375bcf685c2ba483efe (patch) | |
tree | 481aa4a5340b5c1f3d9a167f06fce036ba08fbc7 /kernel | |
parent | 85acbb21b9310043692cf18b1fd14067b5a25ccd (diff) |
ftrace: Allow enabling of filters via index of available_filter_functions
Enabling of large number of functions by echoing in a large subset of the
functions in available_filter_functions can take a very long time. The
process requires testing all functions registered by the function tracer
(which is in the 10s of thousands), and doing a kallsyms lookup to convert
the ip address into a name, then comparing that name with the string passed
in.
When a function causes the function tracer to crash the system, a binary
bisect of the available_filter_functions can be done to find the culprit.
But this requires passing in half of the functions in
available_filter_functions over and over again, which makes it basically a
O(n^2) operation. With 40,000 functions, that ends up bing 1,600,000,000
opertions! And enabling this can take over 20 minutes.
As a quick speed up, if a number is passed into one of the filter files,
instead of doing a search, it just enables the function at the corresponding
line of the available_filter_functions file. That is:
# echo 50 > set_ftrace_filter
# cat set_ftrace_filter
x86_pmu_commit_txn
# head -50 available_filter_functions | tail -1
x86_pmu_commit_txn
This allows setting of half the available_filter_functions to take place in
less than a second!
# time seq 20000 > set_ftrace_filter
real 0m0.042s
user 0m0.005s
sys 0m0.015s
# wc -l set_ftrace_filter
20000 set_ftrace_filter
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/ftrace.c | 30 | ||||
-rw-r--r-- | kernel/trace/trace.h | 1 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 5 |
3 files changed, 36 insertions, 0 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index aac7847c0214..fa79323331b2 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -3702,6 +3702,31 @@ enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int clear_filter) | |||
3702 | } | 3702 | } |
3703 | 3703 | ||
3704 | static int | 3704 | static int |
3705 | add_rec_by_index(struct ftrace_hash *hash, struct ftrace_glob *func_g, | ||
3706 | int clear_filter) | ||
3707 | { | ||
3708 | long index = simple_strtoul(func_g->search, NULL, 0); | ||
3709 | struct ftrace_page *pg; | ||
3710 | struct dyn_ftrace *rec; | ||
3711 | |||
3712 | /* The index starts at 1 */ | ||
3713 | if (--index < 0) | ||
3714 | return 0; | ||
3715 | |||
3716 | do_for_each_ftrace_rec(pg, rec) { | ||
3717 | if (pg->index <= index) { | ||
3718 | index -= pg->index; | ||
3719 | /* this is a double loop, break goes to the next page */ | ||
3720 | break; | ||
3721 | } | ||
3722 | rec = &pg->records[index]; | ||
3723 | enter_record(hash, rec, clear_filter); | ||
3724 | return 1; | ||
3725 | } while_for_each_ftrace_rec(); | ||
3726 | return 0; | ||
3727 | } | ||
3728 | |||
3729 | static int | ||
3705 | ftrace_match_record(struct dyn_ftrace *rec, struct ftrace_glob *func_g, | 3730 | ftrace_match_record(struct dyn_ftrace *rec, struct ftrace_glob *func_g, |
3706 | struct ftrace_glob *mod_g, int exclude_mod) | 3731 | struct ftrace_glob *mod_g, int exclude_mod) |
3707 | { | 3732 | { |
@@ -3769,6 +3794,11 @@ match_records(struct ftrace_hash *hash, char *func, int len, char *mod) | |||
3769 | if (unlikely(ftrace_disabled)) | 3794 | if (unlikely(ftrace_disabled)) |
3770 | goto out_unlock; | 3795 | goto out_unlock; |
3771 | 3796 | ||
3797 | if (func_g.type == MATCH_INDEX) { | ||
3798 | found = add_rec_by_index(hash, &func_g, clear_filter); | ||
3799 | goto out_unlock; | ||
3800 | } | ||
3801 | |||
3772 | do_for_each_ftrace_rec(pg, rec) { | 3802 | do_for_each_ftrace_rec(pg, rec) { |
3773 | 3803 | ||
3774 | if (rec->flags & FTRACE_FL_DISABLED) | 3804 | if (rec->flags & FTRACE_FL_DISABLED) |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index a34fa5e76abb..ae7df090b93e 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -1459,6 +1459,7 @@ enum regex_type { | |||
1459 | MATCH_MIDDLE_ONLY, | 1459 | MATCH_MIDDLE_ONLY, |
1460 | MATCH_END_ONLY, | 1460 | MATCH_END_ONLY, |
1461 | MATCH_GLOB, | 1461 | MATCH_GLOB, |
1462 | MATCH_INDEX, | ||
1462 | }; | 1463 | }; |
1463 | 1464 | ||
1464 | struct regex { | 1465 | struct regex { |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index f052ecb085e9..ade606c33231 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -825,6 +825,9 @@ enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not) | |||
825 | 825 | ||
826 | *search = buff; | 826 | *search = buff; |
827 | 827 | ||
828 | if (isdigit(buff[0])) | ||
829 | return MATCH_INDEX; | ||
830 | |||
828 | for (i = 0; i < len; i++) { | 831 | for (i = 0; i < len; i++) { |
829 | if (buff[i] == '*') { | 832 | if (buff[i] == '*') { |
830 | if (!i) { | 833 | if (!i) { |
@@ -862,6 +865,8 @@ static void filter_build_regex(struct filter_pred *pred) | |||
862 | } | 865 | } |
863 | 866 | ||
864 | switch (type) { | 867 | switch (type) { |
868 | /* MATCH_INDEX should not happen, but if it does, match full */ | ||
869 | case MATCH_INDEX: | ||
865 | case MATCH_FULL: | 870 | case MATCH_FULL: |
866 | r->match = regex_match_full; | 871 | r->match = regex_match_full; |
867 | break; | 872 | break; |