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 @@   * @remark Read the file COPYING   *   * @author John Levon <levon@movementarian.org> + * @author Barry Kasindorf <barry.kasindorf@amd.com>   *   * Each CPU has a local buffer that stores PC value/event   * 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,  	return 1;  } -static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf) +static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)  {  	if (nr_available_slots(cpu_buf) < 4) {  		cpu_buf->sample_lost_overflow++; @@ -254,6 +255,75 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)  	oprofile_add_ext_sample(pc, regs, event, is_kernel);  } +#ifdef CONFIG_OPROFILE_IBS + +#define MAX_IBS_SAMPLE_SIZE	14 +static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf, +	unsigned long pc, int is_kernel, unsigned  int *ibs, int ibs_code) +{ +	struct task_struct *task; + +	cpu_buf->sample_received++; + +	if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) { +		cpu_buf->sample_lost_overflow++; +		return 0; +	} + +	is_kernel = !!is_kernel; + +	/* notice a switch from user->kernel or vice versa */ +	if (cpu_buf->last_is_kernel != is_kernel) { +		cpu_buf->last_is_kernel = is_kernel; +		add_code(cpu_buf, is_kernel); +	} + +	/* notice a task switch */ +	if (!is_kernel) { +		task = current; + +		if (cpu_buf->last_task != task) { +			cpu_buf->last_task = task; +			add_code(cpu_buf, (unsigned long)task); +		} +	} + +	add_code(cpu_buf, ibs_code); +	add_sample(cpu_buf, ibs[0], ibs[1]); +	add_sample(cpu_buf, ibs[2], ibs[3]); +	add_sample(cpu_buf, ibs[4], ibs[5]); + +	if (ibs_code == IBS_OP_BEGIN) { +	add_sample(cpu_buf, ibs[6], ibs[7]); +	add_sample(cpu_buf, ibs[8], ibs[9]); +	add_sample(cpu_buf, ibs[10], ibs[11]); +	} + +	return 1; +} + +void oprofile_add_ibs_sample(struct pt_regs *const regs, +				unsigned int * const ibs_sample, u8 code) +{ +	int is_kernel = !user_mode(regs); +	unsigned long pc = profile_pc(regs); + +	struct oprofile_cpu_buffer *cpu_buf = +			 &per_cpu(cpu_buffer, smp_processor_id()); + +	if (!backtrace_depth) { +		log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code); +		return; +	} + +	/* if log_sample() fails we can't backtrace since we lost the source +	* of this event */ +	if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code)) +		oprofile_ops.backtrace(regs, backtrace_depth); +} + +#endif +  void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)  {  	struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); @@ -296,7 +366,7 @@ static void wq_sync_buffer(struct work_struct *work)  	struct oprofile_cpu_buffer * b =  		container_of(work, struct oprofile_cpu_buffer, work.work);  	if (b->cpu != smp_processor_id()) { -		printk("WQ on CPU%d, prefer CPU%d\n", +		printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n",  		       smp_processor_id(), b->cpu);  	}  	sync_buffer(b->cpu);  | 
