[RFC 2/4] perf, ftrace: Add filter support for ftrace:function tracepoint

From: Jiri Olsa
Date: Mon Jul 11 2011 - 09:23:16 EST


Add support to specify perf filter for function trace.

Standard perf filter could be now used for ftrace:function tracepoint like:

# ./perf stat -e ftrace:function --filter "ip == sys_open || ip == sys_close" sleep 1

Performance counter stats for 'sleep 1':

9 ftrace:function

1.003097430 seconds time elapsed

Details:
- the value for ip and parent_ip fields gets translated to the
function value (mcount return IP). The ip and parent_ip are then
processed as integer values.

---
include/linux/ftrace.h | 2 ++
kernel/trace/ftrace.c | 23 +++++++++++++++++++++++
kernel/trace/trace_events_filter.c | 32 ++++++++++++++++++++++++++------
3 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index ed0eb52..f858e97 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -157,6 +157,8 @@ extern void
unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
extern void unregister_ftrace_function_probe_all(char *glob);

+extern int ftrace_function_rec_ip(char *func, unsigned long long *ip);
+
extern int ftrace_text_reserved(void *start, void *end);

enum {
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6d6e0d0..7325ae4 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2599,6 +2599,29 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
return count;
}

+int ftrace_function_rec_ip(char *func, unsigned long long *ip)
+{
+ struct ftrace_page *pg;
+ struct dyn_ftrace *rec;
+ int len = strlen(func);
+ int found = 0;
+
+ mutex_lock(&ftrace_lock);
+
+ do_for_each_ftrace_rec(pg, rec) {
+ if (!ftrace_match_record(rec, NULL, func, len, MATCH_FULL))
+ continue;
+
+ *ip = rec->ip;
+ found = 1;
+ break;
+ } while_for_each_ftrace_rec();
+
+ mutex_unlock(&ftrace_lock);
+
+ return found ? 0 : -EINVAL;
+}
+
enum {
PROBE_TEST_FUNC = 1,
PROBE_TEST_DATA = 2
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 256764e..dd5c648 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -883,8 +883,12 @@ static bool is_string_field(struct ftrace_event_field *field)
field->filter_type == FILTER_PTR_STRING;
}

-static int is_legal_op(struct ftrace_event_field *field, int op)
+static int is_legal_op(struct ftrace_event_call *call,
+ struct ftrace_event_field *field, int op)
{
+ if ((call->event.type == TRACE_FN) &&
+ (op != OP_EQ && op != OP_NE))
+ return 0;
if (is_string_field(field) &&
(op != OP_EQ && op != OP_NE && op != OP_GLOB))
return 0;
@@ -937,6 +941,24 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size,
return fn;
}

+static int pred_get_val(struct ftrace_event_call *call,
+ struct filter_pred *pred,
+ struct ftrace_event_field *field,
+ unsigned long long *val)
+{
+ int ret;
+
+ if (call->event.type == TRACE_FN)
+ return ftrace_function_rec_ip(pred->regex.pattern, val);
+
+ if (field->is_signed)
+ ret = strict_strtoll(pred->regex.pattern, 0, val);
+ else
+ ret = strict_strtoull(pred->regex.pattern, 0, val);
+
+ return ret;
+}
+
static int filter_add_pred(struct filter_parse_state *ps,
struct ftrace_event_call *call,
struct event_filter *filter,
@@ -964,7 +986,7 @@ static int filter_add_pred(struct filter_parse_state *ps,

pred->offset = field->offset;

- if (!is_legal_op(field, pred->op)) {
+ if (!is_legal_op(call, field, pred->op)) {
parse_error(ps, FILT_ERR_ILLEGAL_FIELD_OP, 0);
return -EINVAL;
}
@@ -980,14 +1002,12 @@ static int filter_add_pred(struct filter_parse_state *ps,
else
fn = filter_pred_pchar;
} else {
- if (field->is_signed)
- ret = strict_strtoll(pred->regex.pattern, 0, &val);
- else
- ret = strict_strtoull(pred->regex.pattern, 0, &val);
+ ret = pred_get_val(call, pred, field, &val);
if (ret) {
parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0);
return -EINVAL;
}
+
pred->val = val;

fn = select_comparison_fn(pred->op, field->size,
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/