]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_exchange.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.0.0 / test / src / test_lfds700_porting_abstraction_layer_atomic_exchange.c
1 /***** includes *****/
2 #include "internal.h"
3
4 /***** structs *****/
5 struct test_state
6 {
7   lfds700_pal_uint_t
8     counter,
9     *counter_array,
10     number_elements,
11     number_logical_processors;
12
13   lfds700_pal_uint_t volatile
14     *shared_exchange;
15 };
16
17 /***** private prototyps *****/
18 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_exchange( void *util_thread_starter_thread_state );
19 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_atomic_exchange( void *util_thread_starter_thread_state );
20
21
22
23
24
25 /****************************************************************************/
26 void test_lfds700_pal_atomic_exchange( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes )
27 {
28   enum flag
29     atomic_exchange_success_flag = RAISED,
30     exchange_success_flag = RAISED;
31
32   lfds700_pal_uint_t
33     loop,
34     *merged_counter_arrays,
35     number_elements,
36     number_logical_processors,
37     subloop;
38
39   lfds700_pal_uint_t volatile LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES)
40     exchange;
41
42   struct lfds700_list_asu_element
43     *lasue;
44
45   struct test_state
46     *ts;
47
48   struct test_pal_logical_processor
49     *lp;
50
51   struct util_thread_starter_state
52     *tts;
53
54   test_pal_thread_state_t
55     *thread_handles;
56
57   assert( list_of_logical_processors != NULL );
58   // TRD : memory_in_megabytes can be any value in its range
59
60   /* TRD : here we test pal_atomic_exchange
61
62            we have one thread per logical core
63            there is one variable which every thread will exchange to/from 
64            we know the number of logical cores
65            the threads have a counter each, which begins with their logical core number plus one
66            (plus one because the exchange counter begins with 0 already in place)
67            (e.g. thread 0 begins with its counter at 1, thread 1 begins with its counter at 2, etc)
68
69            there is an array per thread of 1 million elements, each a counter, set to 0
70
71            when running, each thread increments its counter by the number of threads
72            the threads busy loop, exchanging
73            every time a thread pulls a number off the central, shared exchange variable,
74            it increments the counter for that variable in its thread-local counter array
75
76            (we're not using a global array, because we'd have to be atomic in our increments,
77             which is a slow-down we don't want)
78
79            at the end, we merge all the counter arrays and if the frequency for a counter is a value
80            other than 1, the exchange was not atomic
81
82            we perform the test twice, once with pal_atomic_exchange, once with a non-atomic exchange
83
84            we expect the atomic to pass and the non-atomic to fail
85   */
86
87   internal_display_test_name( "Atomic exchange" );
88
89   lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
90
91   number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(lfds700_pal_uint_t) * (number_logical_processors + 1) );
92
93   merged_counter_arrays = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_elements );
94
95   for( loop = 0 ; loop < number_elements ; loop++ )
96     *(merged_counter_arrays+loop) = 0;
97
98   ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors );
99
100   for( loop = 0 ; loop < number_logical_processors ; loop++ )
101   {
102     (ts+loop)->counter = loop + 1;
103     (ts+loop)->counter_array = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_elements );
104     for( subloop = 0 ; subloop < number_elements ; subloop++ )
105       *((ts+loop)->counter_array+subloop) = 0;
106     (ts+loop)->number_logical_processors = number_logical_processors;
107     (ts+loop)->shared_exchange = &exchange;
108     (ts+loop)->number_elements = number_elements;
109   }
110
111   exchange = 0;
112
113   thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors );
114
115   // TRD : non-atomic
116   util_thread_starter_new( &tts, number_logical_processors );
117
118   LFDS700_MISC_BARRIER_STORE;
119
120   lfds700_misc_force_store();
121
122   loop = 0;
123   lasue = NULL;
124
125   while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) )
126   {
127     lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
128     util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_exchange, ts+loop );
129     loop++;
130   }
131
132   util_thread_starter_run( tts );
133
134   for( loop = 0 ; loop < number_logical_processors ; loop++ )
135     test_pal_thread_wait( thread_handles[loop] );
136
137   util_thread_starter_delete( tts );
138
139   LFDS700_MISC_BARRIER_LOAD;
140
141   for( loop = 0 ; loop < number_elements ; loop++ )
142     for( subloop = 0 ; subloop < number_logical_processors ; subloop++ )
143       *(merged_counter_arrays+loop) += *( (ts+subloop)->counter_array+loop );
144
145   /* TRD : the worker threads exit when their per-thread counter exceeds 1,000,000
146            as such the final number_logical_processors numbers are not read
147            we could change the threads to exit when the number they read exceeds 1,000,000
148            but then we'd need an if() in their work-loop,
149            and we need to go as fast as possible
150   */
151
152   for( loop = 0 ; loop < number_elements - number_logical_processors ; loop++ )
153     if( *(merged_counter_arrays+loop) != 1 )
154       exchange_success_flag = LOWERED;
155
156   // TRD : now for atomic exchange - we need to re-init the data structures
157
158   for( loop = 0 ; loop < number_elements ; loop++ )
159     *(merged_counter_arrays+loop) = 0;
160
161   for( loop = 0 ; loop < number_logical_processors ; loop++ )
162     for( subloop = 0 ; subloop < number_elements ; subloop++ )
163       *((ts+loop)->counter_array+subloop) = 0;
164
165   exchange = 0;
166
167   util_thread_starter_new( &tts, number_logical_processors );
168
169   LFDS700_MISC_BARRIER_STORE;
170
171   lfds700_misc_force_store();
172
173   loop = 0;
174   lasue = NULL;
175
176   while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) )
177   {
178     lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
179     util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_atomic_exchange, ts+loop );
180     loop++;
181   }
182
183   util_thread_starter_run( tts );
184
185   for( loop = 0 ; loop < number_logical_processors ; loop++ )
186     test_pal_thread_wait( thread_handles[loop] );
187
188   for( loop = 0 ; loop < number_elements ; loop++ )
189     for( subloop = 0 ; subloop < number_logical_processors ; subloop++ )
190       *(merged_counter_arrays+loop) += *( (ts+subloop)->counter_array+loop );
191
192   for( loop = 0 ; loop < number_elements - number_logical_processors ; loop++ )
193     if( *(merged_counter_arrays+loop) != 1 )
194       atomic_exchange_success_flag = LOWERED;
195
196   // TRD : cleanup
197   free( merged_counter_arrays );
198
199   for( loop = 0 ; loop < number_logical_processors ; loop++ )
200     free( (ts+loop)->counter_array );
201
202   util_thread_starter_delete( tts );
203   free( thread_handles );
204   free( ts );
205
206   /* TRD : results
207
208            on a single core, atomic and non-atomic exchange should both work
209
210            if we find our non-atomic test passes, then we can't really say anything
211            about whether or not the atomic test is really working
212   */
213
214   LFDS700_MISC_BARRIER_LOAD;
215
216   if( number_logical_processors == 1 )
217   {
218     if( exchange_success_flag == RAISED and atomic_exchange_success_flag == RAISED )
219       puts( "passed" );
220
221     if( exchange_success_flag != RAISED or atomic_exchange_success_flag != RAISED )
222       puts( "failed (atomic and non-atomic both failed)" );
223   }
224
225   if( number_logical_processors >= 2 )
226   {
227     if( atomic_exchange_success_flag == RAISED and exchange_success_flag == LOWERED )
228       puts( "passed" );
229
230     if( atomic_exchange_success_flag == RAISED and exchange_success_flag == RAISED )
231       puts( "indeterminate (atomic and non-atomic both passed)" );
232
233     if( atomic_exchange_success_flag == LOWERED )
234     {
235       puts( "failed (atomic failed)" );
236       exit( EXIT_FAILURE );
237     }
238   }
239
240   return;
241 }
242
243
244
245
246
247 /****************************************************************************/
248 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_exchange( void *util_thread_starter_thread_state )
249 {
250   lfds700_pal_uint_t
251     local_counter,
252     exchange;
253
254   struct test_state
255     *ts;
256
257   struct util_thread_starter_thread_state
258     *tsts;
259
260   LFDS700_MISC_BARRIER_LOAD;
261
262   assert( util_thread_starter_thread_state != NULL );
263
264   tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
265   ts = (struct test_state *) tsts->thread_user_state;
266
267   util_thread_starter_ready_and_wait( tsts );
268
269   local_counter = ts->counter;
270
271   while( local_counter < ts->number_elements )
272   {
273     exchange = *ts->shared_exchange;
274     *ts->shared_exchange = local_counter;
275
276     ( *(ts->counter_array + exchange) )++;
277
278     local_counter += ts->number_logical_processors;
279   }
280
281   LFDS700_MISC_BARRIER_STORE;
282
283   lfds700_misc_force_store();
284
285   return( (test_pal_thread_return_t) EXIT_SUCCESS );
286 }
287
288
289
290
291
292 /****************************************************************************/
293 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_atomic_exchange( void *util_thread_starter_thread_state )
294 {
295   lfds700_pal_uint_t
296     local_counter,
297     exchange;
298
299   struct test_state
300     *ts;
301
302   struct util_thread_starter_thread_state
303     *tsts;
304
305   LFDS700_MISC_BARRIER_LOAD;
306
307   assert( util_thread_starter_thread_state != NULL );
308
309   tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
310   ts = (struct test_state *) tsts->thread_user_state;
311
312   util_thread_starter_ready_and_wait( tsts );
313
314   local_counter = ts->counter;
315
316   while( local_counter < ts->number_elements )
317   {
318     exchange = local_counter;
319
320     LFDS700_PAL_ATOMIC_EXCHANGE( ts->shared_exchange, &exchange );
321
322     ( *(ts->counter_array + exchange) )++;
323
324     local_counter += ts->number_logical_processors;
325   }
326
327   LFDS700_MISC_BARRIER_STORE;
328
329   lfds700_misc_force_store();
330
331   return( (test_pal_thread_return_t) EXIT_SUCCESS );
332 }
333