diff options
| author | Steven Rostedt <rostedt@goodmis.org> | 2008-10-01 00:29:53 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-10-14 04:39:05 -0400 |
| commit | d769041f865330034131525ee6a7f72eb4af2a24 (patch) | |
| tree | 5c0d93063585c9a94d3c8e8105cc7ad27f4fe0e8 /kernel/trace | |
| parent | 70255b5e3f1bd1a5af5b1e425ec2c4db7c735112 (diff) | |
ring_buffer: implement new locking
The old "lock always" scheme had issues with lockdep, and was not very
efficient anyways.
This patch does a new design to be partially lockless on writes.
Writes will add new entries to the per cpu pages by simply disabling
interrupts. When a write needs to go to another page than it will
grab the lock.
A new "read page" has been added so that the reader can pull out a page
from the ring buffer to read without worrying about the writer writing over
it. This allows us to not take the lock for all reads. The lock is
now only taken when a read needs to go to a new page.
This is far from lockless, and interrupts still need to be disabled,
but it is a step towards a more lockless solution, and it also
solves a lot of the issues that were noticed by the first conversion
of ftrace to the ring buffers.
Note: the ring_buffer_{un}lock API has been removed.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/ring_buffer.c | 298 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 113 |
2 files changed, 247 insertions, 164 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 8e7392fd0db9..9631abf2ae29 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
| @@ -161,8 +161,10 @@ struct ring_buffer_per_cpu { | |||
| 161 | struct list_head pages; | 161 | struct list_head pages; |
| 162 | unsigned long head; /* read from head */ | 162 | unsigned long head; /* read from head */ |
| 163 | unsigned long tail; /* write to tail */ | 163 | unsigned long tail; /* write to tail */ |
| 164 | unsigned long reader; | ||
| 164 | struct buffer_page *head_page; | 165 | struct buffer_page *head_page; |
| 165 | struct buffer_page *tail_page; | 166 | struct buffer_page *tail_page; |
| 167 | struct buffer_page *reader_page; | ||
| 166 | unsigned long overrun; | 168 | unsigned long overrun; |
| 167 | unsigned long entries; | 169 | unsigned long entries; |
| 168 | u64 write_stamp; | 170 | u64 write_stamp; |
| @@ -260,6 +262,7 @@ static struct ring_buffer_per_cpu * | |||
| 260 | rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) | 262 | rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) |
| 261 | { | 263 | { |
| 262 | struct ring_buffer_per_cpu *cpu_buffer; | 264 | struct ring_buffer_per_cpu *cpu_buffer; |
| 265 | unsigned long addr; | ||
| 263 | int ret; | 266 | int ret; |
| 264 | 267 | ||
| 265 | cpu_buffer = kzalloc_node(ALIGN(sizeof(*cpu_buffer), cache_line_size()), | 268 | cpu_buffer = kzalloc_node(ALIGN(sizeof(*cpu_buffer), cache_line_size()), |
| @@ -272,9 +275,16 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) | |||
| 272 | spin_lock_init(&cpu_buffer->lock); | 275 | spin_lock_init(&cpu_buffer->lock); |
| 273 | INIT_LIST_HEAD(&cpu_buffer->pages); | 276 | INIT_LIST_HEAD(&cpu_buffer->pages); |
| 274 | 277 | ||
| 278 | addr = __get_free_page(GFP_KERNEL); | ||
| 279 | if (!addr) | ||
| 280 | goto fail_free_buffer; | ||
| 281 | cpu_buffer->reader_page = (struct buffer_page *)virt_to_page(addr); | ||
| 282 | INIT_LIST_HEAD(&cpu_buffer->reader_page->list); | ||
| 283 | cpu_buffer->reader_page->size = 0; | ||
| 284 | |||
| 275 | ret = rb_allocate_pages(cpu_buffer, buffer->pages); | 285 | ret = rb_allocate_pages(cpu_buffer, buffer->pages); |
| 276 | if (ret < 0) | 286 | if (ret < 0) |
| 277 | goto fail_free_buffer; | 287 | goto fail_free_reader; |
| 278 | 288 | ||
| 279 | cpu_buffer->head_page | 289 | cpu_buffer->head_page |
| 280 | = list_entry(cpu_buffer->pages.next, struct buffer_page, list); | 290 | = list_entry(cpu_buffer->pages.next, struct buffer_page, list); |
| @@ -283,6 +293,9 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) | |||
| 283 | 293 | ||
| 284 | return cpu_buffer; | 294 | return cpu_buffer; |
| 285 | 295 | ||
| 296 | fail_free_reader: | ||
| 297 | free_buffer_page(cpu_buffer->reader_page); | ||
| 298 | |||
| 286 | fail_free_buffer: | 299 | fail_free_buffer: |
| 287 | kfree(cpu_buffer); | 300 | kfree(cpu_buffer); |
| 288 | return NULL; | 301 | return NULL; |
| @@ -293,6 +306,9 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer) | |||
| 293 | struct list_head *head = &cpu_buffer->pages; | 306 | struct list_head *head = &cpu_buffer->pages; |
| 294 | struct buffer_page *page, *tmp; | 307 | struct buffer_page *page, *tmp; |
| 295 | 308 | ||
| 309 | list_del_init(&cpu_buffer->reader_page->list); | ||
| 310 | free_buffer_page(cpu_buffer->reader_page); | ||
| 311 | |||
| 296 | list_for_each_entry_safe(page, tmp, head, list) { | 312 | list_for_each_entry_safe(page, tmp, head, list) { |
| 297 | list_del_init(&page->list); | 313 | list_del_init(&page->list); |
| 298 | free_buffer_page(page); | 314 | free_buffer_page(page); |
| @@ -538,8 +554,10 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size) | |||
| 538 | 554 | ||
| 539 | static inline int rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer) | 555 | static inline int rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer) |
| 540 | { | 556 | { |
| 541 | return cpu_buffer->head_page == cpu_buffer->tail_page && | 557 | return (cpu_buffer->reader == cpu_buffer->reader_page->size && |
| 542 | cpu_buffer->head == cpu_buffer->tail; | 558 | (cpu_buffer->tail_page == cpu_buffer->reader_page || |
| 559 | (cpu_buffer->tail_page == cpu_buffer->head_page && | ||
| 560 | cpu_buffer->head == cpu_buffer->tail))); | ||
| 543 | } | 561 | } |
| 544 | 562 | ||
| 545 | static inline int rb_null_event(struct ring_buffer_event *event) | 563 | static inline int rb_null_event(struct ring_buffer_event *event) |
| @@ -555,10 +573,10 @@ static inline void *rb_page_index(struct buffer_page *page, unsigned index) | |||
| 555 | } | 573 | } |
| 556 | 574 | ||
| 557 | static inline struct ring_buffer_event * | 575 | static inline struct ring_buffer_event * |
| 558 | rb_head_event(struct ring_buffer_per_cpu *cpu_buffer) | 576 | rb_reader_event(struct ring_buffer_per_cpu *cpu_buffer) |
| 559 | { | 577 | { |
| 560 | return rb_page_index(cpu_buffer->head_page, | 578 | return rb_page_index(cpu_buffer->reader_page, |
| 561 | cpu_buffer->head); | 579 | cpu_buffer->reader); |
| 562 | } | 580 | } |
| 563 | 581 | ||
| 564 | static inline struct ring_buffer_event * | 582 | static inline struct ring_buffer_event * |
| @@ -610,15 +628,32 @@ rb_add_stamp(struct ring_buffer_per_cpu *cpu_buffer, u64 *ts) | |||
| 610 | cpu_buffer->write_stamp = *ts; | 628 | cpu_buffer->write_stamp = *ts; |
| 611 | } | 629 | } |
| 612 | 630 | ||
| 613 | static void rb_reset_read_page(struct ring_buffer_per_cpu *cpu_buffer) | 631 | static void rb_reset_head_page(struct ring_buffer_per_cpu *cpu_buffer) |
| 614 | { | 632 | { |
| 615 | cpu_buffer->read_stamp = cpu_buffer->head_page->time_stamp; | ||
| 616 | cpu_buffer->head = 0; | 633 | cpu_buffer->head = 0; |
| 617 | } | 634 | } |
| 618 | 635 | ||
| 619 | static void | 636 | static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer) |
| 620 | rb_reset_iter_read_page(struct ring_buffer_iter *iter) | ||
| 621 | { | 637 | { |
| 638 | cpu_buffer->read_stamp = cpu_buffer->reader_page->time_stamp; | ||
| 639 | cpu_buffer->reader = 0; | ||
| 640 | } | ||
| 641 | |||
| 642 | static inline void rb_inc_iter(struct ring_buffer_iter *iter) | ||
| 643 | { | ||
| 644 | struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer; | ||
| 645 | |||
| 646 | /* | ||
| 647 | * The iterator could be on the reader page (it starts there). | ||
| 648 | * But the head could have moved, since the reader was | ||
| 649 | * found. Check for this case and assign the iterator | ||
| 650 | * to the head page instead of next. | ||
| 651 | */ | ||
| 652 | if (iter->head_page == cpu_buffer->reader_page) | ||
| 653 | iter->head_page = cpu_buffer->head_page; | ||
| 654 | else | ||
| 655 | rb_inc_page(cpu_buffer, &iter->head_page); | ||
| 656 | |||
| 622 | iter->read_stamp = iter->head_page->time_stamp; | 657 | iter->read_stamp = iter->head_page->time_stamp; |
| 623 | iter->head = 0; | 658 | iter->head = 0; |
| 624 | } | 659 | } |
| @@ -693,30 +728,39 @@ static struct ring_buffer_event * | |||
| 693 | __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, | 728 | __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, |
| 694 | unsigned type, unsigned long length, u64 *ts) | 729 | unsigned type, unsigned long length, u64 *ts) |
| 695 | { | 730 | { |
| 696 | struct buffer_page *head_page, *tail_page; | 731 | struct buffer_page *tail_page, *head_page, *reader_page; |
| 697 | unsigned long tail; | 732 | unsigned long tail; |
| 698 | struct ring_buffer *buffer = cpu_buffer->buffer; | 733 | struct ring_buffer *buffer = cpu_buffer->buffer; |
| 699 | struct ring_buffer_event *event; | 734 | struct ring_buffer_event *event; |
| 700 | 735 | ||
| 736 | /* No locking needed for tail page */ | ||
| 701 | tail_page = cpu_buffer->tail_page; | 737 | tail_page = cpu_buffer->tail_page; |
| 702 | head_page = cpu_buffer->head_page; | ||
| 703 | tail = cpu_buffer->tail; | 738 | tail = cpu_buffer->tail; |
| 704 | 739 | ||
| 705 | if (tail + length > BUF_PAGE_SIZE) { | 740 | if (tail + length > BUF_PAGE_SIZE) { |
| 706 | struct buffer_page *next_page = tail_page; | 741 | struct buffer_page *next_page = tail_page; |
| 707 | 742 | ||
| 743 | spin_lock(&cpu_buffer->lock); | ||
| 708 | rb_inc_page(cpu_buffer, &next_page); | 744 | rb_inc_page(cpu_buffer, &next_page); |
| 709 | 745 | ||
| 746 | head_page = cpu_buffer->head_page; | ||
| 747 | reader_page = cpu_buffer->reader_page; | ||
| 748 | |||
| 749 | /* we grabbed the lock before incrementing */ | ||
| 750 | WARN_ON(next_page == reader_page); | ||
| 751 | |||
| 710 | if (next_page == head_page) { | 752 | if (next_page == head_page) { |
| 711 | if (!(buffer->flags & RB_FL_OVERWRITE)) | 753 | if (!(buffer->flags & RB_FL_OVERWRITE)) { |
| 754 | spin_unlock(&cpu_buffer->lock); | ||
| 712 | return NULL; | ||
