7 /****************************************************************************/
8 void test_lfds600_abstraction( void )
12 "=================\n" );
14 abstraction_test_increment();
15 abstraction_test_dcas();
24 /****************************************************************************/
25 void abstraction_test_increment( void )
36 atomic_shared_counter = 0;
38 /* TRD : here we test lfds600_abstraction_increment
40 first, we run one thread per CPU where each thread increments
41 a shared counter 10,000,000 times - however, this first test
42 does NOT use atomic increment; it uses "++"
44 second, we repeat the exercise, but this time using
45 lfds600_abstraction_increment()
47 if the final value in the first test is less than (10,000,000*cpu_count)
48 then the system is sensitive to non-atomic increments; this means if
49 our atomic version of the test passes, we can have some degree of confidence
52 if the final value in the first test is in fact correct, then we can't know
53 that our atomic version has changed anything
55 and of course if the final value in the atomic test is wrong, we know things
59 internal_display_test_name( "Atomic increment" );
61 cpu_count = abstraction_cpu_count();
63 thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
66 for( loop = 0 ; loop < cpu_count ; loop++ )
67 abstraction_thread_start( &thread_handles[loop], loop, abstraction_test_internal_thread_increment, &shared_counter );
69 for( loop = 0 ; loop < cpu_count ; loop++ )
70 abstraction_thread_wait( thread_handles[loop] );
73 for( loop = 0 ; loop < cpu_count ; loop++ )
74 abstraction_thread_start( &thread_handles[loop], loop, abstraction_test_internal_thread_atomic_increment, &atomic_shared_counter );
76 for( loop = 0 ; loop < cpu_count ; loop++ )
77 abstraction_thread_wait( thread_handles[loop] );
79 free( thread_handles );
82 if( shared_counter < (10000000 * cpu_count) and atomic_shared_counter == (10000000 * cpu_count) )
85 if( shared_counter == (10000000 * cpu_count) and atomic_shared_counter == (10000000 * cpu_count) )
86 puts( "indeterminate" );
88 if( atomic_shared_counter < (10000000 * cpu_count) )
98 /****************************************************************************/
99 thread_return_t CALLING_CONVENTION abstraction_test_internal_thread_increment( void *shared_counter )
101 volatile lfds600_atom_t
104 /* TRD : lfds600_atom_t must be volatile or the compiler
105 optimizes it away into a single store
108 assert( shared_counter != NULL );
110 while( count++ < 10000000 )
111 (*(lfds600_atom_t *) shared_counter)++;
113 return( (thread_return_t) EXIT_SUCCESS );
120 /****************************************************************************/
121 thread_return_t CALLING_CONVENTION abstraction_test_internal_thread_atomic_increment( void *shared_counter )
126 assert( shared_counter != NULL );
128 while( count++ < 10000000 )
129 lfds600_abstraction_increment( shared_counter );
131 return( (thread_return_t) EXIT_SUCCESS );
138 /****************************************************************************/
139 void abstraction_test_dcas( void )
148 struct abstraction_test_dcas_state
151 LFDS600_ALIGN(LFDS600_ALIGN_DOUBLE_POINTER) volatile lfds600_atom_t
152 shared_counter[2] = { 0, 0 };
157 /* TRD : here we test lfds600_abstraction_dcas
159 we run one thread per CPU
160 we use lfds600_abstraction_dcas() to increment a shared counter
161 every time a thread successfully increments the counter,
162 it increments a thread local counter
163 the threads run for ten seconds
164 after the threads finish, we total the local counters
165 they should equal the shared counter
168 internal_display_test_name( "Atomic DCAS" );
170 cpu_count = abstraction_cpu_count();
172 atds = malloc( sizeof(struct abstraction_test_dcas_state) * cpu_count );
174 for( loop = 0 ; loop < cpu_count ; loop++ )
176 (atds+loop)->shared_counter = shared_counter;
177 (atds+loop)->local_counter = 0;
180 thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
182 for( loop = 0 ; loop < cpu_count ; loop++ )
183 abstraction_thread_start( &thread_handles[loop], loop, abstraction_test_internal_thread_dcas, atds+loop );
185 for( loop = 0 ; loop < cpu_count ; loop++ )
186 abstraction_thread_wait( thread_handles[loop] );
188 free( thread_handles );
191 for( loop = 0 ; loop < cpu_count ; loop++ )
192 local_total += (atds+loop)->local_counter;
194 if( local_total == shared_counter[0] )
197 if( local_total != shared_counter[0] )
210 /****************************************************************************/
211 thread_return_t CALLING_CONVENTION abstraction_test_internal_thread_dcas( void *abstraction_test_dcas_state )
213 struct abstraction_test_dcas_state
219 LFDS600_ALIGN(LFDS600_ALIGN_DOUBLE_POINTER) lfds600_atom_t
223 assert( abstraction_test_dcas_state != NULL );
225 atds = (struct abstraction_test_dcas_state *) abstraction_test_dcas_state;
229 while( time(NULL) < start_time + 10 )
231 compare[0] = *atds->shared_counter;
232 compare[1] = *(atds->shared_counter+1);
236 exchange[0] = compare[0] + 1;
237 exchange[1] = compare[1];
239 while( 0 == lfds600_abstraction_dcas(atds->shared_counter, exchange, compare) );
241 atds->local_counter++;
244 return( (thread_return_t) EXIT_SUCCESS );