aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/fork.c1
-rw-r--r--kernel/perf_counter.c943
-rw-r--r--kernel/sched.c24
-rw-r--r--kernel/sys_ni.c3
5 files changed, 972 insertions, 0 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index 19fad003b19d..1f184a1dc406 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
89obj-$(CONFIG_FUNCTION_TRACER) += trace/ 89obj-$(CONFIG_FUNCTION_TRACER) += trace/
90obj-$(CONFIG_TRACING) += trace/ 90obj-$(CONFIG_TRACING) += trace/
91obj-$(CONFIG_SMP) += sched_cpupri.o 91obj-$(CONFIG_SMP) += sched_cpupri.o
92obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o
92 93
93ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) 94ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
94# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is 95# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/fork.c b/kernel/fork.c
index 2a372a0e206f..441fadff1fa4 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -975,6 +975,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
975 goto fork_out; 975 goto fork_out;
976 976
977 rt_mutex_init_task(p); 977 rt_mutex_init_task(p);
978 perf_counter_init_task(p);
978 979
979#ifdef CONFIG_PROVE_LOCKING 980#ifdef CONFIG_PROVE_LOCKING
980 DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); 981 DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
new file mode 100644
index 000000000000..20508f053658
--- /dev/null
+++ b/kernel/perf_counter.c
@@ -0,0 +1,943 @@
1/*
2 * Performance counter core code
3 *
4 * Copyright(C) 2008 Thomas Gleixner <tglx@linutronix.de>
5 * Copyright(C) 2008 Red Hat, Inc., Ingo Molnar
6 *
7 * For licencing details see kernel-base/COPYING
8 */
9
10#include <linux/fs.h>
11#include <linux/cpu.h>
12#include <linux/smp.h>
13#include <linux/poll.h>
14#include <linux/sysfs.h>
15#include <linux/ptrace.h>
16#include <linux/percpu.h>
17#include <linux/uaccess.h>
18#include <linux/syscalls.h>
19#include <linux/anon_inodes.h>
20#include <linux/perf_counter.h>
21
22/*
23 * Each CPU has a list of per CPU counters:
24 */
25DEFINE_PER_CPU(struct perf_cpu_context, perf_cpu_context);
26
27int perf_max_counters __read_mostly;
28static int perf_reserved_percpu __read_mostly;
29static int perf_overcommit __read_mostly = 1;
30
31/*
32 * Mutex for (sysadmin-configurable) counter reservations:
33 */
34static DEFINE_MUTEX(perf_resource_mutex);
35
36/*
37 * Architecture provided APIs - weak aliases:
38 */
39
40int __weak hw_perf_counter_init(struct perf_counter *counter, u32 hw_event_type)
41{
42 return -EINVAL;
43}
44
45void __weak hw_perf_counter_enable(struct perf_counter *counter) { }
46void __weak hw_perf_counter_disable(struct perf_counter *counter) { }
47void __weak hw_perf_counter_read(struct perf_counter *counter) { }
48void __weak hw_perf_disable_all(void) { }
49void __weak hw_perf_enable_all(void) { }
50void __weak hw_perf_counter_setup(void) { }
51
52#if BITS_PER_LONG == 64
53
54/*
55 * Read the cached counter in counter safe against cross CPU / NMI
56 * modifications. 64 bit version - no complications.
57 */
58static inline u64 perf_read_counter_safe(struct perf_counter *counter)
59{
60 return (u64) atomic64_read(&counter->count);
61}
62
63#else
64
65/*
66 * Read the cached counter in counter safe against cross CPU / NMI
67 * modifications. 32 bit version.
68 */
69static u64 perf_read_counter_safe(struct perf_counter *counter)
70{
71 u32 cntl, cnth;
72
73 local_irq_disable();
74 do {
75 cnth = atomic_read(&counter->count32[1]);
76 cntl = atomic_read(&counter->count32[0]);
77 } while (cnth != atomic_read(&counter->count32[1]));
78
79 local_irq_enable();
80
81 return cntl | ((u64) cnth) << 32;
82}
83
84#endif
85
86/*
87 * Cross CPU call to remove a performance counter
88 *
89 * We disable the counter on the hardware level first. After that we
90 * remove it from the context list.
91 */
92static void __perf_remove_from_context(void *info)
93{
94 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
95 struct perf_counter *counter = info;
96 struct perf_counter_context *ctx = counter->ctx;
97
98 /*
99 * If this is a task context, we need to check whether it is
100 * the current task context of this cpu. If not it has been
101 * scheduled out before the smp call arrived.
102 */
103 if (ctx->task && cpuctx->task_ctx != ctx)
104 return;
105
106 spin_lock(&ctx->lock);
107
108 if (counter->active) {
109 hw_perf_counter_disable(counter);
110 counter->active = 0;
111 ctx->nr_active--;
112 cpuctx->active_oncpu--;
113 counter->task = NULL;
114 }
115 ctx->nr_counters--;
116
117 /*
118 * Protect the list operation against NMI by disabling the
119 * counters on a global level. NOP for non NMI based counters.
120 */
121 hw_perf_disable_all();
122 list_del_init(&counter->list);
123 hw_perf_enable_all();
124
125 if (!ctx->task) {
126 /*
127 * Allow more per task counters with respect to the
128 * reservation:
129 */
130 cpuctx->max_pertask =
131 min(perf_max_counters - ctx->nr_counters,
132 perf_max_counters - perf_reserved_percpu);
133 }
134
135 spin_unlock(&ctx->lock);
136}
137
138
139/*
140 * Remove the counter from a task's (or a CPU's) list of counters.
141 *
142 * Must be called with counter->mutex held.
143 *
144 * CPU counters are removed with a smp call. For task counters we only
145 * call when the task is on a CPU.
146 */
147static void perf_remove_from_context(struct perf_counter *counter)
148{
149 struct perf_counter_context *ctx = counter->ctx;
150 struct task_struct *task = ctx->task;
151
152 if (!task) {
153 /*
154 * Per cpu counters are removed via an smp call and
155 * the removal is always sucessful.
156 */
157 smp_call_function_single(counter->cpu,
158 __perf_remove_from_context,
159 counter, 1);
160 return;
161 }
162
163retry:
164 task_oncpu_function_call(task, __perf_remove_from_context,
165 counter);
166
167 spin_lock_irq(&ctx->lock);
168 /*
169 * If the context is active we need to retry the smp call.
170 */
171 if (ctx->nr_active && !list_empty(&counter->list)) {
172 spin_unlock_irq(&ctx->lock);
173 goto retry;
174 }
175
176 /*
177 * The lock prevents that this context is scheduled in so we
</