diff options
author | Jason Yeh <jason.yeh@amd.com> | 2008-07-23 17:05:53 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-26 05:48:16 -0400 |
commit | 1a960b402a51d80abf54e3f8e4972374ffe5f22d (patch) | |
tree | 108222afe94df145e7a71f44bb077067c35f0131 /drivers | |
parent | 6852fd9b86d05063c6ef49d2e12e061cc7f6a105 (diff) |
Oprofile Multiplexing Patch
This patch introduces multiplexing support for the Oprofile kernel
module. It basically adds a new function pointer in oprofile_operator
allowing each architecture to supply its callback to switch between
different sets of event when the timer expires. Userspace tools can
modify the time slice through /dev/oprofile/time_slice.
It also modifies the number of counters exposed to the userspace through
/dev/oprofile. For example, the number of counters for AMD CPUs are
changed to 32 and multiplexed in the sets of 4.
Signed-off-by: Jason Yeh <jason.yeh@amd.com>
Signed-off-by: Robert Richter <robert.richter@amd.com>
Cc: oprofile-list <oprofile-list@lists.sourceforge.net>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/oprofile/oprof.c | 58 | ||||
-rw-r--r-- | drivers/oprofile/oprof.h | 4 | ||||
-rw-r--r-- | drivers/oprofile/oprofile_files.c | 39 |
3 files changed, 95 insertions, 6 deletions
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 2c645170f06e..b2fa5df64a62 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" |
@@ -19,13 +21,18 @@ | |||
19 | #include "cpu_buffer.h" | 21 | #include "cpu_buffer.h" |
20 | #include "buffer_sync.h" | 22 | #include "buffer_sync.h" |
21 | #include "oprofile_stats.h" | 23 | #include "oprofile_stats.h" |
24 | |||
25 | static unsigned long is_setup; | ||
26 | static void switch_worker(struct work_struct *work); | ||
27 | static DECLARE_DELAYED_WORK(switch_work, switch_worker); | ||
28 | static DEFINE_MUTEX(start_mutex); | ||
22 | 29 | ||
23 | struct oprofile_operations oprofile_ops; | 30 | struct oprofile_operations oprofile_ops; |
24 | 31 | ||
32 | unsigned long timeout_jiffies; | ||
25 | unsigned long oprofile_started; | 33 | unsigned long oprofile_started; |
26 | unsigned long backtrace_depth; | 34 | unsigned long backtrace_depth; |
27 | static unsigned long is_setup; | 35 | /* Multiplexing defaults at 1 msec*/ |
28 | static DEFINE_MUTEX(start_mutex); | ||
29 | 36 | ||
30 | /* timer | 37 | /* timer |
31 | 0 - use performance monitoring hardware if available | 38 | 0 - use performance monitoring hardware if available |
@@ -87,6 +94,16 @@ out: | |||
87 | return err; | 94 | return err; |
88 | } | 95 | } |
89 | 96 | ||
97 | static void start_switch_worker(void) | ||
98 | { | ||
99 | schedule_delayed_work(&switch_work, timeout_jiffies); | ||
100 | } | ||
101 | |||
102 | static void switch_worker(struct work_struct *work) | ||
103 | { | ||
104 | if (!oprofile_ops.switch_events()) | ||
105 | start_switch_worker(); | ||
106 | } | ||
90 | 107 | ||
91 | /* Actually start profiling (echo 1>/dev/oprofile/enable) */ | 108 | /* Actually start profiling (echo 1>/dev/oprofile/enable) */ |
92 | int oprofile_start(void) | 109 | int oprofile_start(void) |
@@ -94,7 +111,6 @@ int oprofile_start(void) | |||
94 | int err = -EINVAL; | 111 | int err = -EINVAL; |
95 | 112 | ||
96 | mutex_lock(&start_mutex); | 113 | mutex_lock(&start_mutex); |
97 | |||
98 | if (!is_setup) | 114 | if (!is_setup) |
99 | goto out; | 115 | goto out; |
100 | 116 | ||
@@ -108,6 +124,9 @@ int oprofile_start(void) | |||
108 | if ((err = oprofile_ops.start())) | 124 | if ((err = oprofile_ops.start())) |
109 | goto out; | 125 | goto out; |
110 | 126 | ||
127 | if (oprofile_ops.switch_events) | ||
128 | start_switch_worker(); | ||
129 | |||
111 | oprofile_started = 1; | 130 | oprofile_started = 1; |
112 | out: | 131 | out: |
113 | mutex_unlock(&start_mutex); | 132 | mutex_unlock(&start_mutex); |
@@ -123,6 +142,7 @@ void oprofile_stop(void) | |||
123 | goto out; | 142 | goto out; |
124 | oprofile_ops.stop(); | 143 | oprofile_ops.stop(); |
125 | oprofile_started = 0; | 144 | oprofile_started = 0; |
145 | cancel_delayed_work_sync(&switch_work); | ||
126 | /* wake up the daemon to read what remains */ | 146 | /* wake up the daemon to read what remains */ |
127 | wake_up_buffer_waiter(); | 147 | wake_up_buffer_waiter(); |
128 | out: | 148 | out: |
@@ -155,6 +175,32 @@ post_sync: | |||
155 | mutex_unlock(&start_mutex); | 175 | mutex_unlock(&start_mutex); |
156 | } | 176 | } |
157 | 177 | ||
178 | /* User inputs in ms, converts to jiffies */ | ||
179 | int oprofile_set_timeout(unsigned long val_msec) | ||
180 | { | ||
181 | int err = 0; | ||
182 | |||
183 | mutex_lock(&start_mutex); | ||
184 | |||
185 | if (oprofile_started) { | ||
186 | err = -EBUSY; | ||
187 | goto out; | ||
188 | } | ||
189 | |||
190 | if (!oprofile_ops.switch_events) { | ||
191 | err = -EINVAL; | ||
192 | goto out; | ||
193 | } | ||
194 | |||
195 | timeout_jiffies = msecs_to_jiffies(val_msec); | ||
196 | if (timeout_jiffies == MAX_JIFFY_OFFSET) | ||
197 | timeout_jiffies = msecs_to_jiffies(1); | ||
198 | |||
199 | out: | ||
200 | mutex_unlock(&start_mutex); | ||
201 | return err; | ||
202 | |||
203 | } | ||
158 | 204 | ||
159 | int oprofile_set_backtrace(unsigned long val) | 205 | int oprofile_set_backtrace(unsigned long val) |
160 | { | 206 | { |
@@ -179,10 +225,16 @@ out: | |||
179 | return err; | 225 | return err; |
180 | } | 226 | } |
181 | 227 | ||
228 | static void __init oprofile_switch_timer_init(void) | ||
229 | { | ||
230 | timeout_jiffies = msecs_to_jiffies(1); | ||
231 | } | ||
232 | |||
182 | static int __init oprofile_init(void) | 233 | static int __init oprofile_init(void) |
183 | { | 234 | { |
184 | int err; | 235 | int err; |
185 | 236 | ||
237 | oprofile_switch_timer_init(); | ||
186 | err = oprofile_arch_init(&oprofile_ops); | 238 | err = oprofile_arch_init(&oprofile_ops); |
187 | 239 | ||
188 | if (err < 0 || timer) { | 240 | if (err < 0 || timer) { |
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index 18323650806e..c4406a7366bb 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h | |||
@@ -27,7 +27,8 @@ extern unsigned long fs_buffer_watershed; | |||
27 | extern struct oprofile_operations oprofile_ops; | 27 | extern struct oprofile_operations oprofile_ops; |
28 | extern unsigned long oprofile_started; | 28 | extern unsigned long oprofile_started; |
29 | extern unsigned long backtrace_depth; | 29 | extern unsigned long backtrace_depth; |
30 | 30 | extern unsigned long timeout_jiffies; | |
31 | |||
31 | struct super_block; | 32 | struct super_block; |
32 | struct dentry; | 33 | struct dentry; |
33 | 34 | ||
@@ -35,5 +36,6 @@ void oprofile_create_files(struct super_block * sb, struct dentry * root); | |||
35 | void oprofile_timer_init(struct oprofile_operations * ops); | 36 | void oprofile_timer_init(struct oprofile_operations * ops); |
36 | 37 | ||
37 | int oprofile_set_backtrace(unsigned long depth); | 38 | int oprofile_set_backtrace(unsigned long depth); |
39 | int oprofile_set_timeout(unsigned long time); | ||
38 | 40 | ||
39 | #endif /* OPROF_H */ | 41 | #endif /* OPROF_H */ |
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index ef953ba5ab6b..cc4f5a1f8ef2 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
11 | #include <linux/oprofile.h> | 11 | #include <linux/oprofile.h> |
12 | #include <linux/jiffies.h> | ||
12 | 13 | ||
13 | #include "event_buffer.h" | 14 | #include "event_buffer.h" |
14 | #include "oprofile_stats.h" | 15 | #include "oprofile_stats.h" |
@@ -18,6 +19,40 @@ unsigned long fs_buffer_size = 131072; | |||
18 | unsigned long fs_cpu_buffer_size = 8192; | 19 | unsigned long fs_cpu_buffer_size = 8192; |
19 | unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */ | 20 | unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */ |
20 | 21 | ||
22 | static ssize_t timeout_read(struct file *file, char __user *buf, | ||
23 | size_t count, loff_t *offset) | ||
24 | { | ||
25 | return oprofilefs_ulong_to_user(jiffies_to_msecs(timeout_jiffies), | ||
26 | buf, count, offset); | ||
27 | } | ||
28 | |||
29 | |||
30 | static ssize_t timeout_write(struct file *file, char const __user *buf, | ||
31 | size_t count, loff_t *offset) | ||
32 | { | ||
33 | unsigned long val; | ||
34 | int retval; | ||
35 | |||
36 | if (*offset) | ||
37 | return -EINVAL; | ||
38 | |||
39 | retval = oprofilefs_ulong_from_user(&val, buf, count); | ||
40 | if (retval) | ||
41 | return retval; | ||
42 | |||
43 | retval = oprofile_set_timeout(val); | ||
44 | |||
45 | if (retval) | ||
46 | return retval; | ||
47 | return count; | ||
48 | } | ||
49 | |||
50 | static const struct file_operations timeout_fops = { | ||
51 | .read = timeout_read, | ||
52 | .write = timeout_write, | ||
53 | }; | ||
54 | |||
55 | |||
21 | static ssize_t depth_read(struct file * file, char __user * buf, size_t count, loff_t * offset) | 56 | static ssize_t depth_read(struct file * file, char __user * buf, size_t count, loff_t * offset) |
22 | { | 57 | { |
23 | return oprofilefs_ulong_to_user(backtrace_depth, buf, count, offset); | 58 | return oprofilefs_ulong_to_user(backtrace_depth, buf, count, offset); |
@@ -85,11 +120,10 @@ static ssize_t enable_write(struct file * file, char const __user * buf, size_t | |||
85 | 120 | ||
86 | if (*offset) | 121 | if (*offset) |
87 | return -EINVAL; | 122 | return -EINVAL; |
88 | |||
89 | retval = oprofilefs_ulong_from_user(&val, buf, count); | 123 | retval = oprofilefs_ulong_from_user(&val, buf, count); |
90 | if (retval) | 124 | if (retval) |
91 | return retval; | 125 | return retval; |
92 | 126 | ||
93 | if (val) | 127 | if (val) |
94 | retval = oprofile_start(); | 128 | retval = oprofile_start(); |
95 | else | 129 | else |
@@ -129,6 +163,7 @@ void oprofile_create_files(struct super_block * sb, struct dentry * root) | |||
129 | oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); | 163 | oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); |
130 | oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); | 164 | oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); |
131 | oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); | 165 | oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); |
166 | oprofilefs_create_file(sb, root, "timeout_ms", &timeout_fops); | ||
132 | oprofile_create_stats_files(sb, root); | 167 | oprofile_create_stats_files(sb, root); |
133 | if (oprofile_ops.create_files) | 168 | if (oprofile_ops.create_files) |
134 | oprofile_ops.create_files(sb, root); | 169 | oprofile_ops.create_files(sb, root); |