aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-08-04 18:32:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-08-04 18:32:40 -0400
commita40694a38a745af0dd7d8b796597ada1dd6caeb7 (patch)
treeb9f7014a6309f6b82e947d926384c0e2101b28cd /kernel
parentea5634246beaedd91b93d7e7fce7d825232d1b78 (diff)
parentf26542600e605482a1231c44ddb2966d69bd09b0 (diff)
Merge branch 'perfcounters-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perfcounters-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: perf_counter: Set the CONFIG_PERF_COUNTERS default to y if CONFIG_PROFILING=y perf: Fix read buffer overflow perf top: Add mwait_idle_with_hints to skip_symbols[] perf tools: Fix faulty check perf report: Update for the new FORK/EXIT events perf_counter: Full task tracing perf_counter: Collapse inherit on read() tracing, perf_counter: Add help text to CONFIG_EVENT_PROFILE perf_counter tools: Fix link errors with older toolchains
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fork.c4
-rw-r--r--kernel/perf_counter.c101
2 files changed, 72 insertions, 33 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index 29b532e718f7..466531eb92cc 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1269,6 +1269,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1269 write_unlock_irq(&tasklist_lock); 1269 write_unlock_irq(&tasklist_lock);
1270 proc_fork_connector(p); 1270 proc_fork_connector(p);
1271 cgroup_post_fork(p); 1271 cgroup_post_fork(p);
1272 perf_counter_fork(p);
1272 return p; 1273 return p;
1273 1274
1274bad_fork_free_pid: 1275bad_fork_free_pid:
@@ -1410,9 +1411,6 @@ long do_fork(unsigned long clone_flags,
1410 init_completion(&vfork); 1411 init_completion(&vfork);
1411 } 1412 }
1412 1413
1413 if (!(clone_flags & CLONE_THREAD))
1414 perf_counter_fork(p);
1415
1416 audit_finish_fork(p); 1414 audit_finish_fork(p);
1417 tracehook_report_clone(regs, clone_flags, nr, p); 1415 tracehook_report_clone(regs, clone_flags, nr, p);
1418 1416
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index 950931041954..199ed4771315 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -42,6 +42,7 @@ static int perf_overcommit __read_mostly = 1;
42static atomic_t nr_counters __read_mostly; 42static atomic_t nr_counters __read_mostly;
43static atomic_t nr_mmap_counters __read_mostly; 43static atomic_t nr_mmap_counters __read_mostly;
44static atomic_t nr_comm_counters __read_mostly; 44static atomic_t nr_comm_counters __read_mostly;
45static atomic_t nr_task_counters __read_mostly;
45 46
46/* 47/*
47 * perf counter paranoia level: 48 * perf counter paranoia level:
@@ -1654,6 +1655,8 @@ static void free_counter(struct perf_counter *counter)
1654 atomic_dec(&nr_mmap_counters); 1655 atomic_dec(&nr_mmap_counters);
1655 if (counter->attr.comm) 1656 if (counter->attr.comm)
1656 atomic_dec(&nr_comm_counters); 1657 atomic_dec(&nr_comm_counters);
1658 if (counter->attr.task)
1659 atomic_dec(&nr_task_counters);
1657 } 1660 }
1658 1661
1659 if (counter->destroy) 1662 if (counter->destroy)
@@ -1688,6 +1691,18 @@ static int perf_release(struct inode *inode, struct file *file)
1688 return 0; 1691 return 0;
1689} 1692}
1690 1693
1694static u64 perf_counter_read_tree(struct perf_counter *counter)
1695{
1696 struct perf_counter *child;
1697 u64 total = 0;
1698
1699 total += perf_counter_read(counter);
1700 list_for_each_entry(child, &counter->child_list, child_list)
1701 total += perf_counter_read(child);
1702
1703 return total;
1704}
1705
1691/* 1706/*
1692 * Read the performance counter - simple non blocking version for now 1707 * Read the performance counter - simple non blocking version for now
1693 */ 1708 */
@@ -1707,7 +1722,7 @@ perf_read_hw(struct perf_counter *counter, char __user *buf, size_t count)
1707 1722
1708 WARN_ON_ONCE(counter->ctx->parent_ctx); 1723 WARN_ON_ONCE(counter->ctx->parent_ctx);
1709 mutex_lock(&counter->child_mutex); 1724 mutex_lock(&counter->child_mutex);
1710 values[0] = perf_counter_read(counter); 1725 values[0] = perf_counter_read_tree(counter);
1711 n = 1; 1726 n = 1;
1712 if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 1727 if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
1713 values[n++] = counter->total_time_enabled + 1728 values[n++] = counter->total_time_enabled +
@@ -2819,10 +2834,12 @@ perf_counter_read_event(struct perf_counter *counter,
2819} 2834}
2820 2835
2821/* 2836/*
2822 * fork tracking 2837 * task tracking -- fork/exit
2838 *
2839 * enabled by: attr.comm | attr.mmap | attr.task
2823 */ 2840 */
2824 2841
2825struct perf_fork_event { 2842struct perf_task_event {
2826 struct task_struct *task; 2843 struct task_struct *task;
2827 2844
2828 struct { 2845 struct {
@@ -2830,37 +2847,42 @@ struct perf_fork_event {
2830 2847
2831 u32 pid; 2848 u32 pid;
2832 u32 ppid; 2849 u32 ppid;
2850 u32 tid;
2851 u32 ptid;
2833 } event; 2852 } event;
2834}; 2853};
2835 2854
2836static void perf_counter_fork_output(struct perf_counter *counter, 2855static void perf_counter_task_output(struct perf_counter *counter,
2837 struct perf_fork_event *fork_event) 2856 struct perf_task_event *task_event)
2838{ 2857{
2839 struct perf_output_handle handle; 2858 struct perf_output_handle handle;
2840 int size = fork_event->event.header.size; 2859 int size = task_event->event.header.size;
2841 struct task_struct *task = fork_event->task; 2860 struct task_struct *task = task_event->task;
2842 int ret = perf_output_begin(&handle, counter, size, 0, 0); 2861 int ret = perf_output_begin(&handle, counter, size, 0, 0);
2843 2862
2844 if (ret) 2863 if (ret)
2845 return; 2864 return;
2846 2865
2847 fork_event->event.pid = perf_counter_pid(counter, task); 2866 task_event->event.pid = perf_counter_pid(counter, task);
2848 fork_event->event.ppid = perf_counter_pid(counter, task->real_parent); 2867 task_event->event.ppid = perf_counter_pid(counter, task->real_parent);
2849 2868
2850 perf_output_put(&handle, fork_event->event); 2869 task_event->event.tid = perf_counter_tid(counter, task);
2870 task_event->event.ptid = perf_counter_tid(counter, task->real_parent);
2871
2872 perf_output_put(&handle, task_event->event);
2851 perf_output_end(&handle); 2873 perf_output_end(&handle);
2852} 2874}
2853 2875
2854static int perf_counter_fork_match(struct perf_counter *counter) 2876static int perf_counter_task_match(struct perf_counter *counter)
2855{ 2877{
2856 if (counter->attr.comm || counter->attr.mmap) 2878 if (counter->attr.comm || counter->attr.mmap || counter->attr.task)
2857 return 1; 2879 return 1;
2858 2880
2859 return 0; 2881 return 0;
2860} 2882}
2861 2883
2862static void perf_counter_fork_ctx(struct perf_counter_context *ctx, 2884static void perf_counter_task_ctx(struct perf_counter_context *ctx,
2863 struct perf_fork_event *fork_event) 2885 struct perf_task_event *task_event)
2864{ 2886{
2865 struct perf_counter *counter; 2887 struct perf_counter *counter;
2866 2888
@@ -2869,19 +2891,19 @@ static void perf_counter_fork_ctx(struct perf_counter_context *ctx,
2869 2891
2870 rcu_read_lock(); 2892 rcu_read_lock();
2871 list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { 2893 list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) {
2872 if (perf_counter_fork_match(counter)) 2894 if (perf_counter_task_match(counter))
2873 perf_counter_fork_output(counter, fork_event); 2895 perf_counter_task_output(counter, task_event);
2874 } 2896 }
2875 rcu_read_unlock(); 2897 rcu_read_unlock();
2876} 2898}
2877 2899
2878static void perf_counter_fork_event(struct perf_fork_event *fork_event) 2900static void perf_counter_task_event(struct perf_task_event *task_event)
2879{ 2901{
2880 struct perf_cpu_context *cpuctx; 2902 struct perf_cpu_context *cpuctx;
2881 struct perf_counter_context *ctx; 2903 struct perf_counter_context *ctx;
2882 2904
2883 cpuctx = &get_cpu_var(perf_cpu_context); 2905 cpuctx = &get_cpu_var(perf_cpu_context);
2884 perf_counter_fork_ctx(&cpuctx->ctx, fork_event); 2906 perf_counter_task_ctx(&cpuctx->ctx, task_event);
2885 put_cpu_var(perf_cpu_context); 2907 put_cpu_var(perf_cpu_context);
2886 2908
2887 rcu_read_lock(); 2909 rcu_read_lock();
@@ -2891,32 +2913,40 @@ static void perf_counter_fork_event(struct perf_fork_event *fork_event)
2891 */ 2913 */
2892 ctx = rcu_dereference(current->perf_counter_ctxp); 2914 ctx = rcu_dereference(current->perf_counter_ctxp);
2893 if (ctx) 2915 if (ctx)
2894 perf_counter_fork_ctx(ctx, fork_event); 2916 perf_counter_task_ctx(ctx, task_event);
2895 rcu_read_unlock(); 2917 rcu_read_unlock();
2896} 2918}
2897 2919
2898void perf_counter_fork(struct task_struct *task) 2920static void perf_counter_task(struct task_struct *task, int new)
2899{ 2921{
2900 struct perf_fork_event fork_event; 2922 struct perf_task_event task_event;
2901 2923
2902 if (!atomic_read(&nr_comm_counters) && 2924 if (!atomic_read(&nr_comm_counters) &&
2903 !atomic_read(&nr_mmap_counters)) 2925 !atomic_read(&nr_mmap_counters) &&
2926 !atomic_read(&nr_task_counters))
2904 return; 2927 return;
2905 2928
2906 fork_event = (struct perf_fork_event){ 2929 task_event = (struct perf_task_event){
2907 .task = task, 2930 .task = task,
2908 .event = { 2931 .event = {
2909 .header = { 2932 .header = {
2910 .type = PERF_EVENT_FORK, 2933 .type = new ? PERF_EVENT_FORK : PERF_EVENT_EXIT,
2911 .misc = 0, 2934 .misc = 0,
2912 .size = sizeof(fork_event.event), 2935 .size = sizeof(task_event.event),
2913 }, 2936 },
2914 /* .pid */ 2937 /* .pid */
2915 /* .ppid */ 2938 /* .ppid */
2939 /* .tid */
2940 /* .ptid */
2916 }, 2941 },
2917 }; 2942 };
2918 2943
2919 perf_counter_fork_event(&fork_event); 2944 perf_counter_task_event(&task_event);
2945}
2946
2947void perf_counter_fork(struct task_struct *task)
2948{
2949 perf_counter_task(task, 1);
2920} 2950}
2921 2951
2922/* 2952/*
@@ -3875,6 +3905,8 @@ done:
3875 atomic_inc(&nr_mmap_counters); 3905 atomic_inc(&nr_mmap_counters);
3876 if (counter->attr.comm) 3906 if (counter->attr.comm)
3877 atomic_inc(&nr_comm_counters); 3907 atomic_inc(&nr_comm_counters);
3908 if (counter->attr.task)
3909 atomic_inc(&nr_task_counters);
3878 } 3910 }
3879 3911
3880 return counter; 3912 return counter;
@@ -4236,8 +4268,10 @@ void perf_counter_exit_task(struct task_struct *child)
4236 struct perf_counter_context *child_ctx; 4268 struct perf_counter_context *child_ctx;
4237 unsigned long flags; 4269 unsigned long flags;
4238 4270
4239 if (likely(!child->perf_counter_ctxp)) 4271 if (likely(!child->perf_counter_ctxp)) {
4272 perf_counter_task(child, 0);
4240 return; 4273 return;
4274 }
4241 4275
4242 local_irq_save(flags); 4276 local_irq_save(flags);
4243 /* 4277 /*
@@ -4255,15 +4289,22 @@ void perf_counter_exit_task(struct task_struct *child)
4255 * incremented the context's refcount before we do put_ctx below. 4289 * incremented the context's refcount before we do put_ctx below.
4256 */ 4290 */
4257 spin_lock(&child_ctx->lock); 4291 spin_lock(&child_ctx->lock);
4258 child->perf_counter_ctxp = NULL;
4259 /* 4292 /*
4260 * If this context is a clone; unclone it so it can't get 4293 * If this context is a clone; unclone it so it can't get
4261 * swapped to another process while we're removing all 4294 * swapped to another process while we're removing all
4262 * the counters from it. 4295 * the counters from it.
4263 */ 4296 */
4264 unclone_ctx(child_ctx); 4297 unclone_ctx(child_ctx);
4265 spin_unlock(&child_ctx->lock); 4298 spin_unlock_irqrestore(&child_ctx->lock, flags);
4266 local_irq_restore(flags); 4299
4300 /*
4301 * Report the task dead after unscheduling the counters so that we
4302 * won't get any samples after PERF_EVENT_EXIT. We can however still
4303 * get a few PERF_EVENT_READ events.
4304 */
4305 perf_counter_task(child, 0);
4306
4307 child->perf_counter_ctxp = NULL;
4267 4308
4268 /* 4309 /*
4269 * We can recurse on the same lock type through: 4310 * We can recurse on the same lock type through: