]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.1.0/test_and_benchmark/libtest/src/libtest_tests/libtest_tests_porting_abstraction_layer_atomic_exchange.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.1.0 / test_and_benchmark / libtest / src / libtest_tests / libtest_tests_porting_abstraction_layer_atomic_exchange.c
1 /***** includes *****/
2 #include "libtest_tests_internal.h"
3
4 /***** structs *****/
5 struct test_per_thread_state
6 {
7   lfds710_pal_uint_t
8     counter,
9     *counter_array,
10     number_elements_per_thread,
11     number_logical_processors;
12
13   lfds710_pal_uint_t volatile
14     *shared_exchange;
15 };
16
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 );
20
21
22
23
24
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 )
27 {
28   enum flag
29     atomic_exchange_success_flag = RAISED,
30     exchange_success_flag = RAISED;
31
32   lfds710_pal_uint_t
33     loop,
34     *merged_counter_arrays,
35     number_elements,
36     number_elements_per_thread,
37     number_logical_processors,
38     subloop;
39
40   lfds710_pal_uint_t volatile LFDS710_PAL_ALIGN(LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES)
41     exchange = 0;
42
43   struct lfds710_list_asu_element
44     *lasue = NULL;
45
46   struct libtest_logical_processor
47     *lp;
48
49   struct libtest_threadset_per_thread_state
50     *pts;
51
52   struct libtest_threadset_state
53     ts;
54
55   struct test_per_thread_state
56     *tpts;
57
58   LFDS710_PAL_ASSERT( list_of_logical_processors != NULL );
59   LFDS710_PAL_ASSERT( ms != NULL );
60   LFDS710_PAL_ASSERT( dvs != NULL );
61
62   /* TRD : here we test pal_atomic_exchange
63
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)
70
71            there is an array per thread of 1 million elements, each a counter, set to 0
72
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
77
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)
80
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
83
84            we perform the test twice, once with pal_atomic_exchange, once with a non-atomic exchange
85
86            we expect the atomic to pass and the non-atomic to fail
87   */
88
89   *dvs = LFDS710_MISC_VALIDITY_VALID;
90
91   // TRD : allocate
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 );
96
97   /* TRD : one array per thread, one array for merging
98            +1 as we need store for a merged counter array
99   */
100
101   number_elements_per_thread = number_elements / (number_logical_processors+1);
102
103   // TRD : non-atomic
104
105   for( loop = 0 ; loop < number_elements_per_thread ; loop++ )
106     *(merged_counter_arrays+loop) = 0;
107
108   libtest_threadset_init( &ts, NULL );
109
110   loop = 0;
111
112   while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors,lasue) )
113   {
114     lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
115
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;
124
125     libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_exchange, &tpts[loop] );
126
127     loop++;
128   }
129
130   LFDS710_MISC_BARRIER_STORE;
131
132   lfds710_misc_force_store();
133
134   // TRD : run the test
135   libtest_threadset_run( &ts );
136   libtest_threadset_cleanup( &ts );
137
138   // TRD : validate
139   LFDS710_MISC_BARRIER_LOAD;
140
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 );
144
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
150   */
151
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;
155
156   // TRD : now for atomic exchange - we need to re-init the data structures
157
158   for( loop = 0 ; loop < number_elements_per_thread ; loop++ )
159     *(merged_counter_arrays+loop) = 0;
160
161   libtest_threadset_init( &ts, NULL );
162
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;
166
167   loop = 0;
168   lasue = NULL;
169
170   while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors,lasue) )
171   {
172     lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
173
174     libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_atomic_exchange, &tpts[loop] );
175     loop++;
176   }
177
178   exchange = 0;
179
180   LFDS710_MISC_BARRIER_STORE;
181
182   lfds710_misc_force_store();
183
184   libtest_threadset_run( &ts );
185
186   libtest_threadset_cleanup( &ts );
187
188   // TRD : validate
189   LFDS710_MISC_BARRIER_LOAD;
190
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 );
194
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;
198
199   /* TRD : results
200
201            on a single core, atomic and non-atomic exchange should both work
202
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
205   */
206
207   LFDS710_MISC_BARRIER_LOAD;
208
209   if( number_logical_processors == 1 )
210   {
211     if( exchange_success_flag == RAISED and atomic_exchange_success_flag == RAISED )
212       *dvs = LFDS710_MISC_VALIDITY_VALID;
213
214     if( exchange_success_flag != RAISED or atomic_exchange_success_flag != RAISED )
215       *dvs = LFDS710_MISC_VALIDITY_INVALID_ATOMIC_FAILED;
216   }
217
218   if( number_logical_processors >= 2 )
219   {
220     if( atomic_exchange_success_flag == RAISED and exchange_success_flag == LOWERED )
221       *dvs = LFDS710_MISC_VALIDITY_VALID;
222
223     if( atomic_exchange_success_flag == RAISED and exchange_success_flag == RAISED )
224       *dvs = LFDS710_MISC_VALIDITY_INDETERMINATE_NONATOMIC_PASSED;
225
226     if( atomic_exchange_success_flag == LOWERED )
227       *dvs = LFDS710_MISC_VALIDITY_INVALID_ATOMIC_FAILED;
228   }
229
230   return;
231 }
232
233
234
235
236
237 /****************************************************************************/
238 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_exchange( void *libtest_threadset_per_thread_state )
239 {
240   lfds710_pal_uint_t
241     local_counter,
242     exchange;
243
244   struct test_per_thread_state
245     *tpts;
246
247   struct libtest_threadset_per_thread_state
248     *pts;
249
250   LFDS710_MISC_BARRIER_LOAD;
251
252   LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
253
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 );
256
257   libtest_threadset_thread_ready_and_wait( pts );
258
259   local_counter = tpts->counter;
260
261   while( local_counter < tpts->number_elements_per_thread )
262   {
263     exchange = *tpts->shared_exchange;
264     *tpts->shared_exchange = local_counter;
265
266     ( *(tpts->counter_array + exchange) )++;
267
268     local_counter += tpts->number_logical_processors;
269   }
270
271   LFDS710_MISC_BARRIER_STORE;
272
273   lfds710_misc_force_store();
274
275   return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);
276 }
277
278
279
280
281
282 /****************************************************************************/
283 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_atomic_exchange( void *libtest_threadset_per_thread_state )
284 {
285   lfds710_pal_uint_t
286     local_counter,
287     exchange;
288
289   struct test_per_thread_state
290     *tpts;
291
292   struct libtest_threadset_per_thread_state
293     *pts;
294
295   LFDS710_MISC_BARRIER_LOAD;
296
297   LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
298
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 );
301
302   libtest_threadset_thread_ready_and_wait( pts );
303
304   local_counter = tpts->counter;
305
306   while( local_counter < tpts->number_elements_per_thread )
307   {
308     exchange = local_counter;
309
310     LFDS710_PAL_ATOMIC_EXCHANGE( tpts->shared_exchange, exchange, lfds710_pal_uint_t );
311
312     // TRD : increment the original value in shared_exchange, which exchange has now been set to
313     ( *(tpts->counter_array + exchange) )++;
314
315     local_counter += (lfds710_pal_uint_t) tpts->number_logical_processors;
316   }
317
318   LFDS710_MISC_BARRIER_STORE;
319
320   lfds710_misc_force_store();
321
322   return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);
323 }
324