diff options
Diffstat (limited to 'drivers/oprofile/cpu_buffer.c')
| -rw-r--r-- | drivers/oprofile/cpu_buffer.c | 74 |
1 files changed, 72 insertions, 2 deletions
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 7ba78e6d210e..e1bd5a937f6c 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. |
| @@ -209,7 +210,7 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc, | |||
| 209 | return 1; | 210 | return 1; |
| 210 | } | 211 | } |
| 211 | 212 | ||
| 212 | static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf) | 213 | static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) |
| 213 | { | 214 | { |
| 214 | if (nr_available_slots(cpu_buf) < 4) { | 215 | if (nr_available_slots(cpu_buf) < 4) { |
| 215 | cpu_buf->sample_lost_overflow++; | 216 | cpu_buf->sample_lost_overflow++; |
| @@ -254,6 +255,75 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) | |||
| 254 | oprofile_add_ext_sample(pc, regs, event, is_kernel); | 255 | oprofile_add_ext_sample(pc, regs, event, is_kernel); |
| 255 | } | 256 | } |
| 256 | 257 | ||
| 258 | #ifdef CONFIG_OPROFILE_IBS | ||
| 259 | |||
| 260 | #define MAX_IBS_SAMPLE_SIZE 14 | ||
| 261 | static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf, | ||
| 262 | unsigned long pc, int is_kernel, unsigned int *ibs, int ibs_code) | ||
| 263 | { | ||
| 264 | struct task_struct *task; | ||
| 265 | |||
| 266 | cpu_buf->sample_received++; | ||
| 267 | |||
| 268 | if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) { | ||
| 269 | cpu_buf->sample_lost_overflow++; | ||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | is_kernel = !!is_kernel; | ||
| 274 | |||
| 275 | /* notice a switch from user->kernel or vice versa */ | ||
| 276 | if (cpu_buf->last_is_kernel != is_kernel) { | ||
| 277 | cpu_buf->last_is_kernel = is_kernel; | ||
| 278 | add_code(cpu_buf, is_kernel); | ||
| 279 | } | ||
| 280 | |||
| 281 | /* notice a task switch */ | ||
| 282 | if (!is_kernel) { | ||
| 283 | task = current; | ||
| 284 | |||
| 285 | if (cpu_buf->last_task != task) { | ||
| 286 | cpu_buf->last_task = task; | ||
| 287 | add_code(cpu_buf, (unsigned long)task); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | add_code(cpu_buf, ibs_code); | ||
| 292 | add_sample(cpu_buf, ibs[0], ibs[1]); | ||
| 293 | add_sample(cpu_buf, ibs[2], ibs[3]); | ||
| 294 | add_sample(cpu_buf, ibs[4], ibs[5]); | ||
| 295 | |||
| 296 | if (ibs_code == IBS_OP_BEGIN) { | ||
| 297 | add_sample(cpu_buf, ibs[6], ibs[7]); | ||
| 298 | add_sample(cpu_buf, ibs[8], ibs[9]); | ||
| 299 | add_sample(cpu_buf, ibs[10], ibs[11]); | ||
| 300 | } | ||
| 301 | |||
| 302 | return 1; | ||
| 303 | } | ||
| 304 | |||
| 305 | void oprofile_add_ibs_sample(struct pt_regs *const regs, | ||
| 306 | unsigned int * const ibs_sample, u8 code) | ||
| 307 | { | ||
| 308 | int is_kernel = !user_mode(regs); | ||
| 309 | unsigned long pc = profile_pc(regs); | ||
| 310 | |||
| 311 | struct oprofile_cpu_buffer *cpu_buf = | ||
| 312 | &per_cpu(cpu_buffer, smp_processor_id()); | ||
| 313 | |||
| 314 | if (!backtrace_depth) { | ||
| 315 | log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code); | ||
| 316 | return; | ||
| 317 | } | ||
| 318 | |||
| 319 | /* if log_sample() fails we can't backtrace since we lost the source | ||
| 320 | * of this event */ | ||
| 321 | if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code)) | ||
| 322 | oprofile_ops.backtrace(regs, backtrace_depth); | ||
| 323 | } | ||
| 324 | |||
| 325 | #endif | ||
| 326 | |||
| 257 | void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) | 327 | void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) |
| 258 | { | 328 | { |
| 259 | struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); | 329 | struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); |
| @@ -296,7 +366,7 @@ static void wq_sync_buffer(struct work_struct *work) | |||
| 296 | struct oprofile_cpu_buffer * b = | 366 | struct oprofile_cpu_buffer * b = |
| 297 | container_of(work, struct oprofile_cpu_buffer, work.work); | 367 | container_of(work, struct oprofile_cpu_buffer, work.work); |
| 298 | if (b->cpu != smp_processor_id()) { | 368 | if (b->cpu != smp_processor_id()) { |
| 299 | printk("WQ on CPU%d, prefer CPU%d\n", | 369 | printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n", |
| 300 | smp_processor_id(), b->cpu); | 370 | smp_processor_id(), b->cpu); |
| 301 | } | 371 | } |
| 302 | sync_buffer(b->cpu); | 372 | sync_buffer(b->cpu); |
