diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-06-04 10:53:44 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-04 11:51:38 -0400 |
commit | 60313ebed739b331e8e61079da27a11ee3b73a30 (patch) | |
tree | 8476fbd05be709595876360765776dd9ca20608d /kernel/perf_counter.c | |
parent | 20c84e959ec11b1803d2b2832eef703d5fbe7f7b (diff) |
perf_counter: Add fork event
Create a fork event so that we can easily clone the comm and
dso maps without having to generate all those events.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r-- | kernel/perf_counter.c | 131 |
1 files changed, 114 insertions, 17 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 0bb03f15a5b6..78c58623a0dd 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -40,9 +40,9 @@ static int perf_reserved_percpu __read_mostly; | |||
40 | static int perf_overcommit __read_mostly = 1; | 40 | static int perf_overcommit __read_mostly = 1; |
41 | 41 | ||
42 | static atomic_t nr_counters __read_mostly; | 42 | static atomic_t nr_counters __read_mostly; |
43 | static atomic_t nr_mmap_tracking __read_mostly; | 43 | static atomic_t nr_mmap_counters __read_mostly; |
44 | static atomic_t nr_munmap_tracking __read_mostly; | 44 | static atomic_t nr_munmap_counters __read_mostly; |
45 | static atomic_t nr_comm_tracking __read_mostly; | 45 | static atomic_t nr_comm_counters __read_mostly; |
46 | 46 | ||
47 | int sysctl_perf_counter_priv __read_mostly; /* do we need to be privileged */ | 47 | int sysctl_perf_counter_priv __read_mostly; /* do we need to be privileged */ |
48 | int sysctl_perf_counter_mlock __read_mostly = 512; /* 'free' kb per user */ | 48 | int sysctl_perf_counter_mlock __read_mostly = 512; /* 'free' kb per user */ |
@@ -1447,11 +1447,11 @@ static void free_counter(struct perf_counter *counter) | |||
1447 | 1447 | ||
1448 | atomic_dec(&nr_counters); | 1448 | atomic_dec(&nr_counters); |
1449 | if (counter->attr.mmap) | 1449 | if (counter->attr.mmap) |
1450 | atomic_dec(&nr_mmap_tracking); | 1450 | atomic_dec(&nr_mmap_counters); |
1451 | if (counter->attr.munmap) | 1451 | if (counter->attr.munmap) |
1452 | atomic_dec(&nr_munmap_tracking); | 1452 | atomic_dec(&nr_munmap_counters); |
1453 | if (counter->attr.comm) | 1453 | if (counter->attr.comm) |
1454 | atomic_dec(&nr_comm_tracking); | 1454 | atomic_dec(&nr_comm_counters); |
1455 | 1455 | ||
1456 | if (counter->destroy) | 1456 | if (counter->destroy) |
1457 | counter->destroy(counter); | 1457 | counter->destroy(counter); |
@@ -2476,6 +2476,105 @@ static void perf_counter_output(struct perf_counter *counter, | |||
2476 | } | 2476 | } |
2477 | 2477 | ||
2478 | /* | 2478 | /* |
2479 | * fork tracking | ||
2480 | */ | ||
2481 | |||
2482 | struct perf_fork_event { | ||
2483 | struct task_struct *task; | ||
2484 | |||
2485 | struct { | ||
2486 | struct perf_event_header header; | ||
2487 | |||
2488 | u32 pid; | ||
2489 | u32 ppid; | ||
2490 | } event; | ||
2491 | }; | ||
2492 | |||
2493 | static void perf_counter_fork_output(struct perf_counter *counter, | ||
2494 | struct perf_fork_event *fork_event) | ||
2495 | { | ||
2496 | struct perf_output_handle handle; | ||
2497 | int size = fork_event->event.header.size; | ||
2498 | struct task_struct *task = fork_event->task; | ||
2499 | int ret = perf_output_begin(&handle, counter, size, 0, 0); | ||
2500 | |||
2501 | if (ret) | ||
2502 | return; | ||
2503 | |||
2504 | fork_event->event.pid = perf_counter_pid(counter, task); | ||
2505 | fork_event->event.ppid = perf_counter_pid(counter, task->real_parent); | ||
2506 | |||
2507 | perf_output_put(&handle, fork_event->event); | ||
2508 | perf_output_end(&handle); | ||
2509 | } | ||
2510 | |||
2511 | static int perf_counter_fork_match(struct perf_counter *counter) | ||
2512 | { | ||
2513 | if (counter->attr.comm || counter->attr.mmap || counter->attr.munmap) | ||
2514 | return 1; | ||
2515 | |||
2516 | return 0; | ||
2517 | } | ||
2518 | |||
2519 | static void perf_counter_fork_ctx(struct perf_counter_context *ctx, | ||
2520 | struct perf_fork_event *fork_event) | ||
2521 | { | ||
2522 | struct perf_counter *counter; | ||
2523 | |||
2524 | if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list)) | ||
2525 | return; | ||
2526 | |||
2527 | rcu_read_lock(); | ||
2528 | list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { | ||
2529 | if (perf_counter_fork_match(counter)) | ||
2530 | perf_counter_fork_output(counter, fork_event); | ||
2531 | } | ||
2532 | rcu_read_unlock(); | ||
2533 | } | ||
2534 | |||
2535 | static void perf_counter_fork_event(struct perf_fork_event *fork_event) | ||
2536 | { | ||
2537 | struct perf_cpu_context *cpuctx; | ||
2538 | struct perf_counter_context *ctx; | ||
2539 | |||
2540 | cpuctx = &get_cpu_var(perf_cpu_context); | ||
2541 | perf_counter_fork_ctx(&cpuctx->ctx, fork_event); | ||
2542 | put_cpu_var(perf_cpu_context); | ||
2543 | |||
2544 | rcu_read_lock(); | ||
2545 | /* | ||
2546 | * doesn't really matter which of the child contexts the | ||
2547 | * events ends up in. | ||
2548 | */ | ||
2549 | ctx = rcu_dereference(current->perf_counter_ctxp); | ||
2550 | if (ctx) | ||
2551 | perf_counter_fork_ctx(ctx, fork_event); | ||
2552 | rcu_read_unlock(); | ||
2553 | } | ||
2554 | |||
2555 | void perf_counter_fork(struct task_struct *task) | ||
2556 | { | ||
2557 | struct perf_fork_event fork_event; | ||
2558 | |||
2559 | if (!atomic_read(&nr_comm_counters) && | ||
2560 | !atomic_read(&nr_mmap_counters) && | ||
2561 | !atomic_read(&nr_munmap_counters)) | ||
2562 | return; | ||
2563 | |||
2564 | fork_event = (struct perf_fork_event){ | ||
2565 | .task = task, | ||
2566 | .event = { | ||
2567 | .header = { | ||
2568 | .type = PERF_EVENT_FORK, | ||
2569 | .size = sizeof(fork_event.event), | ||
2570 | }, | ||
2571 | }, | ||
2572 | }; | ||
2573 | |||
2574 | perf_counter_fork_event(&fork_event); | ||
2575 | } | ||
2576 | |||
2577 | /* | ||
2479 | * comm tracking | 2578 | * comm tracking |
2480 | */ | 2579 | */ |
2481 | 2580 | ||
@@ -2511,11 +2610,9 @@ static void perf_counter_comm_output(struct perf_counter *counter, | |||
2511 | perf_output_end(&handle); | 2610 | perf_output_end(&handle); |
2512 | } | 2611 | } |
2513 | 2612 | ||
2514 | static int perf_counter_comm_match(struct perf_counter *counter, | 2613 | static int perf_counter_comm_match(struct perf_counter *counter) |
2515 | struct perf_comm_event *comm_event) | ||
2516 | { | 2614 | { |
2517 | if (counter->attr.comm && | 2615 | if (counter->attr.comm) |
2518 | comm_event->event.header.type == PERF_EVENT_COMM) | ||
2519 | return 1; | 2616 | return 1; |
2520 | 2617 | ||
2521 | return 0; | 2618 | return 0; |
@@ -2531,7 +2628,7 @@ static void perf_counter_comm_ctx(struct perf_counter_context *ctx, | |||
2531 | 2628 | ||
2532 | rcu_read_lock(); | 2629 | rcu_read_lock(); |
2533 | list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { | 2630 | list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { |
2534 | if (perf_counter_comm_match(counter, comm_event)) | 2631 | if (perf_counter_comm_match(counter)) |
2535 | perf_counter_comm_output(counter, comm_event); | 2632 | perf_counter_comm_output(counter, comm_event); |
2536 | } | 2633 | } |
2537 | rcu_read_unlock(); | 2634 | rcu_read_unlock(); |
@@ -2570,7 +2667,7 @@ void perf_counter_comm(struct task_struct *task) | |||
2570 | { | 2667 | { |
2571 | struct perf_comm_event comm_event; | 2668 | struct perf_comm_event comm_event; |
2572 | 2669 | ||
2573 | if (!atomic_read(&nr_comm_tracking)) | 2670 | if (!atomic_read(&nr_comm_counters)) |
2574 | return; | 2671 | return; |
2575 | 2672 | ||
2576 | comm_event = (struct perf_comm_event){ | 2673 | comm_event = (struct perf_comm_event){ |
@@ -2708,7 +2805,7 @@ void perf_counter_mmap(unsigned long addr, unsigned long len, | |||
2708 | { | 2805 | { |
2709 | struct perf_mmap_event mmap_event; | 2806 | struct perf_mmap_event mmap_event; |
2710 | 2807 | ||
2711 | if (!atomic_read(&nr_mmap_tracking)) | 2808 | if (!atomic_read(&nr_mmap_counters)) |
2712 | return; | 2809 | return; |
2713 | 2810 | ||
2714 | mmap_event = (struct perf_mmap_event){ | 2811 | mmap_event = (struct perf_mmap_event){ |
@@ -2729,7 +2826,7 @@ void perf_counter_munmap(unsigned long addr, unsigned long len, | |||
2729 | { | 2826 | { |
2730 | struct perf_mmap_event mmap_event; | 2827 | struct perf_mmap_event mmap_event; |
2731 | 2828 | ||
2732 | if (!atomic_read(&nr_munmap_tracking)) | 2829 | if (!atomic_read(&nr_munmap_counters)) |
2733 | return; | 2830 | return; |
2734 | 2831 | ||
2735 | mmap_event = (struct perf_mmap_event){ | 2832 | mmap_event = (struct perf_mmap_event){ |
@@ -3427,11 +3524,11 @@ done: | |||
3427 | 3524 | ||
3428 | atomic_inc(&nr_counters); | 3525 | atomic_inc(&nr_counters); |
3429 | if (counter->attr.mmap) | 3526 | if (counter->attr.mmap) |
3430 | atomic_inc(&nr_mmap_tracking); | 3527 | atomic_inc(&nr_mmap_counters); |
3431 | if (counter->attr.munmap) | 3528 | if (counter->attr.munmap) |
3432 | atomic_inc(&nr_munmap_tracking); | 3529 | atomic_inc(&nr_munmap_counters); |
3433 | if (counter->attr.comm) | 3530 | if (counter->attr.comm) |
3434 | atomic_inc(&nr_comm_tracking); | 3531 | atomic_inc(&nr_comm_counters); |
3435 | 3532 | ||
3436 | return counter; | 3533 | return counter; |
3437 | } | 3534 | } |