]> pd.if.org Git - liblfds/blob - liblfds/liblfds6.1.1/test/src/test_ringbuffer.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds6.1.1 / test / src / test_ringbuffer.c
1 #include "internal.h"\r
2 \r
3 \r
4 \r
5 \r
6 \r
7 /****************************************************************************/\r
8 void test_lfds611_ringbuffer( void )\r
9 {\r
10   printf( "\n"\r
11           "Ringbuffer Tests\n"\r
12           "================\n" );\r
13 \r
14   ringbuffer_test_reading();\r
15   ringbuffer_test_writing();\r
16   ringbuffer_test_reading_and_writing();\r
17 \r
18   return;\r
19 }\r
20 \r
21 \r
22 \r
23 \r
24 \r
25 /****************************************************************************/\r
26 void ringbuffer_test_reading( void )\r
27 {\r
28   unsigned int\r
29     loop,\r
30     cpu_count;\r
31 \r
32   thread_state_t\r
33     *thread_handles;\r
34 \r
35   struct lfds611_ringbuffer_state\r
36     *rs;\r
37 \r
38   struct lfds611_freelist_element\r
39     *fe;\r
40 \r
41   struct ringbuffer_test_reading_state\r
42     *rtrs;\r
43 \r
44   struct lfds611_validation_info\r
45     vi = { 0, 0 };\r
46 \r
47   enum lfds611_data_structure_validity\r
48     dvs[3];\r
49 \r
50   lfds611_atom_t\r
51     total_read = 0;\r
52 \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
57 \r
58            we create one thread per CPU\r
59            where each thread busy-works,\r
60            reading until the ringbuffer is empty\r
61 \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
65   */\r
66 \r
67   internal_display_test_name( "Reading" );\r
68 \r
69   cpu_count = abstraction_cpu_count();\r
70 \r
71   lfds611_ringbuffer_new( &rs, 1000000, NULL, NULL );\r
72 \r
73   for( loop = 0 ; loop < 1000000 ; loop++ )\r
74   {\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
78   }\r
79 \r
80   rtrs = malloc( sizeof(struct ringbuffer_test_reading_state) * cpu_count );\r
81 \r
82   for( loop = 0 ; loop < cpu_count ; loop++ )\r
83   {\r
84     (rtrs+loop)->rs = rs;\r
85     (rtrs+loop)->read_count = 0;\r
86     (rtrs+loop)->error_flag = LOWERED;\r
87   }\r
88 \r
89   thread_handles = malloc( sizeof(thread_state_t) * cpu_count );\r
90 \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
93 \r
94   for( loop = 0 ; loop < cpu_count ; loop++ )\r
95     abstraction_thread_wait( thread_handles[loop] );\r
96 \r
97   free( thread_handles );\r
98 \r
99   lfds611_ringbuffer_query( rs, LFDS611_RINGBUFFER_QUERY_VALIDATE, (void *) &vi, (void *) dvs );\r
100 \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
105 \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
109 \r
110   if( total_read < 1000000 )\r
111     dvs[0] = LFDS611_VALIDITY_INVALID_MISSING_ELEMENTS;\r
112 \r
113   if( total_read > 1000000 )\r
114     dvs[0] = LFDS611_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\r
115 \r
116   free( rtrs );\r
117 \r
118   lfds611_ringbuffer_delete( rs, NULL, NULL );\r
119 \r
120   internal_display_test_result( 3, "queue", dvs[0], "queue freelist", dvs[1], "freelist", dvs[2] );\r
121 \r
122   return;\r
123 }\r
124 \r
125 \r
126 \r
127 \r
128 \r
129 /****************************************************************************/\r
130 thread_return_t CALLING_CONVENTION ringbuffer_test_thread_simple_reader( void *ringbuffer_test_reading_state )\r
131 {\r
132   struct ringbuffer_test_reading_state\r
133     *rtrs;\r
134 \r
135   struct lfds611_freelist_element\r
136     *fe;\r
137 \r
138   lfds611_atom_t\r
139     *prev_user_data,\r
140     *user_data;\r
141 \r
142   assert( ringbuffer_test_reading_state != NULL );\r
143 \r
144   rtrs = (struct ringbuffer_test_reading_state *) ringbuffer_test_reading_state;\r
145 \r
146   lfds611_ringbuffer_use( rtrs->rs );\r
147 \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
151   */\r
152 \r
153   lfds611_ringbuffer_get_read_element( rtrs->rs, &fe );\r
154   if( fe == NULL )\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
158 \r
159   rtrs->read_count++;\r
160 \r
161   while( lfds611_ringbuffer_get_read_element(rtrs->rs, &fe) )\r
162   {\r
163     lfds611_freelist_get_user_data_from_element( fe, (void **) &user_data );\r
164     lfds611_ringbuffer_put_read_element( rtrs->rs, fe );\r
165 \r
166     if( user_data <= prev_user_data )\r
167       rtrs->error_flag = RAISED;\r
168 \r
169     prev_user_data = user_data;\r
170 \r
171     rtrs->read_count++;\r
172   }\r
173 \r
174   return( (thread_return_t) EXIT_SUCCESS );\r
175 }\r
176 \r
177 \r
178 \r
179 \r
180 \r
181 /****************************************************************************/\r
182 void ringbuffer_test_writing( void )\r
183 {\r
184   unsigned int\r
185     loop,\r
186     cpu_count;\r
187 \r
188   thread_state_t\r
189     *thread_handles;\r
190 \r
191   struct lfds611_ringbuffer_state\r
192     *rs;\r
193 \r
194   struct lfds611_freelist_element\r
195     *fe;\r
196 \r
197   struct ringbuffer_test_writing_state\r
198     *rtws;\r
199 \r
200   struct lfds611_validation_info\r
201     vi = { 100000, 100000 };\r
202 \r
203   enum lfds611_data_structure_validity\r
204     dvs[3];\r
205 \r
206   lfds611_atom_t\r
207     thread,\r
208     count,\r
209     user_data,\r
210     *per_thread_counters;\r
211 \r
212   /* TRD : we create a single ringbuffer\r
213            with 100000 elements\r
214            the ringbuffers starts empty\r
215 \r
216            we create one thread per CPU\r
217            where each thread busy-works writing\r
218            for ten seconds\r
219 \r
220            the user data in each written element is a combination\r
221            of the thread number and the counter\r
222 \r
223            after the threads are complete, we validate by\r
224            checking the user data counters increment on a per thread\r
225            basis\r
226   */\r
227 \r
228   internal_display_test_name( "Writing (10 seconds)" );\r
229 \r
230   cpu_count = abstraction_cpu_count();\r
231 \r
232   lfds611_ringbuffer_new( &rs, 100000, NULL, NULL );\r
233 \r
234   rtws = malloc( sizeof(struct ringbuffer_test_writing_state) * cpu_count );\r
235 \r
236   for( loop = 0 ; loop < cpu_count ; loop++ )\r
237   {\r
238     (rtws+loop)->rs = rs;\r
239     (rtws+loop)->write_count = (lfds611_atom_t) loop << (sizeof(lfds611_atom_t)*8-8);\r
240   }\r
241 \r
242   thread_handles = malloc( sizeof(thread_state_t) * cpu_count );\r
243 \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
246 \r
247   for( loop = 0 ; loop < cpu_count ; loop++ )\r
248     abstraction_thread_wait( thread_handles[loop] );\r
249 \r
250   free( thread_handles );\r
251 \r
252   // TRD : now check results\r
253   per_thread_counters = malloc( sizeof(lfds611_atom_t) * cpu_count );\r
254 \r
255   for( loop = 0 ; loop < cpu_count ; loop++ )\r
256     *(per_thread_counters+loop) = 0;\r
257 \r
258   lfds611_ringbuffer_query( rs, LFDS611_RINGBUFFER_QUERY_VALIDATE, (void *) &vi, (void *) dvs );\r
259 \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
261   {\r
262     lfds611_freelist_get_user_data_from_element( fe, (void *) &user_data );\r
263 \r
264     thread = user_data >> (sizeof(lfds611_atom_t)*8-8);\r
265     count = (user_data << 8) >> 8;\r
266 \r
267     if( thread >= cpu_count )\r
268     {\r
269       dvs[0] = LFDS611_VALIDITY_INVALID_TEST_DATA;\r
270       lfds611_ringbuffer_put_read_element( rs, fe );\r
271       break;\r
272     }\r
273 \r
274     if( per_thread_counters[thread] == 0 )\r
275       per_thread_counters[thread] = count;\r
276 \r
277     if( count < per_thread_counters[thread] )\r
278       dvs[0] = LFDS611_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\r
279 \r
280     if( count >= per_thread_counters[thread] )\r
281       per_thread_counters[thread] = count+1;\r
282 \r
283     lfds611_ringbuffer_put_read_element( rs, fe );\r
284   }\r
285 \r
286   free( per_thread_counters );\r
287 \r
288   free( rtws );\r
289 \r
290   lfds611_ringbuffer_delete( rs, NULL, NULL );\r
291 \r
292   internal_display_test_result( 3, "queue", dvs[0], "queue freelist", dvs[1], "freelist", dvs[2] );\r
293 \r
294   return;\r
295 }\r
296 \r
297 \r
298 \r
299 \r
300 \r
301 /****************************************************************************/\r
302 thread_return_t CALLING_CONVENTION ringbuffer_test_thread_simple_writer( void *ringbuffer_test_writing_state )\r
303 {\r
304   struct ringbuffer_test_writing_state\r
305     *rtws;\r
306 \r
307   struct lfds611_freelist_element\r
308     *fe;\r
309 \r
310   time_t\r
311     start_time;\r
312 \r
313   assert( ringbuffer_test_writing_state != NULL );\r
314 \r
315   rtws = (struct ringbuffer_test_writing_state *) ringbuffer_test_writing_state;\r
316 \r
317   lfds611_ringbuffer_use( rtws->rs );\r
318 \r
319   time( &start_time );\r
320 \r
321   while( time(NULL) < start_time + 10 )\r
322   {\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
326   }\r
327 \r
328   return( (thread_return_t) EXIT_SUCCESS );\r
329 }\r
330 \r
331 \r
332 \r
333 \r
334 \r
335 /****************************************************************************/\r
336 void ringbuffer_test_reading_and_writing( void )\r
337 {\r
338   unsigned int\r
339     loop,\r
340     subloop,\r
341     cpu_count;\r
342 \r
343   thread_state_t\r
344     *thread_handles;\r
345 \r
346   struct lfds611_ringbuffer_state\r
347     *rs;\r
348 \r
349   struct ringbuffer_test_reading_and_writing_state\r
350     *rtrws;\r
351 \r
352   struct lfds611_validation_info\r
353     vi = { 0, 0 };\r
354 \r
355   enum lfds611_data_structure_validity\r
356     dvs[3];\r
357 \r
358   /* TRD : we create a single ringbuffer\r
359            with 100000 elements\r
360            the ringbuffers starts empty\r
361 \r
362            we create one thread per CPU\r
363            where each thread busy-works writing\r
364            and then immediately reading\r
365            for ten seconds\r
366 \r
367            the user data in each written element is a combination\r
368            of the thread number and the counter\r
369 \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
373   */\r
374 \r
375   internal_display_test_name( "Reading and writing (10 seconds)" );\r
376 \r
377   cpu_count = abstraction_cpu_count();\r
378 \r
379   lfds611_ringbuffer_new( &rs, 100000, NULL, NULL );\r
380 \r
381   rtrws = malloc( sizeof(struct ringbuffer_test_reading_and_writing_state) * cpu_count );\r
382 \r
383   for( loop = 0 ; loop < cpu_count ; loop++ )\r
384   {\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
390 \r
391     for( subloop = 0 ; subloop < cpu_count ; subloop++ )\r
392       *((rtrws+loop)->per_thread_counters+subloop) = 0;\r
393   }\r
394 \r
395   thread_handles = malloc( sizeof(thread_state_t) * cpu_count );\r
396 \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
399 \r
400   for( loop = 0 ; loop < cpu_count ; loop++ )\r
401     abstraction_thread_wait( thread_handles[loop] );\r
402 \r
403   free( thread_handles );\r
404 \r
405   lfds611_ringbuffer_query( rs, LFDS611_RINGBUFFER_QUERY_VALIDATE, (void *) &vi, (void *) dvs );\r
406 \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
410 \r
411   for( loop = 0 ; loop < cpu_count ; loop++ )\r
412     free( (rtrws+loop)->per_thread_counters );\r
413 \r
414   free( rtrws );\r
415 \r
416   lfds611_ringbuffer_delete( rs, NULL, NULL );\r
417 \r
418   internal_display_test_result( 3, "queue", dvs[0], "queue freelist", dvs[1], "freelist", dvs[2] );\r
419 \r
420   return;\r
421 }\r
422 \r
423 \r
424 \r
425 \r
426 \r
427 /****************************************************************************/\r
428 thread_return_t CALLING_CONVENTION ringbuffer_test_thread_reader_writer( void *ringbuffer_test_reading_and_writing_state )\r
429 {\r
430   struct ringbuffer_test_reading_and_writing_state\r
431     *rtrws;\r
432 \r
433   struct lfds611_freelist_element\r
434     *fe;\r
435 \r
436   lfds611_atom_t\r
437     user_data,\r
438     thread,\r
439     count;\r
440 \r
441   time_t\r
442     start_time;\r
443 \r
444   assert( ringbuffer_test_reading_and_writing_state != NULL );\r
445 \r
446   rtrws = (struct ringbuffer_test_reading_and_writing_state *) ringbuffer_test_reading_and_writing_state;\r
447 \r
448   lfds611_ringbuffer_use( rtrws->rs );\r
449 \r
450   time( &start_time );\r
451 \r
452   while( time(NULL) < start_time + 10 )\r
453   {\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
457 \r
458     lfds611_ringbuffer_get_read_element( rtrws->rs, &fe );\r
459     lfds611_freelist_get_user_data_from_element( fe, (void *) &user_data );\r
460 \r
461     thread = user_data >> (sizeof(lfds611_atom_t)*8-8);\r
462     count = (user_data << 8) >> 8;\r
463 \r
464     if( thread >= rtrws->cpu_count )\r
465       rtrws->error_flag = RAISED;\r
466     else\r
467     {\r
468       if( count < rtrws->per_thread_counters[thread] )\r
469         rtrws->error_flag = RAISED;\r
470 \r
471       if( count >= rtrws->per_thread_counters[thread] )\r
472         rtrws->per_thread_counters[thread] = count+1;\r
473     }\r
474 \r
475     lfds611_ringbuffer_put_read_element( rtrws->rs, fe );\r
476   }\r
477 \r
478   return( (thread_return_t) EXIT_SUCCESS );\r
479 }\r
480 \r