Hi Olivier,
On Oct 20, 2008, at 6:13 AM, Olivier Guilyardi wrote:
Until now, I just couldn't write a test that fail
because of the
lack of memory
barrier on x86. However, I think I found another bug in Jack
ringbuffer, by
writing another test.
It's a bit of a weird test, I call it "bit circle": I start 16
"node" threads.
Each node :
- communicate with its adjacent node through 2 ring buffers
- is responsible for shifting an integer by one bit
- send the shifted result to the next node through a ring buffer
- checks that the value read from previous node is correct.
On my Debian Quad Core and Mac OS X Core Duo boxes, this test fails
with Jack's
ringbuffer even with my patch applied. But it succeeds with
Portaudio (both with
and without memory barriers), and also with Fons' implementation.
I wish someone could eventually run my test suite on a PowerPC,
especially SMP.
The usage is unchanged:
svn co
http://svn.samalyse.com/misc/rbtest
cd rbtest
make test
The run time is now shorter, about 2 minutes. Below is the output.
You can see
that jack (test-bit-circle-jack) fails the bit circle test, even
when patched
(test-bit-circle-jack-fix1). "|" is printed when a node thread
starts, and "-"
when a node has read 1000 values, to ensure data is really flowing.
The test-int-array-* tests are the same as my original test. All *-
lfq tests use
Fons's Lfq ringbuffer (modified to use char instead of uint32_t) as
backend.
./run-tests.sh bit-circle 512 jack jack-fix1 portaudio portaudio-
nobarrier lfq
test-bit-circle-jack - starting (5s max) - buffer size: 512
|| FAILURE: 2 != 514
I thought it suspicious that 514 = 2 + 2 * 256, while on a PPC it
returns
FAILURE: 2 != 0. Endianness bug? No, but it's a clue...
I don't think you're seeing a *bug* in the jack ringbuffer, just a
difference in
semantics between it and the PortAudio and lfq imlementations. Both PA
and lfq mask the index after reading it, so they can completely fill
the buffer.
The jack implementation masks the stored index, which means it can't
ever completely fill the buffer, or there would be an ambiguity as to
whether
it was full or empty. The most it can store is (size - 1) bytes.
In the jack version of your code, at some point, the buffer almost
fills, and
jack_ringbuffer_write only writes a single byte to the buffer (low
order on x86,
high order on PPC). Next time around, it does this again. Then the
following
thread reads, not 0x0002 like it should, but either 0x0202 (x86) or
0x0000 (PPC).
Paul said he prefers storing the masked pointer, but I think Fons & PA's
approach is better: it allows for full use of the buffer.
-Sean