ring-buffer: fix uninitialized read_stamp
Subsystems (2)
PATCH 1/1 ring-buffer: fix uninitialized read_stamp
This fixes a scenario in which trace_pipe_raw will return events with invalid timestamps when events are copied out one at a time (instead of swapping out the reader page with a spare page). In this scenario, ring_buffer_read_page() uses cpu_buffer->read_stamp to keep track of the time of the earliest event. However, cpu_buffer->read_stamp was not always updated. The only function that sets read_stamp to a new valid value is rb_reset_reader_page(), which is called only by rb_get_reader_page(). rb_reset_reader_page() was not called when there is data immediately available on the page to read (read < rb_page_size()). This is the bug.
Setting the read_stamp on the first read from a page fixes the bug.
Tested: On certain lightly-loaded machines, repetitive reads from trace_pipe_raw without using splice() would sometimes result in invalid timestamps. Poisoning read_stamp in rb_init_page() with a negative value makes the problem more visible. After this fix, the invalid timstamps disappear.
Google-Bug-Id: 6410455
--- kernel/trace/ring_buffer.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
kernel/trace/ring_buffer.c +8 -1
@@ -3226,8 +3226,15 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) reader = cpu_buffer->reader_page;/* If there's more to read, return this page */ -if (cpu_buffer->reader_page->read <rb_page_size (reader)) +if (cpu_buffer->reader_page->read <rb_page_size (reader)) { +/* +* If this is the first read from this page, +* initialize the read timestamp. +*/ +if (cpu_buffer->reader_page->read ==0 ) + cpu_buffer->read_stamp = reader->page->time_stamp; goto out; + }/* Never should we have an index greater than the size */ if (RB_WARN_ON(cpu_buffer,
Signature · 1 line
1.7.7.3
Quoted 10 lines · David Sharp
This fixes a scenario in which
trace_pipe_rawwill return events with invalid timestamps when events are copied out one at a time (instead of swapping out the reader page with a spare page). In this scenario,ring_buffer_read_page()usescpu_buffer->read_stampto keep track of the time of the earliest event. However,cpu_buffer->read_stampwas not always updated. The only function that setsread_stampto a new valid value isrb_reset_reader_page(), which is called only byrb_get_reader_page().rb_reset_reader_page()was not called when there is data immediately available on the page to read (read <rb_page_size()). This is the bug.
Quoted 6 lines
Setting the
read_stampon the first read from a page fixes the bug.Tested: On certain lightly-loaded machines, repetitive reads from
trace_pipe_rawwithout usingsplice()would sometimes result in invalid timestamps. Poisoningread_stampinrb_init_page()with a negative value makes the problem more visible. After this fix, the invalid timstamps disappear.
err, that's poisoning the bpage->time_stamp, not read_stamp.
Quoted 3 lines
Google-Bug-Id: 6410455
Signed-off-by David Sharp <[email protected]>
PATCH 1/1 ring-buffer: fix uninitialized read_stamp
This fixes a scenario in which trace_pipe_raw will return events with invalid timestamps when events are copied out one at a time (instead of swapping out the reader page with a spare page). In this scenario, ring_buffer_read_page() uses cpu_buffer->read_stamp to keep track of the time of the earliest event. However, cpu_buffer->read_stamp was not always updated. The only function that sets read_stamp to a new valid value is rb_reset_reader_page(), which is called only by rb_get_reader_page(). rb_reset_reader_page() was not called when there is data immediately available on the page to read (read < rb_page_size()). This is the bug.
Setting the read_stamp on the first read from a page fixes the bug.
Tested: On certain lightly-loaded machines, repetitive reads from trace_pipe_raw without using splice() would sometimes result in invalid timestamps. Poisoning bpage->timestamp in rb_init_page() with a negative value makes the problem more visible. After this fix, the invalid timstamps disappear.
Google-Bug-Id: 6410455
---
Steve, did you see this? It fixes a data-accuracy bug in ftrace. Also taking this reminder as an opportunity to correct that typo in the description.
kernel/trace/ring_buffer.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
kernel/trace/ring_buffer.c +8 -1
@@ -3226,8 +3226,15 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) reader = cpu_buffer->reader_page;/* If there's more to read, return this page */ -if (cpu_buffer->reader_page->read <rb_page_size (reader)) +if (cpu_buffer->reader_page->read <rb_page_size (reader)) { +/* +* If this is the first read from this page, +* initialize the read timestamp. +*/ +if (cpu_buffer->reader_page->read ==0 ) + cpu_buffer->read_stamp = reader->page->time_stamp; goto out; + }/* Never should we have an index greater than the size */ if (RB_WARN_ON(cpu_buffer,
Signature · 1 line
1.7.7.3
Steven Rostedt
maintainerQuoted 9 lines · David Sharp
This fixes a scenario in which
trace_pipe_rawwill return events with invalid timestamps when events are copied out one at a time (instead of swapping out the reader page with a spare page). In this scenario,ring_buffer_read_page()usescpu_buffer->read_stampto keep track of the time of the earliest event. However,cpu_buffer->read_stampwas not always updated. The only function that setsread_stampto a new valid value isrb_reset_reader_page(), which is called only byrb_get_reader_page().rb_reset_reader_page()was not called when there is data immediately available on the page to read (read <rb_page_size()). This is the bug.
Hi David,
Thanks for the reminder, I'll be looking at it today.
Do you believe that this is an urgent fix and should be marked for stable, or do you think it can wait till 3.6? If you think it should be marked for stable, then it should be pushed for 3.5.
-- Steve
Steven Rostedt
maintainerOK, I did look at this more.
Quoted 11 lines · David Sharp
This fixes a scenario in which
trace_pipe_rawwill return events with invalid timestamps when events are copied out one at a time (instead of swapping out the reader page with a spare page). In this scenario,ring_buffer_read_page()usescpu_buffer->read_stampto keep track of the time of the earliest event. However,cpu_buffer->read_stampwas not always updated.The only function that
setsread_stampto a new valid value isrb_reset_reader_page(), which is called only byrb_get_reader_page().
Correct, which is the only way to get the reader page no matter how you read the buffer.
Quoted 3 lines
rb_reset_reader_page()was not called when there
is data immediately available on the page to read (read <rb_page_size()). This is the bug.
It is not called? but how did you get the reader_page without the swap in the first place?
When the ring buffer is first allocated the reader page is set to a zero'd page, making the "read" and "commit" both zero.
The first time rb_get_reader_page() is called, the compare of read < rb_page_size() (which is the commit field) fails (0 < 0 is false).
A swap from the writable ring buffer takes place and the cpu_buffer->read_stamp is updated.
Ah! I think this is where the bug you see happens. But your analysis is flawed.
If the ring buffer is currently empty, we swap an empty page for an empty page. But the writer ends up on the reader page preventing new swaps from taking place.
commit_page == reader_page
If the writer starts writing, it will update the time stamp of the page. If your next read happens now, and it's just a single read, then you are correct that it will not update the read_stamp.
I'm wondering if it would be better to just not do the swap, and return NULL when it is empty. This would also fix the problem, as the read_stamp will only be set when you actually have data.
Or it may just be simpler to take your patch.
-- Steve
Steven Rostedt
maintainerQuoted 3 lines · Steven Rostedt
I'm wondering if it would be better to just not do the swap, and return NULL when it is empty. This would also fix the problem, as the
read_stampwill only be set when you actually have data.
Does something like this work for you. Note, this is totally untested!
-- Steve
kernel/trace/ring_buffer.c +4 -0
@@ -3246,6 +3246,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)if (cpu_buffer->commit_page == cpu_buffer->reader_page) goto out; +/* Don't bother swapping if the ring buffer is empty */ +if (rb_num_of_entries (cpu_buffer) ==0 ) + goto out; +/* * Reset the reader page to size zero. */
Quoted 3 lines · Steven Rostedt
Do you believe that this is an urgent fix and should be marked for stable, or do you think it can wait till 3.6? If you think it should be marked for stable, then it should be pushed for 3.5.
I think it should be considered for 3.5, since it affects the accuracy of the timestamps in very roughly 20% of traces read with read() on trace_pipe_raw. otoh, it only affects the first page or so on lightly loaded CPUs. Personally it doesn't make much difference to us what release it gets into.
Quoted 6 lines · Steven Rostedt
OK, I did look at this more.
Quoted 3 lines
The only function that
setsread_stampto a new valid value isrb_reset_reader_page(), which is called only byrb_get_reader_page().
Quoted 8 lines
Correct, which is the only way to get the reader page no matter how you read the buffer.
Quoted 3 lines
rb_reset_reader_page() was not called when there
is data immediately available on the page to read (read <rb_page_size()). This is the bug.It is not called?
Correct. I was able to add WARN_ONs that showed that it reached "out:" without reaching rb_reset_reader_page() first while still having a poison value in cpu_buffer->read_stamp.
Quoted 6 lines
but how did you get the
reader_pagewithout the swap in the first place?When the ring buffer is first allocated the reader page is set to a zero'd page, making the "read" and "commit" both zero.
Quoted 8 lines
The first time
rb_get_reader_page()is called, the compare of read <rb_page_size()(which is the commit field) fails (0 < 0 is false).A swap from the writable ring buffer takes place and the
cpu_buffer->read_stampis updated.Ah! I think this is where the bug you see happens. But your analysis is flawed.
I admit I didn't look into it that closely, so flaws are quite possible (also, I'm human).
Quoted 7 lines
If the ring buffer is currently empty, we swap an empty page for an empty page. But the writer ends up on the reader page preventing new swaps from taking place.
commit_page ==
reader_page
Quoted 7 lines
If the writer starts writing, it will update the time stamp of the page. If your next read happens now, and it's just a single read, then you are correct that it will not update the
read_stamp.I'm wondering if it would be better to just not do the swap, and return NULL when it is empty. This would also fix the problem, as the
read_stampwill only be set when you actually have data.
But we do have data... That's how we know we're getting invalid timestamps.
I don't quite understand what you're describing. Here's what I think is happening though:
When the ring buffer is reset, commit_page == tail_page == head_page. rb_get_reader_page() will pick up the head page. Then a few (less than 1 page worth) writes happen, on the tail_page which is currently (or soon to be) also the reader_page. Now read == 0, but rb_page_size(reader) is however many bytes have been written to the page.
So we have valid data on the reader page, but read_stamp has not been set yet.
Quoted 2 lines
Or it may just be simpler to take your patch.
Please? :)
kernel/trace/ring_buffer.c rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) · line 3249
Quoted 13 lines · Steven Rostedt
Does something like this work for you. Note, this is totally untested!
-- Steve
kernel/trace/ring_buffer.c +1
-0@@ -3246,6 +3246,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) if (cpu_buffer->commit_page == cpu_buffer->reader_page) goto out; + /* Don't bother swapping if the ring buffer is empty */
This doesn't make sense, since the ring buffer isn't empty in this scenario. (I didn't bother testing it.)
kernel/trace/ring_buffer.c rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) · line 3250
Quoted 1 line
kernel/trace/ring_buffer.c +1
-0+ if (rb_num_of_entries(cpu_buffer) == 0)
Did you mean rb_page_entries(something?)
Quoted 7 lines
kernel/trace/ring_buffer.c +2
-0+ goto out; + /** Reset the reader page to size zero. */
Steven Rostedt
maintainerQuoted 10 lines · David Sharp
Quoted 3 lines · Steven Rostedt
Do you believe that this is an urgent fix and should be marked for stable, or do you think it can wait till 3.6? If you think it should be marked for stable, then it should be pushed for 3.5.
I think it should be considered for 3.5, since it affects the accuracy of the timestamps in very roughly 20% of traces read with
read()ontrace_pipe_raw. otoh, it only affects the first page or so on lightly loaded CPUs. Personally it doesn't make much difference to us what release it gets into.
If there's a simple fix then I can try to get this into 3.5.
Quoted 15 lines · Steven Rostedt
Quoted 13 lines
OK, I did look at this more.
Quoted 3 lines
The only function that
setsread_stampto a new valid value isrb_reset_reader_page(), which is called only byrb_get_reader_page().Correct, which is the only way to get the reader page no matter how you read the buffer.
Quoted 3 lines
rb_reset_reader_page()was not called when there
is data immediately available on the page to read (read <rb_page_size()). This is the bug.
Quoted 5 lines
Quoted 1 line
It is not called?
Correct. I was able to add
WARN_ONsthat showed that it reached "out:" without reachingrb_reset_reader_page()first while still having a poison value incpu_buffer->read_stamp.
NO! You didn't understand what I wrote. The writer can not get onto the reader page without a swap! The reader page is not part of the main ring buffer.
Quoted 10 lines
Quoted 10 lines
but how did you get the
reader_pagewithout the swap in the first place?When the ring buffer is first allocated the reader page is set to a zero'd page, making the "read" and "commit" both zero.
The first time
rb_get_reader_page()is called, the compare of read <rb_page_size()(which is the commit field) fails (0 < 0 is false).
Quoted 8 lines
Quoted 5 lines
A swap from the writable ring buffer takes place and the
cpu_buffer->read_stampis updated.Ah! I think this is where the bug you see happens. But your analysis is flawed.
I admit I didn't look into it that closely, so flaws are quite possible (also, I'm human).
I didn't mean to offend, as this is not something that can be easily picked up.
Quoted 12 lines
Quoted 12 lines
If the ring buffer is currently empty, we swap an empty page for an empty page. But the writer ends up on the reader page preventing new swaps from taking place.
commit_page == reader_pageIf the writer starts writing, it will update the time stamp of the page. If your next read happens now, and it's just a single read, then you are correct that it will not update the
read_stamp.
Quoted 5 lines
Quoted 3 lines
I'm wondering if it would be better to just not do the swap, and return NULL when it is empty. This would also fix the problem, as the
read_stampwill only be set when you actually have data.But we do have data... That's how we know we're getting invalid timestamps.
I bet this never happens if you add a little data and then do a read. I only happens when you read from an empty ring buffer, then do a small write, and then read again. That's where it will get you.
Quoted 5 lines
I don't quite understand what you're describing. Here's what I think is happening though:
When the ring buffer is reset,
commit_page==tail_page==head_page.
And at this moment, the writer is off the reader page and will not be on the reader page. The only way to get date at this point is if you do a swap.
Quoted 1 line
rb_get_reader_page()will pick up the head page.
Right. But this requires a read to happen. If you never do a read, then rb_get_reader_page will not pick up the head page. The problem is when you read from an empty ring buffer.
Quoted 5 lines
Then a few (less than
1 page worth) writes happen, on thetail_pagewhich is currently (or soon to be) also thereader_page. Now read == 0, butrb_page_size(reader)is however many bytes have been written to the page.
Correct.
Quoted 2 lines
So we have valid data on the reader page, but
read_stamphas not been set yet.
Yep
Quoted 5 lines
Quoted 3 lines
Or it may just be simpler to take your patch.
Please? :)
Now I think you may understand my patch.
Quoted 14 lines · Steven Rostedt
Quoted 12 lines
Does something like this work for you. Note, this is totally untested!
-- Steve
kernel/trace/ring_buffer.c +0
-0@@ -3246,6 +3246,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)if (cpu_buffer->commit_page == cpu_buffer->reader_page) goto out;
Quoted 4 lines
kernel/trace/ring_buffer.c rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) · line 3249
Quoted 1 line
kernel/trace/ring_buffer.c +1
-0+/* Don't bother swapping if the ring buffer is empty */ This doesn't make sense, since the ring buffer isn't empty in this scenario. (I didn't bother testing it.)
Yes it is! If you never did a read on the empty buffer, the *only* way to get what was written is to do the swap.
The problem you are seeing is that you did a read on an empty buffer before writing. In this case the swap happens but all we have is an empty page with the write pointer (commit and tail) on it. When a write happens, and you do another read, *then* we do not do the swap and you get the stale time stamp.
Thus, if you never let the first swap happen, you wont get into this scenario that you read and do not update the read_stamp.
Quoted 4 lines
kernel/trace/ring_buffer.c rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) · line 3250
Quoted 2 lines
kernel/trace/ring_buffer.c +1
-0+if (rb_num_of_entries (cpu_buffer) ==0 )Did you mean
rb_page_entries(something?)
Nope, I meant the actual ring buffer. If the ring buffer is empty, do not perform the swap. Because we only update the read stamp when we perform a swap, and it takes a write to happen before the page's timestamp is updated. If we do the swap before any writes happen, we get an invalid timestamp from the page.
Now do you understand?
-- Steve
Quoted 8 lines
Quoted 8 lines
kernel/trace/ring_buffer.c +2
-0+ goto out; +/* * Reset the reader page to size zero. */
Quoted 18 lines · Steven Rostedt
Quoted 16 lines · David Sharp
Quoted 14 lines · Steven Rostedt
OK, I did look at this more.
Quoted 3 lines
The only function that
setsread_stampto a new valid value isrb_reset_reader_page(), which is called only byrb_get_reader_page().Correct, which is the only way to get the reader page no matter how you read the buffer.
Quoted 3 lines
rb_reset_reader_page() was not called when there
is data immediately available on the page to read (read <rb_page_size()). This is the bug.It is not called?
Quoted 7 lines
Quoted 3 lines
Correct. I was able to add
WARN_ONsthat showed that it reached "out:" without reachingrb_reset_reader_page()first while still having a poison value incpu_buffer->read_stamp.NO! You didn't understand what I wrote. The writer can not get onto the reader page without a swap! The reader page is not part of the main ring buffer.
I understand that. I just thought the writer was getting onto the reader page during a swap in the first read, the same read in which we were getting invalid timestamps. But that doesn't make sense.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Ah! I think this is where the bug you see happens. But your analysis is flawed.
I admit I didn't look into it that closely, so flaws are quite possible (also, I'm human).
I didn't mean to offend, as this is not something that can be easily picked up.
None taken. I only meant I wasn't as rigorous as I could have been.
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
If the ring buffer is currently empty, we swap an empty page for an empty page. But the writer ends up on the reader page preventing new swaps from taking place.
commit_page ==
reader_pageIf the writer starts writing, it will update the time stamp of the page. If your next read happens now, and it's just a single read, then you are correct that it will not update the
read_stamp.I'm wondering if it would be better to just not do the swap, and return NULL when it is empty. This would also fix the problem, as the
read_stampwill only be set when you actually have data.
Quoted 5 lines
Quoted 1 line
But we do have data... That's how we know we're getting invalid timestamps.
I bet this never happens if you add a little data and then do a read. I only happens when you read from an empty ring buffer, then do a small write, and then read again. That's where it will get you.
Ah, see what you mean now. That seems possible.
Quoted 33 lines
Quoted 6 lines
I don't quite understand what you're describing. Here's what I think is happening though:
When the ring buffer is reset,
commit_page==tail_page==head_page.And at this moment, the writer is off the reader page and will not be on the reader page. The only way to get date at this point is if you do a swap.
Quoted 1 line
rb_get_reader_page()will pick up the head page.Right. But this requires a read to happen. If you never do a read, then
rb_get_reader_pagewill not pick up the head page. The problem is when you read from an empty ring buffer.Quoted 5 lines
Then a few (less than
1 page worth) writes happen, on thetail_pagewhich is currently (or soon to be) also thereader_page. Now read == 0, butrb_page_size(reader)is however many bytes have been written to the page.Correct.
Quoted 2 lines
So we have valid data on the reader page, but
read_stamphas not been set yet.Yep
Quoted 2 lines
Quoted 2 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Or it may just be simpler to take your patch.
Please? :)
Now I think you may understand my patch.
Yeah, mostly. At least enough that I think it's worth testing. But Monday.
Quoted 33 lines
Quoted 13 lines · Steven Rostedt
Quoted 12 lines
Does something like this work for you. Note, this is totally untested!
-- Steve
kernel/trace/ring_buffer.c +0
-0@@ -3246,6 +3246,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) if (cpu_buffer->commit_page == cpu_buffer->reader_page) goto out;Quoted 4 lines
kernel/trace/ring_buffer.c rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) · line 3249
Quoted 1 line
kernel/trace/ring_buffer.c +1
-0+ /* Don't bother swapping if the ring buffer is empty */This doesn't make sense, since the ring buffer isn't empty in this scenario. (I didn't bother testing it.)
Yes it is! If you never did a read on the empty buffer, the *only* way to get what was written is to do the swap.
The problem you are seeing is that you did a read on an empty buffer before writing. In this case the swap happens but all we have is an empty page with the write pointer (commit and tail) on it. When a write happens, and you do another read, *then* we do not do the swap and you get the stale time stamp.
Thus, if you never let the first swap happen, you wont get into this scenario that you read and do not update the
read_stamp.Quoted 3 lines
Quoted 2 lines
kernel/trace/ring_buffer.c +1
-0+ if (rb_num_of_entries(cpu_buffer) == 0)
Quoted 7 lines
Quoted 1 line
Did you mean
rb_page_entries(something?)Nope, I meant the actual ring buffer. If the ring buffer is empty, do not perform the swap. Because we only update the read stamp when we perform a swap, and it takes a write to happen before the page's timestamp is updated. If we do the swap before any writes happen, we get an invalid timestamp from the page.
Oops, I only asked because I'm blind, or can't type, or something, because I couldn't find rb_num_of_entries().
Quoted 15 lines
Now do you understand?
-- Steve
Quoted 8 lines
Quoted 8 lines
kernel/trace/ring_buffer.c +2
-0+ goto out; + /** Reset the reader page to size zero. */
Quoted 5 lines · David Sharp
Quoted 2 lines · Steven Rostedt
Now I think you may understand my patch.
Yeah, mostly. At least enough that I think it's worth testing. But Monday.
I got around to testing your patch today, and it fixes the issue. No bad-looking timestamps in 40 runs, whereas could reproduce within 3 runs before. Do you want me to send you a fresh patch, or just use the one you have?
Quoted 20 lines
Quoted 20 lines
Quoted 20 lines · Steven Rostedt
Quoted 19 lines
Does something like this work for you. Note, this is totally untested!
-- Steve
kernel/trace/ring_buffer.c +4
-0@@ -3246,6 +3246,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) if (cpu_buffer->commit_page == cpu_buffer->reader_page) goto out; + /* Don't bother swapping if the ring buffer is empty */ + if (rb_num_of_entries(cpu_buffer) == 0) + goto out; + /** Reset the reader page to size zero. */
Steven Rostedt
maintainerQuoted 11 lines · David Sharp
Quoted 5 lines · David Sharp
Quoted 2 lines · Steven Rostedt
Now I think you may understand my patch.
Yeah, mostly. At least enough that I think it's worth testing. But Monday.
I got around to testing your patch today, and it fixes the issue. No bad-looking timestamps in 40 runs, whereas could reproduce within 3 runs before. Do you want me to send you a fresh patch, or just use the one you have?
I rather use this one for two reasons.
1) it limits the places where read_stamp is updated. And I rather not add an update because "it fixes an anomaly".
2) I think it is wrong to force the writer on the reader page when no write has been made. There's some side effects that this causes. One is that if you do a read with no write, and then do nothing, it forces the writer on that page. Now if a lot of writes happen (function tracing), the writes that were on the reader page are never overwritten when the buffer is full. Then you get a page of very old data, followed by a buffer full of new data.
-- Steve
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines · Steven Rostedt
Quoted 19 lines
Does something like this work for you. Note, this is totally untested!
-- Steve
kernel/trace/ring_buffer.c +4
-0@@ -3246,6 +3246,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)if (cpu_buffer->commit_page == cpu_buffer->reader_page) goto out; +/* Don't bother swapping if the ring buffer is empty */ +if (rb_num_of_entries (cpu_buffer) ==0 ) + goto out; +/* * Reset the reader page to size zero. */
Quoted 6 lines · Steven Rostedt
Quoted 5 lines · David Sharp
Quoted 4 lines · David Sharp
Quoted 2 lines · Steven Rostedt
Now I think you may understand my patch.
Quoted 8 lines
Quoted 6 lines
Quoted 1 line
Yeah, mostly. At least enough that I think it's worth testing. But Monday.
I got around to testing your patch today, and it fixes the issue. No bad-looking timestamps in 40 runs, whereas could reproduce within 3 runs before. Do you want me to send you a fresh patch, or just use the one you have?
I rather use this one for two reasons.
I just meant, do you want me to send you a version of your patch with my description (I'll update it, obviously), or do it yourself.
Quoted 11 lines
1) it limits the places where
read_stampis updated. And I rather not add an update because "it fixes an anomaly".2) I think it is wrong to force the writer on the reader page when no write has been made. There's some side effects that this causes. One is that if you do a read with no write, and then do nothing, it forces the writer on that page. Now if a lot of writes happen (function tracing), the writes that were on the reader page are never overwritten when the buffer is full. Then you get a page of very old data, followed by a buffer full of new data.
I have always disliked that page of very old data, so I'm really happy that this will get rid of it. As I recall, you once claimed this was a "feature". :)
Steven Rostedt
maintainerQuoted 2 lines · David Sharp
I just meant, do you want me to send you a version of your patch with my description (I'll update it, obviously), or do it yourself.
I'll do it. Although, I think this may just go for 3.6 and not 3.5, as the bug is really minor.
Quoted 3 lines
I have always disliked that page of very old data, so I'm really happy that this will get rid of it. As I recall, you once claimed this was a "feature". :)
Of course it was a feature. But we'll just act like Gnome and remove it ;-)
-- Steve
[tip:perf/core] ring-buffer: Fix uninitialized read_stamp
In reply to David SharpCommit-ID: a5fb833172eca69136e9ee1ada778e404086ab8a Gitweb: http://git.kernel.org/tip/a5fb833172eca69136e9ee1ada778e404086ab8a Author: Steven Rostedt <[email protected]> AuthorDate: Thu, 28 Jun 2012 13:35:04 -0400 Committer: Steven Rostedt <[email protected]> CommitDate: Thu, 28 Jun 2012 13:52:15 -0400
ring-buffer: Fix uninitialized read_stamp
The ring buffer reader page is used to swap a page from the writable ring buffer. If the writer happens to be on that page, it ends up on the reader page, but will simply move off of it, back into the writable ring buffer as writes are added.
The time stamp passed back to the readers is stored in the cpu_buffer per CPU descriptor. This stamp is updated when a swap of the reader page takes place, and it reads the current stamp from the page taken from the writable ring buffer. Everytime a writer goes to a new page, it updates the time stamp of that page.
The problem happens if a reader reads a page from an empty per CPU ring buffer. If the buffer is empty, the swap still takes place, placing the writer at the start of the reader page. If at a later time, a write happens, it updates the page's time stamp and continues. But the problem is that the read_stamp does not get updated, because the page was already swapped.
The solution to this was to not swap the page if the ring buffer happens to be empty. This also removes the side effect that the writes on the reader page will not get updated because the writer never gets back on the reader page without a swap. That is, if a read happens on an empty buffer, but then no reads happen for a while. If a swap took place, and the writer were to start writing a lot of data (function tracer), it will start overflowing the ring buffer and overwrite the older data. But because the writer never goes back onto the reader page, the data left on the reader page never gets overwritten. This causes the reader to see really old data, followed by a jump to newer data.
Google-Bug-Id: 6410455
--- kernel/trace/ring_buffer.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
kernel/trace/ring_buffer.c +4 -0
@@ -3239,6 +3239,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)if (cpu_buffer->commit_page == cpu_buffer->reader_page) goto out; +/* Don't bother swapping if the ring buffer is empty */ +if (rb_num_of_entries (cpu_buffer) ==0 ) + goto out; +/* * Reset the reader page to size zero. */
[tip:perf/urgent] ring-buffer: Fix uninitialized read_stamp
In reply to David SharpCommit-ID: 01c4359c155e2613cb29363865804c2b11092d6f Gitweb: http://git.kernel.org/tip/01c4359c155e2613cb29363865804c2b11092d6f Author: Steven Rostedt <[email protected]> AuthorDate: Thu, 28 Jun 2012 13:35:04 -0400 Committer: Ingo Molnar <[email protected]> CommitDate: Fri, 6 Jul 2012 11:13:22 +0200
ring-buffer: Fix uninitialized read_stamp
The ring buffer reader page is used to swap a page from the writable ring buffer. If the writer happens to be on that page, it ends up on the reader page, but will simply move off of it, back into the writable ring buffer as writes are added.
The time stamp passed back to the readers is stored in the cpu_buffer per CPU descriptor. This stamp is updated when a swap of the reader page takes place, and it reads the current stamp from the page taken from the writable ring buffer. Everytime a writer goes to a new page, it updates the time stamp of that page.
The problem happens if a reader reads a page from an empty per CPU ring buffer. If the buffer is empty, the swap still takes place, placing the writer at the start of the reader page. If at a later time, a write happens, it updates the page's time stamp and continues. But the problem is that the read_stamp does not get updated, because the page was already swapped.
The solution to this was to not swap the page if the ring buffer happens to be empty. This also removes the side effect that the writes on the reader page will not get updated because the writer never gets back on the reader page without a swap. That is, if a read happens on an empty buffer, but then no reads happen for a while. If a swap took place, and the writer were to start writing a lot of data (function tracer), it will start overflowing the ring buffer and overwrite the older data. But because the writer never goes back onto the reader page, the data left on the reader page never gets overwritten. This causes the reader to see really old data, followed by a jump to newer data.
Google-Bug-Id: 6410455
--- kernel/trace/ring_buffer.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
kernel/trace/ring_buffer.c +4 -0
@@ -3239,6 +3239,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)if (cpu_buffer->commit_page == cpu_buffer->reader_page) goto out; +/* Don't bother swapping if the ring buffer is empty */ +if (rb_num_of_entries (cpu_buffer) ==0 ) + goto out; +/* * Reset the reader page to size zero. */