aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorSteven Rostedt (VMware) <rostedt@goodmis.org>2019-02-11 15:00:48 -0500
committerSteven Rostedt (VMware) <rostedt@goodmis.org>2019-02-15 13:10:09 -0500
commitf79b3f338564e7674dbe6375bcf685c2ba483efe (patch)
tree481aa4a5340b5c1f3d9a167f06fce036ba08fbc7 /kernel
parent85acbb21b9310043692cf18b1fd14067b5a25ccd (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.c30
-rw-r--r--kernel/trace/trace.h1
-rw-r--r--kernel/trace/trace_events_filter.c5
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
3704static int 3704static int
3705add_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
3729static int
3705ftrace_match_record(struct dyn_ftrace *rec, struct ftrace_glob *func_g, 3730ftrace_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
1464struct regex { 1465struct 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;