aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/oprofile/cpu_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/oprofile/cpu_buffer.c')
-rw-r--r--drivers/oprofile/cpu_buffer.c139
1 files changed, 75 insertions, 64 deletions
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 400f7fcffdbe..e859d23cfc57 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -212,6 +212,59 @@ unsigned long op_cpu_buffer_entries(int cpu)
212 + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); 212 + ring_buffer_entries_cpu(op_ring_buffer_write, cpu);
213} 213}
214 214
215static int
216op_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace,
217 int is_kernel, struct task_struct *task)
218{
219 struct op_entry entry;
220 struct op_sample *sample;
221 unsigned long flags;
222 int size;
223
224 flags = 0;
225
226 if (backtrace)
227 flags |= TRACE_BEGIN;
228
229 /* notice a switch from user->kernel or vice versa */
230 is_kernel = !!is_kernel;
231 if (cpu_buf->last_is_kernel != is_kernel) {
232 cpu_buf->last_is_kernel = is_kernel;
233 flags |= KERNEL_CTX_SWITCH;
234 if (is_kernel)
235 flags |= IS_KERNEL;
236 }
237
238 /* notice a task switch */
239 if (cpu_buf->last_task != task) {
240 cpu_buf->last_task = task;
241 flags |= USER_CTX_SWITCH;
242 }
243
244 if (!flags)
245 /* nothing to do */
246 return 0;
247
248 if (flags & USER_CTX_SWITCH)
249 size = 1;
250 else
251 size = 0;
252
253 sample = op_cpu_buffer_write_reserve(&entry, size);
254 if (!sample)
255 return -ENOMEM;
256
257 sample->eip = ESCAPE_CODE;
258 sample->event = flags;
259
260 if (size)
261 sample->data[0] = (unsigned long)task;
262
263 op_cpu_buffer_write_commit(&entry);
264
265 return 0;
266}
267
215static inline int 268static inline int
216op_add_sample(struct oprofile_cpu_buffer *cpu_buf, 269op_add_sample(struct oprofile_cpu_buffer *cpu_buf,
217 unsigned long pc, unsigned long event) 270 unsigned long pc, unsigned long event)
@@ -229,26 +282,18 @@ op_add_sample(struct oprofile_cpu_buffer *cpu_buf,
229 return op_cpu_buffer_write_commit(&entry); 282 return op_cpu_buffer_write_commit(&entry);
230} 283}
231 284
232static inline int 285/*
233add_code(struct oprofile_cpu_buffer *buffer, unsigned long value) 286 * This must be safe from any context.
234{
235 return op_add_sample(buffer, ESCAPE_CODE, value);
236}
237
238/* This must be safe from any context. It's safe writing here
239 * because of the head/tail separation of the writer and reader
240 * of the CPU buffer.
241 * 287 *
242 * is_kernel is needed because on some architectures you cannot 288 * is_kernel is needed because on some architectures you cannot
243 * tell if you are in kernel or user space simply by looking at 289 * tell if you are in kernel or user space simply by looking at
244 * pc. We tag this in the buffer by generating kernel enter/exit 290 * pc. We tag this in the buffer by generating kernel enter/exit
245 * events whenever is_kernel changes 291 * events whenever is_kernel changes
246 */ 292 */
247static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, 293static int
248 int is_kernel, unsigned long event) 294log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
295 unsigned long backtrace, int is_kernel, unsigned long event)
249{ 296{
250 struct task_struct *task;
251
252 cpu_buf->sample_received++; 297 cpu_buf->sample_received++;
253 298
254 if (pc == ESCAPE_CODE) { 299 if (pc == ESCAPE_CODE) {
@@ -256,23 +301,8 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
256 return 0; 301 return 0;
257 } 302 }
258 303
259 is_kernel = !!is_kernel; 304 if (op_add_code(cpu_buf, backtrace, is_kernel, current))
260 305 goto fail;
261 task = current;
262
263 /* notice a switch from user->kernel or vice versa */
264 if (cpu_buf->last_is_kernel != is_kernel) {
265 cpu_buf->last_is_kernel = is_kernel;
266 if (add_code(cpu_buf, is_kernel))
267 goto fail;
268 }
269
270 /* notice a task switch */
271 if (cpu_buf->last_task != task) {
272 cpu_buf->last_task = task;
273 if (add_code(cpu_buf, (unsigned long)task))
274 goto fail;
275 }
276 306
277 if (op_add_sample(cpu_buf, pc, event)) 307 if (op_add_sample(cpu_buf, pc, event))
278 goto fail; 308 goto fail;
@@ -286,7 +316,6 @@ fail:
286 316
287static inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) 317static inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
288{ 318{
289 add_code(cpu_buf, CPU_TRACE_BEGIN);
290 cpu_buf->tracing = 1; 319 cpu_buf->tracing = 1;
291} 320}
292 321
@@ -300,21 +329,21 @@ __oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
300 unsigned long event, int is_kernel) 329 unsigned long event, int is_kernel)
301{ 330{
302 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); 331 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
303 332 unsigned long backtrace = oprofile_backtrace_depth;
304 if (!oprofile_backtrace_depth) {
305 log_sample(cpu_buf, pc, is_kernel, event);
306 return;
307 }
308
309 oprofile_begin_trace(cpu_buf);
310 333
311 /* 334 /*
312 * if log_sample() fail we can't backtrace since we lost the 335 * if log_sample() fail we can't backtrace since we lost the
313 * source of this event 336 * source of this event
314 */ 337 */
315 if (log_sample(cpu_buf, pc, is_kernel, event)) 338 if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event))
316 oprofile_ops.backtrace(regs, oprofile_backtrace_depth); 339 /* failed */
340 return;
317 341
342 if (!backtrace)
343 return;
344
345 oprofile_begin_trace(cpu_buf);
346 oprofile_ops.backtrace(regs, backtrace);
318 oprofile_end_trace(cpu_buf); 347 oprofile_end_trace(cpu_buf);
319} 348}
320 349
@@ -339,29 +368,14 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs,
339{ 368{
340 int is_kernel = !user_mode(regs); 369 int is_kernel = !user_mode(regs);
341 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); 370 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
342 struct task_struct *task;
343 int fail = 0; 371 int fail = 0;
344 372
345 cpu_buf->sample_received++; 373 cpu_buf->sample_received++;
346 374
347 /* notice a switch from user->kernel or vice versa */ 375 /* backtraces disabled for ibs */
348 if (cpu_buf->last_is_kernel != is_kernel) { 376 fail = fail || op_add_code(cpu_buf, 0, is_kernel, current);
349 if (add_code(cpu_buf, is_kernel))
350 goto fail;
351 cpu_buf->last_is_kernel = is_kernel;
352 }
353 377
354 /* notice a task switch */ 378 fail = fail || op_add_sample(cpu_buf, ESCAPE_CODE, ibs_code);
355 if (!is_kernel) {
356 task = current;
357 if (cpu_buf->last_task != task) {
358 if (add_code(cpu_buf, (unsigned long)task))
359 goto fail;
360 cpu_buf->last_task = task;
361 }
362 }
363
364 fail = fail || add_code(cpu_buf, ibs_code);
365 fail = fail || op_add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); 379 fail = fail || op_add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]);
366 fail = fail || op_add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); 380 fail = fail || op_add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]);
367 fail = fail || op_add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); 381 fail = fail || op_add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]);
@@ -372,11 +386,8 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs,
372 fail = fail || op_add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); 386 fail = fail || op_add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]);
373 } 387 }
374 388
375 if (!fail) 389 if (fail)
376 return; 390 cpu_buf->sample_lost_overflow++;
377
378fail:
379 cpu_buf->sample_lost_overflow++;
380} 391}
381 392
382#endif 393#endif
@@ -384,7 +395,7 @@ fail:
384void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) 395void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
385{ 396{
386 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); 397 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
387 log_sample(cpu_buf, pc, is_kernel, event); 398 log_sample(cpu_buf, pc, 0, is_kernel, event);
388} 399}
389 400
390void oprofile_add_trace(unsigned long pc) 401void oprofile_add_trace(unsigned long pc)