aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/oprofile/oprof.c
diff options
context:
space:
mode:
authorJason Yeh <jason.yeh@amd.com>2009-07-08 07:49:38 -0400
committerRobert Richter <robert.richter@amd.com>2009-07-20 10:33:53 -0400
commit4d4036e0e7299c6cbb2d2421b4b30b7a409ce61a (patch)
treec9003cd927ed878412e89a59db0138b6b701b629 /drivers/oprofile/oprof.c
parent6e63ea4b0b14ff5fb8a3ca704fcda7d28b95f079 (diff)
oprofile: Implement performance counter multiplexing
The number of hardware counters is limited. The multiplexing feature enables OProfile to gather more events than counters are provided by the hardware. This is realized by switching between events at an user specified time interval. A new file (/dev/oprofile/time_slice) is added for the user to specify the timer interval in ms. If the number of events to profile is higher than the number of hardware counters available, the patch will schedule a work queue that switches the event counter and re-writes the different sets of values into it. The switching mechanism needs to be implemented for each architecture to support multiplexing. This patch only implements AMD CPU support, but multiplexing can be easily extended for other models and architectures. There are follow-on patches that rework parts of this patch. Signed-off-by: Jason Yeh <jason.yeh@amd.com> Signed-off-by: Robert Richter <robert.richter@amd.com>
Diffstat (limited to 'drivers/oprofile/oprof.c')
-rw-r--r--drivers/oprofile/oprof.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index 3cffce90f82a..7bc64af7cf99 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -12,6 +12,8 @@
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/oprofile.h> 13#include <linux/oprofile.h>
14#include <linux/moduleparam.h> 14#include <linux/moduleparam.h>
15#include <linux/workqueue.h>
16#include <linux/time.h>
15#include <asm/mutex.h> 17#include <asm/mutex.h>
16 18
17#include "oprof.h" 19#include "oprof.h"
@@ -27,6 +29,15 @@ unsigned long oprofile_backtrace_depth;
27static unsigned long is_setup; 29static unsigned long is_setup;
28static DEFINE_MUTEX(start_mutex); 30static DEFINE_MUTEX(start_mutex);
29 31
32#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
33
34static void switch_worker(struct work_struct *work);
35static DECLARE_DELAYED_WORK(switch_work, switch_worker);
36unsigned long timeout_jiffies;
37#define MULTIPLEXING_TIMER_DEFAULT 1
38
39#endif
40
30/* timer 41/* timer
31 0 - use performance monitoring hardware if available 42 0 - use performance monitoring hardware if available
32 1 - use the timer int mechanism regardless 43 1 - use the timer int mechanism regardless
@@ -87,6 +98,20 @@ out:
87 return err; 98 return err;
88} 99}
89 100
101#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
102
103static void start_switch_worker(void)
104{
105 schedule_delayed_work(&switch_work, timeout_jiffies);
106}
107
108static void switch_worker(struct work_struct *work)
109{
110 if (!oprofile_ops.switch_events())
111 start_switch_worker();
112}
113
114#endif
90 115
91/* Actually start profiling (echo 1>/dev/oprofile/enable) */ 116/* Actually start profiling (echo 1>/dev/oprofile/enable) */
92int oprofile_start(void) 117int oprofile_start(void)
@@ -108,6 +133,11 @@ int oprofile_start(void)
108 if ((err = oprofile_ops.start())) 133 if ((err = oprofile_ops.start()))
109 goto out; 134 goto out;
110 135
136#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
137 if (oprofile_ops.switch_events)
138 start_switch_worker();
139#endif
140
111 oprofile_started = 1; 141 oprofile_started = 1;
112out: 142out:
113 mutex_unlock(&start_mutex); 143 mutex_unlock(&start_mutex);
@@ -123,6 +153,11 @@ void oprofile_stop(void)
123 goto out; 153 goto out;
124 oprofile_ops.stop(); 154 oprofile_ops.stop();
125 oprofile_started = 0; 155 oprofile_started = 0;
156
157#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
158 cancel_delayed_work_sync(&switch_work);
159#endif
160
126 /* wake up the daemon to read what remains */ 161 /* wake up the daemon to read what remains */
127 wake_up_buffer_waiter(); 162 wake_up_buffer_waiter();
128out: 163out:
@@ -155,6 +190,36 @@ post_sync:
155 mutex_unlock(&start_mutex); 190 mutex_unlock(&start_mutex);
156} 191}
157 192
193#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
194
195/* User inputs in ms, converts to jiffies */
196int oprofile_set_timeout(unsigned long val_msec)
197{
198 int err = 0;
199
200 mutex_lock(&start_mutex);
201
202 if (oprofile_started) {
203 err = -EBUSY;
204 goto out;
205 }
206
207 if (!oprofile_ops.switch_events) {
208 err = -EINVAL;
209 goto out;
210 }
211
212 timeout_jiffies = msecs_to_jiffies(val_msec);
213 if (timeout_jiffies == MAX_JIFFY_OFFSET)
214 timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT);
215
216out:
217 mutex_unlock(&start_mutex);
218 return err;
219
220}
221
222#endif
158 223
159int oprofile_set_backtrace(unsigned long val) 224int oprofile_set_backtrace(unsigned long val)
160{ 225{
@@ -179,10 +244,23 @@ out:
179 return err; 244 return err;
180} 245}
181 246
247#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
248
249static void __init oprofile_multiplexing_init(void)
250{
251 timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT);
252}
253
254#endif
255
182static int __init oprofile_init(void) 256static int __init oprofile_init(void)
183{ 257{
184 int err; 258 int err;
185 259
260#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
261 oprofile_multiplexing_init();
262#endif
263
186 err = oprofile_arch_init(&oprofile_ops); 264 err = oprofile_arch_init(&oprofile_ops);
187 265
188 if (err < 0 || timer) { 266 if (err < 0 || timer) {