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>
This commit is contained in:
committed by
Steven Rostedt
parent
68950619f8
commit
5855fead9c
@@ -22,6 +22,7 @@
|
|||||||
#include <linux/hardirq.h>
|
#include <linux/hardirq.h>
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/bsearch.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ftrace.h>
|
#include <linux/ftrace.h>
|
||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
@@ -1300,6 +1301,19 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ftrace_cmp_recs(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct dyn_ftrace *reca = a;
|
||||||
|
const struct dyn_ftrace *recb = b;
|
||||||
|
|
||||||
|
if (reca->ip > recb->ip)
|
||||||
|
return 1;
|
||||||
|
if (reca->ip < recb->ip)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ftrace_location - return true if the ip giving is a traced location
|
* ftrace_location - return true if the ip giving is a traced location
|
||||||
* @ip: the instruction pointer to check
|
* @ip: the instruction pointer to check
|
||||||
@@ -1313,11 +1327,17 @@ int ftrace_location(unsigned long ip)
|
|||||||
{
|
{
|
||||||
struct ftrace_page *pg;
|
struct ftrace_page *pg;
|
||||||
struct dyn_ftrace *rec;
|
struct dyn_ftrace *rec;
|
||||||
|
struct dyn_ftrace key;
|
||||||
|
|
||||||
do_for_each_ftrace_rec(pg, rec) {
|
key.ip = ip;
|
||||||
if (rec->ip == ip)
|
|
||||||
|
for (pg = ftrace_pages_start; pg; pg = pg->next) {
|
||||||
|
rec = bsearch(&key, pg->records, pg->index,
|
||||||
|
sizeof(struct dyn_ftrace),
|
||||||
|
ftrace_cmp_recs);
|
||||||
|
if (rec)
|
||||||
return 1;
|
return 1;
|
||||||
} while_for_each_ftrace_rec();
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3587,18 +3607,6 @@ static void ftrace_swap_recs(void *a, void *b, int size)
|
|||||||
*recb = t;
|
*recb = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ftrace_cmp_recs(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const struct dyn_ftrace *reca = a;
|
|
||||||
const struct dyn_ftrace *recb = b;
|
|
||||||
|
|
||||||
if (reca->ip > recb->ip)
|
|
||||||
return 1;
|
|
||||||
if (reca->ip < recb->ip)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ftrace_process_locs(struct module *mod,
|
static int ftrace_process_locs(struct module *mod,
|
||||||
unsigned long *start,
|
unsigned long *start,
|
||||||
unsigned long *end)
|
unsigned long *end)
|
||||||
|
|||||||
Reference in New Issue
Block a user