Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 169510
b: refs/heads/master
c: 6fb2915
h: refs/heads/master
v: v3
  • Loading branch information
Li Zefan authored and Ingo Molnar committed Oct 15, 2009
1 parent 4f785d6 commit 95f0a91
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 36 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b0f1a59a98d7ac2102e7e4f22904c26d564a5628
refs/heads/master: 6fb2915df7f0747d9044da9dbff5b46dc2e20830
11 changes: 10 additions & 1 deletion trunk/include/linux/ftrace_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ extern char *trace_profile_buf_nmi;
#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */

extern void destroy_preds(struct ftrace_event_call *call);
extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
extern int filter_match_preds(struct event_filter *filter, void *rec);
extern int filter_current_check_discard(struct ring_buffer *buffer,
struct ftrace_event_call *call,
void *rec,
Expand Down Expand Up @@ -186,4 +186,13 @@ do { \
__trace_printk(ip, fmt, ##args); \
} while (0)

#ifdef CONFIG_EVENT_PROFILE
struct perf_event;
extern int ftrace_profile_enable(int event_id);
extern void ftrace_profile_disable(int event_id);
extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
char *filter_str);
extern void ftrace_profile_free_filter(struct perf_event *event);
#endif

#endif /* _LINUX_FTRACE_EVENT_H */
1 change: 1 addition & 0 deletions trunk/include/linux/perf_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ struct perf_counter_attr {
#define PERF_COUNTER_IOC_RESET _IO ('$', 3)
#define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_COUNTER_IOC_SET_OUTPUT _IO ('$', 5)
#define PERF_COUNTER_IOC_SET_FILTER _IOW('$', 6, char *)

enum perf_counter_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
Expand Down
6 changes: 6 additions & 0 deletions trunk/include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ struct perf_event_attr {
#define PERF_EVENT_IOC_RESET _IO ('$', 3)
#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)

enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
Expand Down Expand Up @@ -633,7 +634,12 @@ struct perf_event {

struct pid_namespace *ns;
u64 id;

#ifdef CONFIG_EVENT_PROFILE
struct event_filter *filter;
#endif

#endif /* CONFIG_PERF_EVENTS */
};

/**
Expand Down
80 changes: 73 additions & 7 deletions trunk/kernel/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/anon_inodes.h>
#include <linux/kernel_stat.h>
#include <linux/perf_event.h>
#include <linux/ftrace_event.h>

#include <asm/irq_regs.h>

Expand Down Expand Up @@ -1658,13 +1659,16 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu)
return ERR_PTR(err);
}

static void perf_event_free_filter(struct perf_event *event);

static void free_event_rcu(struct rcu_head *head)
{
struct perf_event *event;

event = container_of(head, struct perf_event, rcu_head);
if (event->ns)
put_pid_ns(event->ns);
perf_event_free_filter(event);
kfree(event);
}

Expand Down Expand Up @@ -1974,7 +1978,8 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
return ret;
}

int perf_event_set_output(struct perf_event *event, int output_fd);
static int perf_event_set_output(struct perf_event *event, int output_fd);
static int perf_event_set_filter(struct perf_event *event, void __user *arg);

static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
Expand Down Expand Up @@ -2002,6 +2007,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PERF_EVENT_IOC_SET_OUTPUT:
return perf_event_set_output(event, arg);

case PERF_EVENT_IOC_SET_FILTER:
return perf_event_set_filter(event, (void __user *)arg);

default:
return -ENOTTY;
}
Expand Down Expand Up @@ -3806,9 +3814,14 @@ static int perf_swevent_is_counting(struct perf_event *event)
return 1;
}

static int perf_tp_event_match(struct perf_event *event,
struct perf_sample_data *data);

static int perf_swevent_match(struct perf_event *event,
enum perf_type_id type,
u32 event_id, struct pt_regs *regs)
u32 event_id,
struct perf_sample_data *data,
struct pt_regs *regs)
{
if (!perf_swevent_is_counting(event))
return 0;
Expand All @@ -3826,6 +3839,10 @@ static int perf_swevent_match(struct perf_event *event,
return 0;
}

if (event->attr.type == PERF_TYPE_TRACEPOINT &&
!perf_tp_event_match(event, data))
return 0;

return 1;
}

Expand All @@ -3842,7 +3859,7 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx,

rcu_read_lock();
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
if (perf_swevent_match(event, type, event_id, regs))
if (perf_swevent_match(event, type, event_id, data, regs))
perf_swevent_add(event, nr, nmi, data, regs);
}
rcu_read_unlock();
Expand Down Expand Up @@ -4086,6 +4103,7 @@ static const struct pmu perf_ops_task_clock = {
};

#ifdef CONFIG_EVENT_PROFILE

void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size)
{
Expand All @@ -4109,8 +4127,15 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
}
EXPORT_SYMBOL_GPL(perf_tp_event);

extern int ftrace_profile_enable(int);
extern void ftrace_profile_disable(int);
static int perf_tp_event_match(struct perf_event *event,
struct perf_sample_data *data)
{
void *record = data->raw->data;

if (likely(!event->filter) || filter_match_preds(event->filter, record))
return 1;
return 0;
}

static void tp_perf_event_destroy(struct perf_event *event)
{
Expand All @@ -4135,12 +4160,53 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)

return &perf_ops_generic;
}

static int perf_event_set_filter(struct perf_event *event, void __user *arg)
{
char *filter_str;
int ret;

if (event->attr.type != PERF_TYPE_TRACEPOINT)
return -EINVAL;

filter_str = strndup_user(arg, PAGE_SIZE);
if (IS_ERR(filter_str))
return PTR_ERR(filter_str);

ret = ftrace_profile_set_filter(event, event->attr.config, filter_str);

kfree(filter_str);
return ret;
}

static void perf_event_free_filter(struct perf_event *event)
{
ftrace_profile_free_filter(event);
}

#else

static int perf_tp_event_match(struct perf_event *event,
struct perf_sample_data *data)
{
return 1;
}

static const struct pmu *tp_perf_event_init(struct perf_event *event)
{
return NULL;
}
#endif

static int perf_event_set_filter(struct perf_event *event, void __user *arg)
{
return -ENOENT;
}

static void perf_event_free_filter(struct perf_event *event)
{
}

#endif /* CONFIG_EVENT_PROFILE */

atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];

Expand Down Expand Up @@ -4394,7 +4460,7 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
goto out;
}

int perf_event_set_output(struct perf_event *event, int output_fd)
static int perf_event_set_output(struct perf_event *event, int output_fd)
{
struct perf_event *output_event = NULL;
struct file *output_file = NULL;
Expand Down
3 changes: 2 additions & 1 deletion trunk/kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
struct ring_buffer *buffer,
struct ring_buffer_event *event)
{
if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) {
if (unlikely(call->filter_active) &&
!filter_match_preds(call->filter, rec)) {
ring_buffer_discard_commit(buffer, event);
return 1;
}
Expand Down
Loading

0 comments on commit 95f0a91

Please sign in to comment.