diff options
author | Barry Kasindorf <barry.kasindorf@amd.com> | 2008-07-22 15:08:54 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-26 05:48:04 -0400 |
commit | 345c25730d085c45622ac779da4dbd97dc3a10fe (patch) | |
tree | 12f31ee55b97ef9604b37990e05c523178c32901 /drivers/oprofile/cpu_buffer.c | |
parent | ee648bc77f11b57d15a68d336fc30e343198f893 (diff) |
x86/oprofile: add IBS support for AMD CPUs, IBS buffer handling routines
This patchset supports the new profiling hardware available in the
latest AMD CPUs in the oProfile driver.
Signed-off-by: Barry Kasindorf <barry.kasindorf@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/oprofile/cpu_buffer.c')
-rw-r--r-- | drivers/oprofile/cpu_buffer.c | 68 |
1 files changed, 67 insertions, 1 deletions
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 2450b3a393ff..c9ac4e156918 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * @remark Read the file COPYING | 5 | * @remark Read the file COPYING |
6 | * | 6 | * |
7 | * @author John Levon <levon@movementarian.org> | 7 | * @author John Levon <levon@movementarian.org> |
8 | * @author Barry Kasindorf <barry.kasindorf@amd.com> | ||
8 | * | 9 | * |
9 | * Each CPU has a local buffer that stores PC value/event | 10 | * Each CPU has a local buffer that stores PC value/event |
10 | * pairs. We also log context switches when we notice them. | 11 | * pairs. We also log context switches when we notice them. |
@@ -207,7 +208,7 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc, | |||
207 | return 1; | 208 | return 1; |
208 | } | 209 | } |
209 | 210 | ||
210 | static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf) | 211 | static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) |
211 | { | 212 | { |
212 | if (nr_available_slots(cpu_buf) < 4) { | 213 | if (nr_available_slots(cpu_buf) < 4) { |
213 | cpu_buf->sample_lost_overflow++; | 214 | cpu_buf->sample_lost_overflow++; |
@@ -252,6 +253,71 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) | |||
252 | oprofile_add_ext_sample(pc, regs, event, is_kernel); | 253 | oprofile_add_ext_sample(pc, regs, event, is_kernel); |
253 | } | 254 | } |
254 | 255 | ||
256 | #define MAX_IBS_SAMPLE_SIZE 14 | ||
257 | static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf, | ||
258 | unsigned long pc, int is_kernel, unsigned int *ibs, int ibs_code) | ||
259 | { | ||
260 | struct task_struct *task; | ||
261 | |||
262 | cpu_buf->sample_received++; | ||
263 | |||
264 | if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) { | ||
265 | cpu_buf->sample_lost_overflow++; | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | is_kernel = !!is_kernel; | ||
270 | |||
271 | /* notice a switch from user->kernel or vice versa */ | ||
272 | if (cpu_buf->last_is_kernel != is_kernel) { | ||
273 | cpu_buf->last_is_kernel = is_kernel; | ||
274 | add_code(cpu_buf, is_kernel); | ||
275 | } | ||
276 | |||
277 | /* notice a task switch */ | ||
278 | if (!is_kernel) { | ||
279 | task = current; | ||
280 | |||
281 | if (cpu_buf->last_task != task) { | ||
282 | cpu_buf->last_task = task; | ||
283 | add_code(cpu_buf, (unsigned long)task); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | add_code(cpu_buf, ibs_code); | ||
288 | add_sample(cpu_buf, ibs[0], ibs[1]); | ||
289 | add_sample(cpu_buf, ibs[2], ibs[3]); | ||
290 | add_sample(cpu_buf, ibs[4], ibs[5]); | ||
291 | |||
292 | if (ibs_code == IBS_OP_BEGIN) { | ||
293 | add_sample(cpu_buf, ibs[6], ibs[7]); | ||
294 | add_sample(cpu_buf, ibs[8], ibs[9]); | ||
295 | add_sample(cpu_buf, ibs[10], ibs[11]); | ||
296 | } | ||
297 | |||
298 | return 1; | ||
299 | } | ||
300 | |||
301 | void oprofile_add_ibs_sample(struct pt_regs *const regs, | ||
302 | unsigned int * const ibs_sample, u8 code) | ||
303 | { | ||
304 | int is_kernel = !user_mode(regs); | ||
305 | unsigned long pc = profile_pc(regs); | ||
306 | |||
307 | struct oprofile_cpu_buffer *cpu_buf = | ||
308 | &per_cpu(cpu_buffer, smp_processor_id()); | ||
309 | |||
310 | if (!backtrace_depth) { | ||
311 | log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code); | ||
312 | return; | ||
313 | } | ||
314 | |||
315 | /* if log_sample() fails we can't backtrace since we lost the source | ||
316 | * of this event */ | ||
317 | if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code)) | ||
318 | oprofile_ops.backtrace(regs, backtrace_depth); | ||
319 | } | ||
320 | |||
255 | void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) | 321 | void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) |
256 | { | 322 | { |
257 | struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); | 323 | struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); |