diff options
| author | Li Zefan <lizf@cn.fujitsu.com> | 2009-10-14 23:21:42 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-10-15 05:35:23 -0400 |
| commit | 6fb2915df7f0747d9044da9dbff5b46dc2e20830 (patch) | |
| tree | b4c5d7d913362ae6161c2859a7a385263330e965 /kernel/trace | |
| parent | b0f1a59a98d7ac2102e7e4f22904c26d564a5628 (diff) | |
tracing/profile: Add filter support
- Add an ioctl to allocate a filter for a perf event.
- Free the filter when the associated perf event is to be freed.
- Do the filtering in perf_swevent_match().
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <4AD69546.8050401@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/trace.h | 3 | ||||
| -rw-r--r-- | kernel/trace/trace_events_filter.c | 133 |
2 files changed, 109 insertions, 27 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index ffe53ddbe67a..4959ada9e0bb 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -743,7 +743,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec, | |||
| 743 | struct ring_buffer *buffer, | 743 | struct ring_buffer *buffer, |
| 744 | struct ring_buffer_event *event) | 744 | struct ring_buffer_event *event) |
| 745 | { | 745 | { |
| 746 | if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) { | 746 | if (unlikely(call->filter_active) && |
| 747 | !filter_match_preds(call->filter, rec)) { | ||
| 747 | ring_buffer_discard_commit(buffer, event); | 748 | ring_buffer_discard_commit(buffer, event); |
| 748 | return 1; | 749 | return 1; |
| 749 | } | 750 | } |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 273845fce393..e27bb6acc2dd 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
| 23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
| 24 | #include <linux/perf_event.h> | ||
| 24 | 25 | ||
| 25 | #include "trace.h" | 26 | #include "trace.h" |
| 26 | #include "trace_output.h" | 27 | #include "trace_output.h" |
| @@ -363,9 +364,8 @@ static void filter_build_regex(struct filter_pred *pred) | |||
| 363 | } | 364 | } |
| 364 | 365 | ||
| 365 | /* return 1 if event matches, 0 otherwise (discard) */ | 366 | /* return 1 if event matches, 0 otherwise (discard) */ |
| 366 | int filter_match_preds(struct ftrace_event_call *call, void *rec) | 367 | int filter_match_preds(struct event_filter *filter, void *rec) |
| 367 | { | 368 | { |
| 368 | struct event_filter *filter = call->filter; | ||
| 369 | int match, top = 0, val1 = 0, val2 = 0; | 369 | int match, top = 0, val1 = 0, val2 = 0; |
| 370 | int stack[MAX_FILTER_PRED]; | 370 | int stack[MAX_FILTER_PRED]; |
| 371 | struct filter_pred *pred; | 371 | struct filter_pred *pred; |
| @@ -538,9 +538,8 @@ static void filter_disable_preds(struct ftrace_event_call *call) | |||
| 538 | filter->preds[i]->fn = filter_pred_none; | 538 | filter->preds[i]->fn = filter_pred_none; |
| 539 | } | 539 | } |
| 540 | 540 | ||
| 541 | void destroy_preds(struct ftrace_event_call *call) | 541 | static void __free_preds(struct event_filter *filter) |
| 542 | { | 542 | { |
| 543 | struct event_filter *filter = call->filter; | ||
| 544 | int i; | 543 | int i; |
| 545 | 544 | ||
| 546 | if (!filter) | 545 | if (!filter) |
| @@ -553,21 +552,24 @@ void destroy_preds(struct ftrace_event_call *call) | |||
| 553 | kfree(filter->preds); | 552 | kfree(filter->preds); |
| 554 | kfree(filter->filter_string); | 553 | kfree(filter->filter_string); |
| 555 | kfree(filter); | 554 | kfree(filter); |
| 555 | } | ||
| 556 | |||
| 557 | void destroy_preds(struct ftrace_event_call *call) | ||
| 558 | { | ||
| 559 | __free_preds(call->filter); | ||
| 556 | call->filter = NULL; | 560 | call->filter = NULL; |
| 561 | call->filter_active = 0; | ||
| 557 | } | 562 | } |
| 558 | 563 | ||
| 559 | static int init_preds(struct ftrace_event_call *call) | 564 | static struct event_filter *__alloc_preds(void) |
| 560 | { | 565 | { |
| 561 | struct event_filter *filter; | 566 | struct event_filter *filter; |
| 562 | struct filter_pred *pred; | 567 | struct filter_pred *pred; |
| 563 | int i; | 568 | int i; |
| 564 | 569 | ||
| 565 | if (call->filter) | 570 | filter = kzalloc(sizeof(*filter), GFP_KERNEL); |
| 566 | return 0; | 571 | if (!filter) |
| 567 | 572 | return ERR_PTR(-ENOMEM); | |
| 568 | filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL); | ||
| 569 | if (!call->filter) | ||
| 570 | return -ENOMEM; | ||
| 571 | 573 | ||
| 572 | filter->n_preds = 0; | 574 | filter->n_preds = 0; |
| 573 | 575 | ||
| @@ -583,12 +585,24 @@ static int init_preds(struct ftrace_event_call *call) | |||
| 583 | filter->preds[i] = pred; | 585 | filter->preds[i] = pred; |
| 584 | } | 586 | } |
| 585 | 587 | ||
| 586 | return 0; | 588 | return filter; |
| 587 | 589 | ||
| 588 | oom: | 590 | oom: |
| 589 | destroy_preds(call); | 591 | __free_preds(filter); |
| 592 | return ERR_PTR(-ENOMEM); | ||
| 593 | } | ||
| 594 | |||
| 595 | static int init_preds(struct ftrace_event_call *call) | ||
| 596 | { | ||
| 597 | if (call->filter) | ||
| 598 | return 0; | ||
| 599 | |||
| 600 | call->filter_active = 0; | ||
| 601 | call->filter = __alloc_preds(); | ||
| 602 | if (IS_ERR(call->filter)) | ||
| 603 | return PTR_ERR(call->filter); | ||
| 590 | 604 | ||
| 591 | return -ENOMEM; | 605 | return 0; |
| 592 | } | 606 | } |
| 593 | 607 | ||
| 594 | static int init_subsystem_preds(struct event_subsystem *system) | 608 | static int init_subsystem_preds(struct event_subsystem *system) |
| @@ -629,10 +643,10 @@ static void filter_free_subsystem_preds(struct event_subsystem *system) | |||
| 629 | 643 | ||
| 630 | static int filter_add_pred_fn(struct filter_parse_state *ps, | 644 | static int filter_add_pred_fn(struct filter_parse_state *ps, |
| 631 | struct ftrace_event_call *call, | 645 | struct ftrace_event_call *call, |
| 646 | struct event_filter *filter, | ||
| 632 | struct filter_pred *pred, | 647 | struct filter_pred *pred, |
| 633 | filter_pred_fn_t fn) | 648 | filter_pred_fn_t fn) |
| 634 | { | 649 | { |
| 635 | struct event_filter *filter = call->filter; | ||
| 636 | int idx, err; | 650 | int idx, err; |
| 637 | 651 | ||
| 638 | if (filter->n_preds == MAX_FILTER_PRED) { | 652 | if (filter->n_preds == MAX_FILTER_PRED) { |
| @@ -647,7 +661,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps, | |||
| 647 | return err; | 661 | return err; |
| 648 | 662 | ||
| 649 | filter->n_preds++; | 663 | filter->n_preds++; |
| 650 | call->filter_active = 1; | ||
| 651 | 664 | ||
| 652 | return 0; | 665 | return 0; |
| 653 | } | 666 | } |
| @@ -726,6 +739,7 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size, | |||
| 726 | 739 | ||
| 727 | static int filter_add_pred(struct filter_parse_state *ps, | 740 | static int filter_add_pred(struct filter_parse_state *ps, |
| 728 | struct ftrace_event_call *call, | 741 | struct ftrace_event_call *call, |
| 742 | struct event_filter *filter, | ||
| 729 | struct filter_pred *pred, | 743 | struct filter_pred *pred, |
| 730 | bool dry_run) | 744 | bool dry_run) |
| 731 | { | 745 | { |
| @@ -795,7 +809,7 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
| 795 | 809 | ||
| 796 | add_pred_fn: | 810 | add_pred_fn: |
| 797 | if (!dry_run) | 811 | if (!dry_run) |
| 798 | return filter_add_pred_fn(ps, call, pred, fn); | 812 | return filter_add_pred_fn(ps, call, filter, pred, fn); |
| 799 | return 0; | 813 | return 0; |
| 800 | } | 814 | } |
| 801 | 815 | ||
| @@ -1154,6 +1168,7 @@ static int check_preds(struct filter_parse_state *ps) | |||
| 1154 | } | 1168 | } |
| 1155 | 1169 | ||
| 1156 | static int replace_preds(struct ftrace_event_call *call, | 1170 | static int replace_preds(struct ftrace_event_call *call, |
| 1171 | struct event_filter *filter, | ||
| 1157 | struct filter_parse_state *ps, | 1172 | struct filter_parse_state *ps, |
| 1158 | char *filter_string, | 1173 | char *filter_string, |
| 1159 | bool dry_run) | 1174 | bool dry_run) |
| @@ -1200,7 +1215,7 @@ static int replace_preds(struct ftrace_event_call *call, | |||
| 1200 | add_pred: | 1215 | add_pred: |
| 1201 | if (!pred) | 1216 | if (!pred) |
| 1202 | return -ENOMEM; | 1217 | return -ENOMEM; |
| 1203 | err = filter_add_pred(ps, call, pred, dry_run); | 1218 | err = filter_add_pred(ps, call, filter, pred, dry_run); |
| 1204 | filter_free_pred(pred); | 1219 | filter_free_pred(pred); |
| 1205 | if (err) | 1220 | if (err) |
| 1206 | return err; | 1221 | return err; |
| @@ -1216,6 +1231,7 @@ static int replace_system_preds(struct event_subsystem *system, | |||
| 1216 | char *filter_string) | 1231 | char *filter_string) |
| 1217 | { | 1232 | { |
| 1218 | struct ftrace_event_call *call; | 1233 | struct ftrace_event_call *call; |
| 1234 | struct event_filter *filter; | ||
| 1219 | int err; | 1235 | int err; |
| 1220 | bool fail = true; | 1236 | bool fail = true; |
| 1221 | 1237 | ||
| @@ -1228,17 +1244,19 @@ static int replace_system_preds(struct event_subsystem *system, | |||
| 1228 | continue; | 1244 | continue; |
| 1229 | 1245 | ||
| 1230 | /* try to see if the filter can be applied */ | 1246 | /* try to see if the filter can be applied */ |
| 1231 | err = replace_preds(call, ps, filter_string, true); | 1247 | err = replace_preds(call, filter, ps, filter_string, true); |
| 1232 | if (err) | 1248 | if (err) |
| 1233 | continue; | 1249 | continue; |
| 1234 | 1250 | ||
| 1235 | /* really apply the filter */ | 1251 | /* really apply the filter */ |
| 1236 | filter_disable_preds(call); | 1252 | filter_disable_preds(call); |
| 1237 | err = replace_preds(call, ps, filter_string, false); | 1253 | err = replace_preds(call, filter, ps, filter_string, false); |
| 1238 | if (err) | 1254 | if (err) |
| 1239 | filter_disable_preds(call); | 1255 | filter_disable_preds(call); |
| 1240 | else | 1256 | else { |
| 1241 | replace_filter_string(call->filter, filter_string); | 1257 | call->filter_active = 1; |
| 1258 | replace_filter_string(filter, filter_string); | ||
| 1259 | } | ||
| 1242 | fail = false; | 1260 | fail = false; |
| 1243 | } | 1261 | } |
| 1244 | 1262 | ||
| @@ -1252,7 +1270,6 @@ static int replace_system_preds(struct event_subsystem *system, | |||
| 1252 | int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | 1270 | int apply_event_filter(struct ftrace_event_call *call, char *filter_string) |
| 1253 | { | 1271 | { |
| 1254 | int err; | 1272 | int err; |
| 1255 | |||
| 1256 | struct filter_parse_state *ps; | 1273 | struct filter_parse_state *ps; |
| 1257 | 1274 | ||
| 1258 | mutex_lock(&event_mutex); | 1275 | mutex_lock(&event_mutex); |
| @@ -1283,10 +1300,11 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | |||
| 1283 | goto out; | 1300 | goto out; |
| 1284 | } | 1301 | } |
| 1285 | 1302 | ||
| 1286 | err = replace_preds(call, ps, filter_string, false); | 1303 | err = replace_preds(call, call->filter, ps, filter_string, false); |
| 1287 | if (err) | 1304 | if (err) |
| 1288 | append_filter_err(ps, call->filter); | 1305 | append_filter_err(ps, call->filter); |
| 1289 | 1306 | else | |
| 1307 | call->filter_active = 1; | ||
| 1290 | out: | 1308 | out: |
| 1291 | filter_opstack_clear(ps); | 1309 | filter_opstack_clear(ps); |
| 1292 | postfix_clear(ps); | 1310 | postfix_clear(ps); |
| @@ -1301,7 +1319,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
| 1301 | char *filter_string) | 1319 | char *filter_string) |
| 1302 | { | 1320 | { |
| 1303 | int err; | 1321 | int err; |
| 1304 | |||
| 1305 | struct filter_parse_state *ps; | 1322 | struct filter_parse_state *ps; |
| 1306 | 1323 | ||
| 1307 | mutex_lock(&event_mutex); | 1324 | mutex_lock(&event_mutex); |
| @@ -1345,3 +1362,67 @@ out_unlock: | |||
| 1345 | return err; | 1362 | return err; |
| 1346 | } | 1363 | } |
| 1347 | 1364 | ||
| 1365 | #ifdef CONFIG_EVENT_PROFILE | ||
| 1366 | |||
| 1367 | void ftrace_profile_free_filter(struct perf_event *event) | ||
| 1368 | { | ||
| 1369 | struct event_filter *filter = event->filter; | ||
| 1370 | |||
| 1371 | event->filter = NULL; | ||
| 1372 | __free_preds(filter); | ||
| 1373 | } | ||
| 1374 | |||
| 1375 | int ftrace_profile_set_filter(struct perf_event *event, int event_id, | ||
| 1376 | char *filter_str) | ||
| 1377 | { | ||
| 1378 | int err; | ||
| 1379 | struct event_filter *filter; | ||
| 1380 | struct filter_parse_state *ps; | ||
| 1381 | struct ftrace_event_call *call = NULL; | ||
| 1382 | |||
| 1383 | mutex_lock(&event_mutex); | ||
| 1384 | |||
| 1385 | list_for_each_entry(call, &ftrace_events, list) { | ||
| 1386 | if (call->id == event_id) | ||
| 1387 | break; | ||
| 1388 | } | ||
| 1389 | if (!call) | ||
| 1390 | return -EINVAL; | ||
| 1391 | |||
| 1392 | if (event->filter) | ||
| 1393 | return -EEXIST; | ||
| 1394 | |||
| 1395 | filter = __alloc_preds(); | ||
| 1396 | if (IS_ERR(filter)) | ||
| 1397 | return PTR_ERR(filter); | ||
| 1398 | |||
| 1399 | err = -ENOMEM; | ||
| 1400 | ps = kzalloc(sizeof(*ps), GFP_KERNEL); | ||
| 1401 | if (!ps) | ||
| 1402 | goto free_preds; | ||
| 1403 | |||
| 1404 | parse_init(ps, filter_ops, filter_str); | ||
| 1405 | err = filter_parse(ps); | ||
| 1406 | if (err) | ||
| 1407 | goto free_ps; | ||
| 1408 | |||
| 1409 | err = replace_preds(call, filter, ps, filter_str, false); | ||
| 1410 | if (!err) | ||
| 1411 | event->filter = filter; | ||
| 1412 | |||
| 1413 | free_ps: | ||
| 1414 | filter_opstack_clear(ps); | ||
| 1415 | postfix_clear(ps); | ||
| 1416 | kfree(ps); | ||
| 1417 | |||
| 1418 | free_preds: | ||
| 1419 | if (err) | ||
| 1420 | __free_preds(filter); | ||
| 1421 | |||
| 1422 | mutex_unlock(&event_mutex); | ||
| 1423 | |||
| 1424 | return err; | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | #endif /* CONFIG_EVENT_PROFILE */ | ||
| 1428 | |||
