aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-05-12 15:20:45 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-23 14:41:35 -0400
commit93a588f459da134be6ab17c4104e28441beb0d22 (patch)
tree30eb991743d7ce5698f070204d666eca98519213 /kernel/trace
parent1d4db00a5e30c7b8f8dc2a1b19e886fd942be143 (diff)
ftrace: change buffers to producer consumer
This patch changes the way the CPU trace buffers are handled. Instead of always starting from the trace page head, the logic is changed to a producer consumer logic. This allows for the buffers to be drained while they are alive. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace.c103
-rw-r--r--kernel/trace/trace.h6
2 files changed, 65 insertions, 44 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 6580e7ed04be..777b859e1c2e 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -176,10 +176,9 @@ flip_trace(struct trace_array_cpu *tr1, struct trace_array_cpu *tr2)
176 176
177 INIT_LIST_HEAD(&flip_pages); 177 INIT_LIST_HEAD(&flip_pages);
178 178
179 tr1->trace_current = NULL; 179 memcpy(&tr1->trace_head_idx, &tr2->trace_head_idx,
180 memcpy(&tr1->trace_current_idx, &tr2->trace_current_idx,
181 sizeof(struct trace_array_cpu) - 180 sizeof(struct trace_array_cpu) -
182 offsetof(struct trace_array_cpu, trace_current_idx)); 181 offsetof(struct trace_array_cpu, trace_head_idx));
183 182
184 check_pages(tr1); 183 check_pages(tr1);
185 check_pages(tr2); 184 check_pages(tr2);
@@ -228,7 +227,6 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
228 tracing_reset(max_tr.data[i]); 227 tracing_reset(max_tr.data[i]);
229 228
230 flip_trace(max_tr.data[cpu], data); 229 flip_trace(max_tr.data[cpu], data);
231
232 tracing_reset(data); 230 tracing_reset(data);
233 231
234 __update_max_tr(tr, tsk, cpu); 232 __update_max_tr(tr, tsk, cpu);
@@ -343,9 +341,9 @@ void unregister_tracer(struct tracer *type)
343notrace void tracing_reset(struct trace_array_cpu *data) 341notrace void tracing_reset(struct trace_array_cpu *data)
344{ 342{
345 data->trace_idx = 0; 343 data->trace_idx = 0;
346 data->trace_current = head_page(data); 344 data->trace_head = data->trace_tail = head_page(data);
347 data->trace_current_idx = 0; 345 data->trace_head_idx = 0;
348 data->time_offset = 0; 346 data->trace_tail_idx = 0;
349} 347}
350 348
351#ifdef CONFIG_FTRACE 349#ifdef CONFIG_FTRACE
@@ -470,38 +468,65 @@ notrace void tracing_record_cmdline(struct task_struct *tsk)
470 trace_save_cmdline(tsk); 468 trace_save_cmdline(tsk);
471} 469}
472 470
471static inline notrace struct list_head *
472trace_next_list(struct trace_array_cpu *data, struct list_head *next)
473{
474 /*
475 * Roundrobin - but skip the head (which is not a real page):
476 */
477 next = next->next;
478 if (unlikely(next == &data->trace_pages))
479 next = next->next;
480 BUG_ON(next == &data->trace_pages);
481
482 return next;
483}
484
485static inline notrace void *
486trace_next_page(struct trace_array_cpu *data, void *addr)
487{
488 struct list_head *next;
489 struct page *page;
490
491 page = virt_to_page(addr);
492
493 next = trace_next_list(data, &page->lru);
494 page = list_entry(next, struct page, lru);
495
496 return page_address(page);
497}
498
473static inline notrace struct trace_entry * 499static inline notrace struct trace_entry *
474tracing_get_trace_entry(struct trace_array *tr, struct trace_array_cpu *data) 500tracing_get_trace_entry(struct trace_array *tr, struct trace_array_cpu *data)
475{ 501{
476 unsigned long idx, idx_next; 502 unsigned long idx, idx_next;
477 struct trace_entry *entry; 503 struct trace_entry *entry;
478 struct list_head *next;
479 struct page *page;
480 504
481 data->trace_idx++; 505 data->trace_idx++;
482 idx = data->trace_current_idx; 506 idx = data->trace_head_idx;
483 idx_next = idx + 1; 507 idx_next = idx + 1;
484 508
485 BUG_ON(idx * TRACE_ENTRY_SIZE >= PAGE_SIZE); 509 BUG_ON(idx * TRACE_ENTRY_SIZE >= PAGE_SIZE);
486 510
487 entry = data->trace_current + idx * TRACE_ENTRY_SIZE; 511 entry = data->trace_head + idx * TRACE_ENTRY_SIZE;
488 512
489 if (unlikely(idx_next >= ENTRIES_PER_PAGE)) { 513 if (unlikely(idx_next >= ENTRIES_PER_PAGE)) {
490 page = virt_to_page(data->trace_current); 514 data->trace_head = trace_next_page(data, data->trace_head);
491 /*
492 * Roundrobin - but skip the head (which is not a real page):
493 */
494 next = page->lru.next;
495 if (unlikely(next == &data->trace_pages))
496 next = next->next;
497 BUG_ON(next == &data->trace_pages);
498
499 page = list_entry(next, struct page, lru);
500 data->trace_current = page_address(page);
501 idx_next = 0; 515 idx_next = 0;
502 } 516 }
503 517
504 data->trace_current_idx = idx_next; 518 if (data->trace_head == data->trace_tail &&
519 idx_next == data->trace_tail_idx) {
520 /* overrun */
521 data->trace_tail_idx++;
522 if (data->trace_tail_idx >= ENTRIES_PER_PAGE) {
523 data->trace_tail =
524 trace_next_page(data, data->trace_tail);
525 data->trace_tail_idx = 0;
526 }
527 }
528
529 data->trace_head_idx = idx_next;
505 530
506 return entry; 531 return entry;
507} 532}
@@ -571,21 +596,11 @@ trace_entry_idx(struct trace_array *tr, struct trace_array_cpu *data,
571 return NULL; 596 return NULL;
572 597
573 if (!iter->next_page[cpu]) { 598 if (!iter->next_page[cpu]) {
574 /* 599 /* Initialize the iterator for this cpu trace buffer */
575 * Initialize. If the count of elements in 600 WARN_ON(!data->trace_tail);
576 * this buffer is greater than the max entries 601 page = virt_to_page(data->trace_tail);
577 * we had an underrun. Which means we looped around. 602 iter->next_page[cpu] = &page->lru;
578 * We can simply use the current pointer as our 603 iter->next_page_idx[cpu] = data->trace_tail_idx;
579 * starting point.
580 */
581 if (data->trace_idx >= tr->entries) {
582 page = virt_to_page(data->trace_current);
583 iter->next_page[cpu] = &page->lru;
584 iter->next_page_idx[cpu] = data->trace_current_idx;
585 } else {
586 iter->next_page[cpu] = data->trace_pages.next;
587 iter->next_page_idx[cpu] = 0;
588 }
589 } 604 }
590 605
591 page = list_entry(iter->next_page[cpu], struct page, lru); 606 page = list_entry(iter->next_page[cpu], struct page, lru);
@@ -593,6 +608,12 @@ trace_entry_idx(struct trace_array *tr, struct trace_array_cpu *data,
593 608
594 array = page_address(page); 609 array = page_address(page);
595 610
611 /* Still possible to catch up to the tail */
612 if (iter->next_idx[cpu] && array == data->trace_tail &&
613 iter->next_page_idx[cpu] == data->trace_tail_idx)
614 return NULL;
615
616 WARN_ON(iter->next_page_idx[cpu] >= ENTRIES_PER_PAGE);
596 return &array[iter->next_page_idx[cpu]]; 617 return &array[iter->next_page_idx[cpu]];
597} 618}
598 619
@@ -638,10 +659,8 @@ static void *find_next_entry_inc(struct trace_iterator *iter)
638 659
639 iter->next_page_idx[next_cpu] = 0; 660 iter->next_page_idx[next_cpu] = 0;
640 iter->next_page[next_cpu] = 661 iter->next_page[next_cpu] =
641 iter->next_page[next_cpu]->next; 662 trace_next_list(data, iter->next_page[next_cpu]);
642 if (iter->next_page[next_cpu] == &data->trace_pages) 663
643 iter->next_page[next_cpu] =
644 data->trace_pages.next;
645 } 664 }
646 } 665 }
647 iter->prev_ent = iter->ent; 666 iter->prev_ent = iter->ent;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 5df8ff2b84a7..0ce127455b4b 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -53,13 +53,15 @@ struct trace_entry {
53 * the trace, etc.) 53 * the trace, etc.)
54 */ 54 */
55struct trace_array_cpu { 55struct trace_array_cpu {
56 void *trace_current;
57 struct list_head trace_pages; 56 struct list_head trace_pages;
58 atomic_t disabled; 57 atomic_t disabled;
59 cycle_t time_offset; 58 cycle_t time_offset;
60 59
61 /* these fields get copied into max-trace: */ 60 /* these fields get copied into max-trace: */
62 unsigned trace_current_idx; 61 unsigned trace_head_idx;
62 unsigned trace_tail_idx;
63 void *trace_head; /* producer */
64 void *trace_tail; /* consumer */
63 unsigned long trace_idx; 65 unsigned long trace_idx;
64 unsigned long saved_latency; 66 unsigned long saved_latency;
65 unsigned long critical_start; 67 unsigned long critical_start;