11 number_logical_processors;
13 lfds700_pal_uint_t volatile
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 );
25 /****************************************************************************/
26 void test_lfds700_pal_atomic_exchange( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes )
29 atomic_exchange_success_flag = RAISED,
30 exchange_success_flag = RAISED;
34 *merged_counter_arrays,
36 number_logical_processors,
39 lfds700_pal_uint_t volatile LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES)
42 struct lfds700_list_asu_element
48 struct test_pal_logical_processor
51 struct util_thread_starter_state
54 test_pal_thread_state_t
57 assert( list_of_logical_processors != NULL );
58 // TRD : memory_in_megabytes can be any value in its range
60 /* TRD : here we test pal_atomic_exchange
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)
69 there is an array per thread of 1 million elements, each a counter, set to 0
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
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)
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
82 we perform the test twice, once with pal_atomic_exchange, once with a non-atomic exchange
84 we expect the atomic to pass and the non-atomic to fail
87 internal_display_test_name( "Atomic exchange" );
89 lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
91 number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(lfds700_pal_uint_t) * (number_logical_processors + 1) );
93 merged_counter_arrays = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_elements );
95 for( loop = 0 ; loop < number_elements ; loop++ )
96 *(merged_counter_arrays+loop) = 0;
98 ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors );
100 for( loop = 0 ; loop < number_logical_processors ; loop++ )
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;
113 thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors );
116 util_thread_starter_new( &tts, number_logical_processors );
118 LFDS700_MISC_BARRIER_STORE;
120 lfds700_misc_force_store();
125 while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) )
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 );
132 util_thread_starter_run( tts );
134 for( loop = 0 ; loop < number_logical_processors ; loop++ )
135 test_pal_thread_wait( thread_handles[loop] );
137 util_thread_starter_delete( tts );
139 LFDS700_MISC_BARRIER_LOAD;
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 );
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
152 for( loop = 0 ; loop < number_elements - number_logical_processors ; loop++ )
153 if( *(merged_counter_arrays+loop) != 1 )
154 exchange_success_flag = LOWERED;
156 // TRD : now for atomic exchange - we need to re-init the data structures
158 for( loop = 0 ; loop < number_elements ; loop++ )
159 *(merged_counter_arrays+loop) = 0;
161 for( loop = 0 ; loop < number_logical_processors ; loop++ )
162 for( subloop = 0 ; subloop < number_elements ; subloop++ )
163 *((ts+loop)->counter_array+subloop) = 0;
167 util_thread_starter_new( &tts, number_logical_processors );
169 LFDS700_MISC_BARRIER_STORE;
171 lfds700_misc_force_store();
176 while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) )
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 );
183 util_thread_starter_run( tts );
185 for( loop = 0 ; loop < number_logical_processors ; loop++ )
186 test_pal_thread_wait( thread_handles[loop] );
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 );
192 for( loop = 0 ; loop < number_elements - number_logical_processors ; loop++ )
193 if( *(merged_counter_arrays+loop) != 1 )
194 atomic_exchange_success_flag = LOWERED;
197 free( merged_counter_arrays );
199 for( loop = 0 ; loop < number_logical_processors ; loop++ )
200 free( (ts+loop)->counter_array );
202 util_thread_starter_delete( tts );
203 free( thread_handles );
208 on a single core, atomic and non-atomic exchange should both work
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
214 LFDS700_MISC_BARRIER_LOAD;
216 if( number_logical_processors == 1 )
218 if( exchange_success_flag == RAISED and atomic_exchange_success_flag == RAISED )
221 if( exchange_success_flag != RAISED or atomic_exchange_success_flag != RAISED )
222 puts( "failed (atomic and non-atomic both failed)" );
225 if( number_logical_processors >= 2 )
227 if( atomic_exchange_success_flag == RAISED and exchange_success_flag == LOWERED )
230 if( atomic_exchange_success_flag == RAISED and exchange_success_flag == RAISED )
231 puts( "indeterminate (atomic and non-atomic both passed)" );
233 if( atomic_exchange_success_flag == LOWERED )
235 puts( "failed (atomic failed)" );
236 exit( EXIT_FAILURE );
247 /****************************************************************************/
248 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_exchange( void *util_thread_starter_thread_state )
257 struct util_thread_starter_thread_state
260 LFDS700_MISC_BARRIER_LOAD;
262 assert( util_thread_starter_thread_state != NULL );
264 tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
265 ts = (struct test_state *) tsts->thread_user_state;
267 util_thread_starter_ready_and_wait( tsts );
269 local_counter = ts->counter;
271 while( local_counter < ts->number_elements )
273 exchange = *ts->shared_exchange;
274 *ts->shared_exchange = local_counter;
276 ( *(ts->counter_array + exchange) )++;
278 local_counter += ts->number_logical_processors;
281 LFDS700_MISC_BARRIER_STORE;
283 lfds700_misc_force_store();
285 return( (test_pal_thread_return_t) EXIT_SUCCESS );
292 /****************************************************************************/
293 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_atomic_exchange( void *util_thread_starter_thread_state )
302 struct util_thread_starter_thread_state
305 LFDS700_MISC_BARRIER_LOAD;
307 assert( util_thread_starter_thread_state != NULL );
309 tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
310 ts = (struct test_state *) tsts->thread_user_state;
312 util_thread_starter_ready_and_wait( tsts );
314 local_counter = ts->counter;
316 while( local_counter < ts->number_elements )
318 exchange = local_counter;
320 LFDS700_PAL_ATOMIC_EXCHANGE( ts->shared_exchange, &exchange );
322 ( *(ts->counter_array + exchange) )++;
324 local_counter += ts->number_logical_processors;
327 LFDS700_MISC_BARRIER_STORE;
329 lfds700_misc_force_store();
331 return( (test_pal_thread_return_t) EXIT_SUCCESS );