2 #include "libtest_tests_internal.h"
5 struct test_per_thread_state
10 number_elements_per_thread,
11 number_logical_processors;
13 lfds710_pal_uint_t volatile
17 /***** private prototyps *****/
18 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_exchange( void *libtest_threadset_per_thread_state );
19 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_atomic_exchange( void *libtest_threadset_per_thread_state );
25 /****************************************************************************/
26 void libtest_tests_pal_atomic_exchange( struct lfds710_list_asu_state *list_of_logical_processors, struct libshared_memory_state *ms, enum lfds710_misc_validity *dvs )
29 atomic_exchange_success_flag = RAISED,
30 exchange_success_flag = RAISED;
34 *merged_counter_arrays,
36 number_elements_per_thread,
37 number_logical_processors,
40 lfds710_pal_uint_t volatile LFDS710_PAL_ALIGN(LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES)
43 struct lfds710_list_asu_element
46 struct libtest_logical_processor
49 struct libtest_threadset_per_thread_state
52 struct libtest_threadset_state
55 struct test_per_thread_state
58 LFDS710_PAL_ASSERT( list_of_logical_processors != NULL );
59 LFDS710_PAL_ASSERT( ms != NULL );
60 LFDS710_PAL_ASSERT( dvs != NULL );
62 /* TRD : here we test pal_atomic_exchange
64 we have one thread per logical core
65 there is one variable which every thread will exchange to/from
66 we know the number of logical cores
67 the threads have a counter each, which begins with their logical core number plus one
68 (plus one because the exchange counter begins with 0 already in place)
69 (e.g. thread 0 begins with its counter at 1, thread 1 begins with its counter at 2, etc)
71 there is an array per thread of 1 million elements, each a counter, set to 0
73 when running, each thread increments its counter by the number of threads
74 the threads busy loop, exchanging
75 every time aa thread pulls a number off the central, shared exchange variable,
76 it increments the counter for that variable in its thread-local counter array
78 (we're not using a global array, because we'd have to be atomic in our increments,
79 which is a slow-down we don't want)
81 at the end, we merge all the counter arrays and if the frequency for a counter is a value
82 other than 1, the exchange was not atomic
84 we perform the test twice, once with pal_atomic_exchange, once with a non-atomic exchange
86 we expect the atomic to pass and the non-atomic to fail
89 *dvs = LFDS710_MISC_VALIDITY_VALID;
92 lfds710_list_asu_query( list_of_logical_processors, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
93 tpts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct test_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
94 pts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct libtest_threadset_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
95 merged_counter_arrays = libshared_memory_alloc_largest_possible_array_from_unknown_node( ms, sizeof(lfds710_pal_uint_t), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES, &number_elements );
97 /* TRD : one array per thread, one array for merging
98 +1 as we need store for a merged counter array
101 number_elements_per_thread = number_elements / (number_logical_processors+1);
105 for( loop = 0 ; loop < number_elements_per_thread ; loop++ )
106 *(merged_counter_arrays+loop) = 0;
108 libtest_threadset_init( &ts, NULL );
112 while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors,lasue) )
114 lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
116 (tpts+loop)->counter = loop + 1;
117 // TRD : +1 on loop to move past merged_counter_arrays
118 (tpts+loop)->counter_array = merged_counter_arrays + ((loop+1)*number_elements_per_thread);
119 for( subloop = 0 ; subloop < number_elements_per_thread ; subloop++ )
120 *((tpts+loop)->counter_array+subloop) = 0;
121 (tpts+loop)->number_logical_processors = number_logical_processors;
122 (tpts+loop)->shared_exchange = &exchange;
123 (tpts+loop)->number_elements_per_thread = number_elements_per_thread;
125 libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_exchange, &tpts[loop] );
130 LFDS710_MISC_BARRIER_STORE;
132 lfds710_misc_force_store();
134 // TRD : run the test
135 libtest_threadset_run( &ts );
136 libtest_threadset_cleanup( &ts );
139 LFDS710_MISC_BARRIER_LOAD;
141 for( loop = 0 ; loop < number_elements_per_thread ; loop++ )
142 for( subloop = 0 ; subloop < number_logical_processors ; subloop++ )
143 *(merged_counter_arrays+loop) += *( (tpts+subloop)->counter_array+loop );
145 /* TRD : the worker threads exit when their per-thread counter exceeds number_elements_per_thread
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 number_elements_per_thread
148 but then we'd need an if() in their work-loop,
149 and we want to go as fast as possible
152 for( loop = 0 ; loop < number_elements_per_thread - 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_per_thread ; loop++ )
159 *(merged_counter_arrays+loop) = 0;
161 libtest_threadset_init( &ts, NULL );
163 for( loop = 0 ; loop < number_logical_processors ; loop++ )
164 for( subloop = 0 ; subloop < number_elements_per_thread ; subloop++ )
165 *((tpts+loop)->counter_array+subloop) = 0;
170 while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors,lasue) )
172 lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
174 libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_atomic_exchange, &tpts[loop] );
180 LFDS710_MISC_BARRIER_STORE;
182 lfds710_misc_force_store();
184 libtest_threadset_run( &ts );
186 libtest_threadset_cleanup( &ts );
189 LFDS710_MISC_BARRIER_LOAD;
191 for( loop = 0 ; loop < number_elements_per_thread ; loop++ )
192 for( subloop = 0 ; subloop < number_logical_processors ; subloop++ )
193 *(merged_counter_arrays+loop) += *( (tpts+subloop)->counter_array+loop );
195 for( loop = 0 ; loop < number_elements_per_thread - number_logical_processors ; loop++ )
196 if( *(merged_counter_arrays+loop) != 1 )
197 atomic_exchange_success_flag = LOWERED;
201 on a single core, atomic and non-atomic exchange should both work
203 if we find our non-atomic test passes, then we can't really say anything
204 about whether or not the atomic test is really working
207 LFDS710_MISC_BARRIER_LOAD;
209 if( number_logical_processors == 1 )
211 if( exchange_success_flag == RAISED and atomic_exchange_success_flag == RAISED )
212 *dvs = LFDS710_MISC_VALIDITY_VALID;
214 if( exchange_success_flag != RAISED or atomic_exchange_success_flag != RAISED )
215 *dvs = LFDS710_MISC_VALIDITY_INVALID_ATOMIC_FAILED;
218 if( number_logical_processors >= 2 )
220 if( atomic_exchange_success_flag == RAISED and exchange_success_flag == LOWERED )
221 *dvs = LFDS710_MISC_VALIDITY_VALID;
223 if( atomic_exchange_success_flag == RAISED and exchange_success_flag == RAISED )
224 *dvs = LFDS710_MISC_VALIDITY_INDETERMINATE_NONATOMIC_PASSED;
226 if( atomic_exchange_success_flag == LOWERED )
227 *dvs = LFDS710_MISC_VALIDITY_INVALID_ATOMIC_FAILED;
237 /****************************************************************************/
238 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_exchange( void *libtest_threadset_per_thread_state )
244 struct test_per_thread_state
247 struct libtest_threadset_per_thread_state
250 LFDS710_MISC_BARRIER_LOAD;
252 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
254 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
255 tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
257 libtest_threadset_thread_ready_and_wait( pts );
259 local_counter = tpts->counter;
261 while( local_counter < tpts->number_elements_per_thread )
263 exchange = *tpts->shared_exchange;
264 *tpts->shared_exchange = local_counter;
266 ( *(tpts->counter_array + exchange) )++;
268 local_counter += tpts->number_logical_processors;
271 LFDS710_MISC_BARRIER_STORE;
273 lfds710_misc_force_store();
275 return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);
282 /****************************************************************************/
283 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_atomic_exchange( void *libtest_threadset_per_thread_state )
289 struct test_per_thread_state
292 struct libtest_threadset_per_thread_state
295 LFDS710_MISC_BARRIER_LOAD;
297 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
299 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
300 tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
302 libtest_threadset_thread_ready_and_wait( pts );
304 local_counter = tpts->counter;
306 while( local_counter < tpts->number_elements_per_thread )
308 exchange = local_counter;
310 LFDS710_PAL_ATOMIC_EXCHANGE( tpts->shared_exchange, exchange, lfds710_pal_uint_t );
312 // TRD : increment the original value in shared_exchange, which exchange has now been set to
313 ( *(tpts->counter_array + exchange) )++;
315 local_counter += (lfds710_pal_uint_t) tpts->number_logical_processors;
318 LFDS710_MISC_BARRIER_STORE;
320 lfds710_misc_force_store();
322 return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);