aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/oprofile/buffer_sync.c
diff options
context:
space:
mode:
authorRobert Richter <robert.richter@amd.com>2008-12-08 19:21:32 -0500
committerRobert Richter <robert.richter@amd.com>2008-12-10 08:20:18 -0500
commit6dad828b76c7224a22ddc9ce7aa495d994f03b31 (patch)
tree364de7a3efd56d60c0742145e3a8d3d4f73bcde4 /drivers/oprofile/buffer_sync.c
parente09373f22e76cc048ca5fe10a9ff9012f5d64309 (diff)
oprofile: port to the new ring_buffer
This patch replaces the current oprofile cpu buffer implementation with the ring buffer provided by the tracing framework. The motivation here is to leave the pain of implementing ring buffers to others. Oh, no, there are more advantages. Main reason is the support of different sample sizes that could be stored in the buffer. Use cases for this are IBS and Cell spu profiling. Using the new ring buffer ensures valid and complete samples and allows copying the cpu buffer stateless without knowing its content. Second it will use generic kernel API and also reduce code size. And hopefully, there are less bugs. Since the new tracing ring buffer implementation uses spin locks to protect the buffer during read/write access, it is difficult to use the buffer in an NMI handler. In this case, writing to the buffer by the NMI handler (x86) could occur also during critical sections when reading the buffer. To avoid this, there are 2 buffers for independent read and write access. Read access is in process context only, write access only in the NMI handler. If the read buffer runs empty, both buffers are swapped atomically. There is potentially a small window during swapping where the buffers are disabled and samples could be lost. Using 2 buffers is a little bit overhead, but the solution is clear and does not require changes in the ring buffer implementation. It can be changed to a single buffer solution when the ring buffer access is implemented as non-locking atomic code. The new buffer requires more size to store the same amount of samples because each sample includes an u32 header. Also, there is more code to execute for buffer access. Nonetheless, the buffer implementation is proven in the ftrace environment and worth to use also in oprofile. Patches that changes the internal IBS buffer usage will follow. Cc: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Robert Richter <robert.richter@amd.com>
Diffstat (limited to 'drivers/oprofile/buffer_sync.c')
-rw-r--r--drivers/oprofile/buffer_sync.c65
1 files changed, 25 insertions, 40 deletions
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 944a5832d9e4..737bd9484822 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -268,18 +268,6 @@ lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset)
268 return cookie; 268 return cookie;
269} 269}
270 270
271static void increment_tail(struct oprofile_cpu_buffer *b)
272{
273 unsigned long new_tail = b->tail_pos + 1;
274
275 rmb(); /* be sure fifo pointers are synchronized */
276
277 if (new_tail < b->buffer_size)
278 b->tail_pos = new_tail;
279 else
280 b->tail_pos = 0;
281}
282
283static unsigned long last_cookie = INVALID_COOKIE; 271static unsigned long last_cookie = INVALID_COOKIE;
284 272
285static void add_cpu_switch(int i) 273static void add_cpu_switch(int i)
@@ -331,26 +319,25 @@ static void add_trace_begin(void)
331 319
332#define IBS_FETCH_CODE_SIZE 2 320#define IBS_FETCH_CODE_SIZE 2
333#define IBS_OP_CODE_SIZE 5 321#define IBS_OP_CODE_SIZE 5
334#define IBS_EIP(cpu_buf) ((cpu_buffer_read_entry(cpu_buf))->eip)
335#define IBS_EVENT(cpu_buf) ((cpu_buffer_read_entry(cpu_buf))->event)
336 322
337/* 323/*
338 * Add IBS fetch and op entries to event buffer 324 * Add IBS fetch and op entries to event buffer
339 */ 325 */
340static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code, 326static void add_ibs_begin(int cpu, int code, struct mm_struct *mm)
341 struct mm_struct *mm)
342{ 327{
343 unsigned long rip; 328 unsigned long rip;
344 int i, count; 329 int i, count;
345 unsigned long ibs_cookie = 0; 330 unsigned long ibs_cookie = 0;
346 off_t offset; 331 off_t offset;
332 struct op_sample *sample;
347 333
348 increment_tail(cpu_buf); /* move to RIP entry */ 334 sample = cpu_buffer_read_entry(cpu);
349 335 if (!sample)
350 rip = IBS_EIP(cpu_buf); 336 goto Error;
337 rip = sample->eip;
351 338
352#ifdef __LP64__ 339#ifdef __LP64__
353 rip += IBS_EVENT(cpu_buf) << 32; 340 rip += sample->event << 32;
354#endif 341#endif
355 342
356 if (mm) { 343 if (mm) {
@@ -374,8 +361,8 @@ static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
374 add_event_entry(offset); /* Offset from Dcookie */ 361 add_event_entry(offset); /* Offset from Dcookie */
375 362
376 /* we send the Dcookie offset, but send the raw Linear Add also*/ 363 /* we send the Dcookie offset, but send the raw Linear Add also*/
377 add_event_entry(IBS_EIP(cpu_buf)); 364 add_event_entry(sample->eip);
378 add_event_entry(IBS_EVENT(cpu_buf)); 365 add_event_entry(sample->event);
379 366
380 if (code == IBS_FETCH_CODE) 367 if (code == IBS_FETCH_CODE)
381 count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/ 368 count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/
@@ -383,10 +370,17 @@ static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
383 count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/ 370 count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/
384 371
385 for (i = 0; i < count; i++) { 372 for (i = 0; i < count; i++) {
386 increment_tail(cpu_buf); 373 sample = cpu_buffer_read_entry(cpu);
387 add_event_entry(IBS_EIP(cpu_buf)); 374 if (!sample)
388 add_event_entry(IBS_EVENT(cpu_buf)); 375 goto Error;
376 add_event_entry(sample->eip);
377 add_event_entry(sample->event);
389 } 378 }
379
380 return;
381
382Error:
383 return;
390} 384}
391 385
392#endif 386#endif
@@ -530,33 +524,26 @@ typedef enum {
530 */ 524 */
531void sync_buffer(int cpu) 525void sync_buffer(int cpu)
532{ 526{
533 struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
534 struct mm_struct *mm = NULL; 527 struct mm_struct *mm = NULL;
535 struct mm_struct *oldmm; 528 struct mm_struct *oldmm;
536 struct task_struct *new; 529 struct task_struct *new;
537 unsigned long cookie = 0; 530 unsigned long cookie = 0;
538 int in_kernel = 1; 531 int in_kernel = 1;
539 sync_buffer_state state = sb_buffer_start; 532 sync_buffer_state state = sb_buffer_start;
540#ifndef CONFIG_OPROFILE_IBS
541 unsigned int i; 533 unsigned int i;
542 unsigned long available; 534 unsigned long available;
543#endif
544 535
545 mutex_lock(&buffer_mutex); 536 mutex_lock(&buffer_mutex);
546 537
547 add_cpu_switch(cpu); 538 add_cpu_switch(cpu);
548 539
549 /* Remember, only we can modify tail_pos */
550
551 cpu_buffer_reset(cpu); 540 cpu_buffer_reset(cpu);
552#ifndef CONFIG_OPROFILE_IBS 541 available = cpu_buffer_entries(cpu);
553 available = cpu_buffer_entries(cpu_buf);
554 542
555 for (i = 0; i < available; ++i) { 543 for (i = 0; i < available; ++i) {
556#else 544 struct op_sample *s = cpu_buffer_read_entry(cpu);
557 while (cpu_buffer_entries(cpu_buf)) { 545 if (!s)
558#endif 546 break;
559 struct op_sample *s = cpu_buffer_read_entry(cpu_buf);
560 547
561 if (is_code(s->eip)) { 548 if (is_code(s->eip)) {
562 switch (s->event) { 549 switch (s->event) {
@@ -575,11 +562,11 @@ void sync_buffer(int cpu)
575#ifdef CONFIG_OPROFILE_IBS 562#ifdef CONFIG_OPROFILE_IBS
576 case IBS_FETCH_BEGIN: 563 case IBS_FETCH_BEGIN:
577 state = sb_bt_start; 564 state = sb_bt_start;
578 add_ibs_begin(cpu_buf, IBS_FETCH_CODE, mm); 565 add_ibs_begin(cpu, IBS_FETCH_CODE, mm);
579 break; 566 break;
580 case IBS_OP_BEGIN: 567 case IBS_OP_BEGIN:
581 state = sb_bt_start; 568 state = sb_bt_start;
582 add_ibs_begin(cpu_buf, IBS_OP_CODE, mm); 569 add_ibs_begin(cpu, IBS_OP_CODE, mm);
583 break; 570 break;
584#endif 571#endif
585 default: 572 default:
@@ -600,8 +587,6 @@ void sync_buffer(int cpu)
600 atomic_inc(&oprofile_stats.bt_lost_no_mapping); 587 atomic_inc(&oprofile_stats.bt_lost_no_mapping);
601 } 588 }
602 } 589 }
603
604 increment_tail(cpu_buf);
605 } 590 }
606 release_mm(mm); 591 release_mm(mm);
607 592