Olivier Guilyardi wrote: > Paul Davis wrote: >> On Wed, 2008-10-15 at 13:02 +0200, Olivier Guilyardi wrote: >>> I'm no memory barrier expert, but from what I read this looks like a complex >>> topic. Adding them to jack's ring buffer may be hazardous without carefully >>> crafted test cases. Bugs related to missing barriers may or may not happen >>> according to various hardware-related issues. >> the point of memory barriers is really to remove the need for test >> cases :) > > I meant Test First, not putting a memory barrier between us and past bugs ;) > > My concern is: people around say memory barriers are missing, but could anyone > write a unit test that actually turns this assumption into a bug? Okay, I wrote such a test. It fails with Jack's ringbuffer (jack1 r3004) but succeeds with Portaudio's one (r1240). It's a very simple test. I'm starting two threads, writing incremented numbers into a ringbuffer, and checking that they follow each other on the reading end. The failure frequency depends on the chunk size / buffer size ratio. With relative short runs, I'm getting about 2 failures / million, for both 256 / 512 and 256 / 1024. I'm around 0.5 failure / million with a 256 / 4096 ratio. But longer runs would be necessary for exact statistics. There is no such failure with Portaudio's ringbuffer, even if I deactivate its memory barriers. But I just can't say if this bug is caused by the lack of memory barrier or not in Jack, because the two implementations are different, and all of this seems to depend on the CPU architecture, the movements of the clouds, the color of my coffee, etc.. ;) I'm running these tests on a Intel Core2 Quad Q6600 CPU, and making sure the two threads run on a different CPU by looking at the program startup output. I didn't test on a single-cpu architecture. The Portaudio code looks more and more robust to me. It's also surprisingly short. Maybe that the best would be to replace jack's ringbuffer with it? I think it should be possible to keep the jack_ringbuffer api unchanged. My test code is below. It expects the buffer size as first argument. Try with 512, 1024, 2048,... With a buffer size of 4096 bytes, I sometimes need to wait a minute or so for the first failure to appear. When saved in jack1 svn working dir, I compile it with something like: gcc -I. -o testrb -Wall testrb.c libjack/ringbuffer.c -lpthread #include <unistd.h> #include <jack/ringbuffer.h> #include <pthread.h> #include <stdio.h> #include <utmpx.h> #define ARRAY_SIZE 64 #define MAX_VALUE 0x10000 jack_ringbuffer_t *rb; static int fill_int_array (int *array, int start, int count) { int i, j = start; for (i = 0; i < count; i++) { array[i] = j; j = (j + 1) % MAX_VALUE; } return j; } static int cmp_array (int *array1, int *array2, int count) { int i; for (i = 0; i < count; i++) if (array1[i] != array2[i]) { printf("%d != %d at offset %d\n", array1[i], array2[i], i); return 0; } return 1; } static void * reader_start (void * arg) { int i = 0, a[ARRAY_SIZE], b[ARRAY_SIZE]; unsigned long j = 0, nfailures = 0; printf("reader started on cpu %d\n", sched_getcpu()); i = fill_int_array (a, i, ARRAY_SIZE); while (1) { if (jack_ringbuffer_read_space (rb) >= ARRAY_SIZE * sizeof (int)) { if (jack_ringbuffer_read (rb, (char *) b, ARRAY_SIZE * sizeof (int))) { if (!cmp_array (a, b, ARRAY_SIZE)) { nfailures++; printf("failure in chunk %lu - probability: %lu/%lu = %.3f per million\n", j, nfailures, j, (float) nfailures / (j + 1) * 1000000); i = (b[0] + ARRAY_SIZE) % MAX_VALUE; } i = fill_int_array (a, i, ARRAY_SIZE); j++; } } } return NULL; } static void * writer_start (void * arg) { int i = 0, a[ARRAY_SIZE]; printf("writer started on cpu: %d\n", sched_getcpu()); i = fill_int_array (a, i, ARRAY_SIZE); while (1) { if (jack_ringbuffer_write_space (rb) >= ARRAY_SIZE * sizeof (int)) { if (jack_ringbuffer_write (rb, (char *) a, ARRAY_SIZE * sizeof (int))) { i = fill_int_array (a, i, ARRAY_SIZE); } } } return NULL; } int main(int argc, char *argv[]) { int size; printf("starting ringbuffer stress test\n"); sscanf(argv[1], "%d", &size); printf("buffer size (bytes): %d\n", size); printf("array size (bytes): %d\n", sizeof(int) * ARRAY_SIZE); rb = jack_ringbuffer_create(size); pthread_t reader_thread, writer_thread; pthread_create (&reader_thread, NULL, reader_start, NULL); pthread_create (&writer_thread, NULL, writer_start, NULL); while (1) sleep(1); return 0; } -- Olivier Guilyardi / Samalyse _______________________________________________ Linux-audio-user mailing list Linux-audio-user@xxxxxxxxxxxxxxxxxxxx http://lists.linuxaudio.org/mailman/listinfo/linux-audio-user