Re: perf events ring buffer memory barrier on powerpc
From: Peter Zijlstra <peterz@infradead.org>
Date: 2013-10-30 17:44:23
Also in:
lkml
On Wed, Oct 30, 2013 at 07:14:29PM +0200, Victor Kaplansky wrote:
We need a complete rmb() here IMO. I think there is a fundamental difference between load and stores in this aspect. Load are allowed to be hoisted by compiler or executed speculatively by HW. To prevent load "*(ubuf->data + tail)" to be hoisted beyond "ubuf->head" load you would need something like this:
Indeed, we could compute and load ->data + tail the moment we've completed the tail load but before we've completed the head load and done the comparison. So yes, full rmb() it is.
void
ubuf_read(void)
{
u64 head, tail;
tail = ubuf->tail;
head = ACCESS_ONCE(ubuf->head);
/*
* Ensure we read the buffer boundaries before the actual buffer
* data...
*/
while (tail != head) {
smp_read_barrier_depends(); /* for Alpha */
obj = *(ubuf->data + head - 128);
/* process obj */
tail += obj->size;
tail %= ubuf->size;
}
/*
* Ensure all data reads are complete before we issue the
* ubuf->tail update; once that update hits, kbuf_write() can
* observe and overwrite data.
*/
smp_mb(); /* D, matches with A */
ubuf->tail = tail;
}
(note that "head" is part of address calculation of obj load now).Right, explicit dependent loads; I was hoping the conditional in between might be enough, but as argued above it is not. The above cannot work in our case though, we must use tail to find the obj since we have variable size objects.
But, even in this demo example some "smp_read_barrier_depends()" before "obj = *(ubuf->data + head - 100);" is required for architectures like Alpha. Though, on more sane architectures "smp_read_barrier_depends()" will be translated to nothing.
Sure.. I know all about that.