diff options
author | Steven Rostedt <srostedt@redhat.com> | 2011-12-16 19:27:42 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2011-12-21 07:20:50 -0500 |
commit | 5855fead9cc358adebd6bdeec202d040c623ae38 (patch) | |
tree | c95d272ff41b7873cc33feef3686ede3f020d4cd | |
parent | 68950619f8c82e468d8976130462617abea605a8 (diff) |
ftrace: Use bsearch to find record ip
Now that each set of pages in the function list are sorted by
ip, we can use bsearch to find a record within each set of pages.
This speeds up the ftrace_location() function by magnitudes.
For archs (like x86) that need to add a breakpoint at every function
that will be converted from a nop to a callback and vice versa,
the breakpoint callback needs to know if the breakpoint was for
ftrace or not. It requires finding the breakpoint ip within the
records. Doing a linear search is extremely inefficient. It is
a must to be able to do a fast binary search to find these locations.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | kernel/trace/ftrace.c | 38 |
1 files changed, 23 insertions, 15 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 2d6f8bcd1884..dcd3a814d39b 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/hardirq.h> | 22 | #include <linux/hardirq.h> |
23 | #include <linux/kthread.h> | 23 | #include <linux/kthread.h> |
24 | #include <linux/uaccess.h> | 24 | #include <linux/uaccess.h> |
25 | #include <linux/bsearch.h> | ||
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
26 | #include <linux/ftrace.h> | 27 | #include <linux/ftrace.h> |
27 | #include <linux/sysctl.h> | 28 | #include <linux/sysctl.h> |
@@ -1300,6 +1301,19 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) | |||
1300 | } \ | 1301 | } \ |
1301 | } | 1302 | } |
1302 | 1303 | ||
1304 | |||
1305 | static int ftrace_cmp_recs(const void *a, const void *b) | ||
1306 | { | ||
1307 | const struct dyn_ftrace *reca = a; | ||
1308 | const struct dyn_ftrace *recb = b; | ||
1309 | |||
1310 | if (reca->ip > recb->ip) | ||
1311 | return 1; | ||
1312 | if (reca->ip < recb->ip) | ||
1313 | return -1; | ||
1314 | return 0; | ||
1315 | } | ||
1316 | |||
1303 | /** | 1317 | /** |
1304 | * ftrace_location - return true if the ip giving is a traced location | 1318 | * ftrace_location - return true if the ip giving is a traced location |
1305 | * @ip: the instruction pointer to check | 1319 | * @ip: the instruction pointer to check |
@@ -1313,11 +1327,17 @@ int ftrace_location(unsigned long ip) | |||
1313 | { | 1327 | { |
1314 | struct ftrace_page *pg; | 1328 | struct ftrace_page *pg; |
1315 | struct dyn_ftrace *rec; | 1329 | struct dyn_ftrace *rec; |
1330 | struct dyn_ftrace key; | ||
1316 | 1331 | ||
1317 | do_for_each_ftrace_rec(pg, rec) { | 1332 | key.ip = ip; |
1318 | if (rec->ip == ip) | 1333 | |
1334 | for (pg = ftrace_pages_start; pg; pg = pg->next) { | ||
1335 | rec = bsearch(&key, pg->records, pg->index, | ||
1336 | sizeof(struct dyn_ftrace), | ||
1337 | ftrace_cmp_recs); | ||
1338 | if (rec) | ||
1319 | return 1; | 1339 | return 1; |
1320 | } while_for_each_ftrace_rec(); | 1340 | } |
1321 | 1341 | ||
1322 | return 0; | 1342 | return 0; |
1323 | } | 1343 | } |
@@ -3587,18 +3607,6 @@ static void ftrace_swap_recs(void *a, void *b, int size) | |||
3587 | *recb = t; | 3607 | *recb = t; |
3588 | } | 3608 | } |
3589 | 3609 | ||
3590 | static int ftrace_cmp_recs(const void *a, const void *b) | ||
3591 | { | ||
3592 | const struct dyn_ftrace *reca = a; | ||
3593 | const struct dyn_ftrace *recb = b; | ||
3594 | |||
3595 | if (reca->ip > recb->ip) | ||
3596 | return 1; | ||
3597 | if (reca->ip < recb->ip) | ||
3598 | return -1; | ||
3599 | return 0; | ||
3600 | } | ||
3601 | |||
3602 | static int ftrace_process_locs(struct module *mod, | 3610 | static int ftrace_process_locs(struct module *mod, |
3603 | unsigned long *start, | 3611 | unsigned long *start, |
3604 | unsigned long *end) | 3612 | unsigned long *end) |