1 #include "internal.h"
\r
7 /****************************************************************************/
\r
8 void test_lfds611_ringbuffer( void )
\r
11 "Ringbuffer Tests\n"
\r
12 "================\n" );
\r
14 ringbuffer_test_reading();
\r
15 ringbuffer_test_writing();
\r
16 ringbuffer_test_reading_and_writing();
\r
25 /****************************************************************************/
\r
26 void ringbuffer_test_reading( void )
\r
35 struct lfds611_ringbuffer_state
\r
38 struct lfds611_freelist_element
\r
41 struct ringbuffer_test_reading_state
\r
44 struct lfds611_validation_info
\r
47 enum lfds611_data_structure_validity
\r
53 /* TRD : we create a single ringbuffer
\r
54 with 1,000,000 elements
\r
55 we populate the ringbuffer, where the
\r
56 user data is an incrementing counter
\r
58 we create one thread per CPU
\r
59 where each thread busy-works,
\r
60 reading until the ringbuffer is empty
\r
62 each thread keeps track of the number of reads it manages
\r
63 and that each user data it reads is greater than the
\r
64 previous user data that was read
\r
67 internal_display_test_name( "Reading" );
\r
69 cpu_count = abstraction_cpu_count();
\r
71 lfds611_ringbuffer_new( &rs, 1000000, NULL, NULL );
\r
73 for( loop = 0 ; loop < 1000000 ; loop++ )
\r
75 lfds611_ringbuffer_get_write_element( rs, &fe, NULL );
\r
76 lfds611_freelist_set_user_data_in_element( fe, (void *) (lfds611_atom_t) loop );
\r
77 lfds611_ringbuffer_put_write_element( rs, fe );
\r
80 rtrs = malloc( sizeof(struct ringbuffer_test_reading_state) * cpu_count );
\r
82 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
84 (rtrs+loop)->rs = rs;
\r
85 (rtrs+loop)->read_count = 0;
\r
86 (rtrs+loop)->error_flag = LOWERED;
\r
89 thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
\r
91 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
92 abstraction_thread_start( &thread_handles[loop], loop, ringbuffer_test_thread_simple_reader, rtrs+loop );
\r
94 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
95 abstraction_thread_wait( thread_handles[loop] );
\r
97 free( thread_handles );
\r
99 lfds611_ringbuffer_query( rs, LFDS611_RINGBUFFER_QUERY_VALIDATE, (void *) &vi, (void *) dvs );
\r
101 // TRD : check for raised error flags
\r
102 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
103 if( (rtrs+loop)->error_flag == RAISED )
\r
104 dvs[0] = LFDS611_VALIDITY_INVALID_TEST_DATA;
\r
106 // TRD : check thread reads total to 1,000,000
\r
107 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
108 total_read += (rtrs+loop)->read_count;
\r
110 if( total_read < 1000000 )
\r
111 dvs[0] = LFDS611_VALIDITY_INVALID_MISSING_ELEMENTS;
\r
113 if( total_read > 1000000 )
\r
114 dvs[0] = LFDS611_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;
\r
118 lfds611_ringbuffer_delete( rs, NULL, NULL );
\r
120 internal_display_test_result( 3, "queue", dvs[0], "queue freelist", dvs[1], "freelist", dvs[2] );
\r
129 /****************************************************************************/
\r
130 thread_return_t CALLING_CONVENTION ringbuffer_test_thread_simple_reader( void *ringbuffer_test_reading_state )
\r
132 struct ringbuffer_test_reading_state
\r
135 struct lfds611_freelist_element
\r
142 assert( ringbuffer_test_reading_state != NULL );
\r
144 rtrs = (struct ringbuffer_test_reading_state *) ringbuffer_test_reading_state;
\r
146 lfds611_ringbuffer_use( rtrs->rs );
\r
148 /* TRD : read an initial element to load a value into prev_user_data
\r
149 it may be (under valgrind for example) that by the time we start
\r
150 there are no elements remaining to read
\r
153 lfds611_ringbuffer_get_read_element( rtrs->rs, &fe );
\r
155 return( (thread_return_t) EXIT_SUCCESS );
\r
156 lfds611_freelist_get_user_data_from_element( fe, (void **) &prev_user_data );
\r
157 lfds611_ringbuffer_put_read_element( rtrs->rs, fe );
\r
159 rtrs->read_count++;
\r
161 while( lfds611_ringbuffer_get_read_element(rtrs->rs, &fe) )
\r
163 lfds611_freelist_get_user_data_from_element( fe, (void **) &user_data );
\r
164 lfds611_ringbuffer_put_read_element( rtrs->rs, fe );
\r
166 if( user_data <= prev_user_data )
\r
167 rtrs->error_flag = RAISED;
\r
169 prev_user_data = user_data;
\r
171 rtrs->read_count++;
\r
174 return( (thread_return_t) EXIT_SUCCESS );
\r
181 /****************************************************************************/
\r
182 void ringbuffer_test_writing( void )
\r
191 struct lfds611_ringbuffer_state
\r
194 struct lfds611_freelist_element
\r
197 struct ringbuffer_test_writing_state
\r
200 struct lfds611_validation_info
\r
201 vi = { 100000, 100000 };
\r
203 enum lfds611_data_structure_validity
\r
210 *per_thread_counters;
\r
212 /* TRD : we create a single ringbuffer
\r
213 with 100000 elements
\r
214 the ringbuffers starts empty
\r
216 we create one thread per CPU
\r
217 where each thread busy-works writing
\r
220 the user data in each written element is a combination
\r
221 of the thread number and the counter
\r
223 after the threads are complete, we validate by
\r
224 checking the user data counters increment on a per thread
\r
228 internal_display_test_name( "Writing (10 seconds)" );
\r
230 cpu_count = abstraction_cpu_count();
\r
232 lfds611_ringbuffer_new( &rs, 100000, NULL, NULL );
\r
234 rtws = malloc( sizeof(struct ringbuffer_test_writing_state) * cpu_count );
\r
236 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
238 (rtws+loop)->rs = rs;
\r
239 (rtws+loop)->write_count = (lfds611_atom_t) loop << (sizeof(lfds611_atom_t)*8-8);
\r
242 thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
\r
244 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
245 abstraction_thread_start( &thread_handles[loop], loop, ringbuffer_test_thread_simple_writer, rtws+loop );
\r
247 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
248 abstraction_thread_wait( thread_handles[loop] );
\r
250 free( thread_handles );
\r
252 // TRD : now check results
\r
253 per_thread_counters = malloc( sizeof(lfds611_atom_t) * cpu_count );
\r
255 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
256 *(per_thread_counters+loop) = 0;
\r
258 lfds611_ringbuffer_query( rs, LFDS611_RINGBUFFER_QUERY_VALIDATE, (void *) &vi, (void *) dvs );
\r
260 while( dvs[0] == LFDS611_VALIDITY_VALID and dvs[1] == LFDS611_VALIDITY_VALID and dvs[2] == LFDS611_VALIDITY_VALID and lfds611_ringbuffer_get_read_element(rs, &fe) )
\r
262 lfds611_freelist_get_user_data_from_element( fe, (void *) &user_data );
\r
264 thread = user_data >> (sizeof(lfds611_atom_t)*8-8);
\r
265 count = (user_data << 8) >> 8;
\r
267 if( thread >= cpu_count )
\r
269 dvs[0] = LFDS611_VALIDITY_INVALID_TEST_DATA;
\r
270 lfds611_ringbuffer_put_read_element( rs, fe );
\r
274 if( per_thread_counters[thread] == 0 )
\r
275 per_thread_counters[thread] = count;
\r
277 if( count < per_thread_counters[thread] )
\r
278 dvs[0] = LFDS611_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;
\r
280 if( count >= per_thread_counters[thread] )
\r
281 per_thread_counters[thread] = count+1;
\r
283 lfds611_ringbuffer_put_read_element( rs, fe );
\r
286 free( per_thread_counters );
\r
290 lfds611_ringbuffer_delete( rs, NULL, NULL );
\r
292 internal_display_test_result( 3, "queue", dvs[0], "queue freelist", dvs[1], "freelist", dvs[2] );
\r
301 /****************************************************************************/
\r
302 thread_return_t CALLING_CONVENTION ringbuffer_test_thread_simple_writer( void *ringbuffer_test_writing_state )
\r
304 struct ringbuffer_test_writing_state
\r
307 struct lfds611_freelist_element
\r
313 assert( ringbuffer_test_writing_state != NULL );
\r
315 rtws = (struct ringbuffer_test_writing_state *) ringbuffer_test_writing_state;
\r
317 lfds611_ringbuffer_use( rtws->rs );
\r
319 time( &start_time );
\r
321 while( time(NULL) < start_time + 10 )
\r
323 lfds611_ringbuffer_get_write_element( rtws->rs, &fe, NULL );
\r
324 lfds611_freelist_set_user_data_in_element( fe, (void *) (lfds611_atom_t) (rtws->write_count++) );
\r
325 lfds611_ringbuffer_put_write_element( rtws->rs, fe );
\r
328 return( (thread_return_t) EXIT_SUCCESS );
\r
335 /****************************************************************************/
\r
336 void ringbuffer_test_reading_and_writing( void )
\r
346 struct lfds611_ringbuffer_state
\r
349 struct ringbuffer_test_reading_and_writing_state
\r
352 struct lfds611_validation_info
\r
355 enum lfds611_data_structure_validity
\r
358 /* TRD : we create a single ringbuffer
\r
359 with 100000 elements
\r
360 the ringbuffers starts empty
\r
362 we create one thread per CPU
\r
363 where each thread busy-works writing
\r
364 and then immediately reading
\r
367 the user data in each written element is a combination
\r
368 of the thread number and the counter
\r
370 while a thread runs, it keeps track of the
\r
371 counters for the other threads and throws an error
\r
372 if it sees the number stay the same or decrease
\r
375 internal_display_test_name( "Reading and writing (10 seconds)" );
\r
377 cpu_count = abstraction_cpu_count();
\r
379 lfds611_ringbuffer_new( &rs, 100000, NULL, NULL );
\r
381 rtrws = malloc( sizeof(struct ringbuffer_test_reading_and_writing_state) * cpu_count );
\r
383 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
385 (rtrws+loop)->rs = rs;
\r
386 (rtrws+loop)->counter = (lfds611_atom_t) loop << (sizeof(lfds611_atom_t)*8-8);
\r
387 (rtrws+loop)->cpu_count = cpu_count;
\r
388 (rtrws+loop)->error_flag = LOWERED;
\r
389 (rtrws+loop)->per_thread_counters = malloc( sizeof(lfds611_atom_t) * cpu_count );
\r
391 for( subloop = 0 ; subloop < cpu_count ; subloop++ )
\r
392 *((rtrws+loop)->per_thread_counters+subloop) = 0;
\r
395 thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
\r
397 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
398 abstraction_thread_start( &thread_handles[loop], loop, ringbuffer_test_thread_reader_writer, rtrws+loop );
\r
400 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
401 abstraction_thread_wait( thread_handles[loop] );
\r
403 free( thread_handles );
\r
405 lfds611_ringbuffer_query( rs, LFDS611_RINGBUFFER_QUERY_VALIDATE, (void *) &vi, (void *) dvs );
\r
407 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
408 if( (rtrws+loop)->error_flag == RAISED )
\r
409 dvs[0] = LFDS611_VALIDITY_INVALID_TEST_DATA;
\r
411 for( loop = 0 ; loop < cpu_count ; loop++ )
\r
412 free( (rtrws+loop)->per_thread_counters );
\r
416 lfds611_ringbuffer_delete( rs, NULL, NULL );
\r
418 internal_display_test_result( 3, "queue", dvs[0], "queue freelist", dvs[1], "freelist", dvs[2] );
\r
427 /****************************************************************************/
\r
428 thread_return_t CALLING_CONVENTION ringbuffer_test_thread_reader_writer( void *ringbuffer_test_reading_and_writing_state )
\r
430 struct ringbuffer_test_reading_and_writing_state
\r
433 struct lfds611_freelist_element
\r
444 assert( ringbuffer_test_reading_and_writing_state != NULL );
\r
446 rtrws = (struct ringbuffer_test_reading_and_writing_state *) ringbuffer_test_reading_and_writing_state;
\r
448 lfds611_ringbuffer_use( rtrws->rs );
\r
450 time( &start_time );
\r
452 while( time(NULL) < start_time + 10 )
\r
454 lfds611_ringbuffer_get_write_element( rtrws->rs, &fe, NULL );
\r
455 lfds611_freelist_set_user_data_in_element( fe, (void *) (lfds611_atom_t) (rtrws->counter++) );
\r
456 lfds611_ringbuffer_put_write_element( rtrws->rs, fe );
\r
458 lfds611_ringbuffer_get_read_element( rtrws->rs, &fe );
\r
459 lfds611_freelist_get_user_data_from_element( fe, (void *) &user_data );
\r
461 thread = user_data >> (sizeof(lfds611_atom_t)*8-8);
\r
462 count = (user_data << 8) >> 8;
\r
464 if( thread >= rtrws->cpu_count )
\r
465 rtrws->error_flag = RAISED;
\r
468 if( count < rtrws->per_thread_counters[thread] )
\r
469 rtrws->error_flag = RAISED;
\r
471 if( count >= rtrws->per_thread_counters[thread] )
\r
472 rtrws->per_thread_counters[thread] = count+1;
\r
475 lfds611_ringbuffer_put_read_element( rtrws->rs, fe );
\r
478 return( (thread_return_t) EXIT_SUCCESS );
\r