]> pd.if.org Git - liblfds/blob - liblfds/liblfds6.0.0/test/src/test_abstraction.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds6.0.0 / test / src / test_abstraction.c
1 #include "internal.h"
2
3
4
5
6
7 /****************************************************************************/
8 void test_lfds600_abstraction( void )
9 {
10   printf( "\n"
11           "Abstraction Tests\n"
12           "=================\n" );
13
14   abstraction_test_increment();
15   abstraction_test_dcas();
16
17   return;
18 }
19
20
21
22
23
24 /****************************************************************************/
25 void abstraction_test_increment( void )
26 {
27   unsigned int
28     loop,
29     cpu_count;
30
31   thread_state_t
32     *thread_handles;
33
34   lfds600_atom_t
35     shared_counter = 0,
36     atomic_shared_counter = 0;
37
38   /* TRD : here we test lfds600_abstraction_increment
39
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 "++"
43
44            second, we repeat the exercise, but this time using
45            lfds600_abstraction_increment()
46
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
50            that it works
51
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
54
55            and of course if the final value in the atomic test is wrong, we know things
56            are broken
57   */
58
59   internal_display_test_name( "Atomic increment" );
60
61   cpu_count = abstraction_cpu_count();
62
63   thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
64
65   // TRD : non-atomic
66   for( loop = 0 ; loop < cpu_count ; loop++ )
67     abstraction_thread_start( &thread_handles[loop], loop, abstraction_test_internal_thread_increment, &shared_counter );
68
69   for( loop = 0 ; loop < cpu_count ; loop++ )
70     abstraction_thread_wait( thread_handles[loop] );
71
72   // TRD : atomic
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 );
75
76   for( loop = 0 ; loop < cpu_count ; loop++ )
77     abstraction_thread_wait( thread_handles[loop] );
78
79   free( thread_handles );
80
81   // TRD : results
82   if( shared_counter < (10000000 * cpu_count) and atomic_shared_counter == (10000000 * cpu_count) )
83     puts( "passed" );
84
85   if( shared_counter == (10000000 * cpu_count) and atomic_shared_counter == (10000000 * cpu_count) )
86     puts( "indeterminate" );
87
88   if( atomic_shared_counter < (10000000 * cpu_count) )
89     puts( "failed" );
90
91   return;
92 }
93
94
95
96
97
98 /****************************************************************************/
99 thread_return_t CALLING_CONVENTION abstraction_test_internal_thread_increment( void *shared_counter )
100 {
101   volatile lfds600_atom_t
102     count = 0;
103
104   /* TRD : lfds600_atom_t must be volatile or the compiler
105            optimizes it away into a single store
106   */
107
108   assert( shared_counter != NULL );
109
110   while( count++ < 10000000 )
111     (*(lfds600_atom_t *) shared_counter)++;
112
113   return( (thread_return_t) EXIT_SUCCESS );
114 }
115
116
117
118
119
120 /****************************************************************************/
121 thread_return_t CALLING_CONVENTION abstraction_test_internal_thread_atomic_increment( void *shared_counter )
122 {
123   lfds600_atom_t
124     count = 0;
125
126   assert( shared_counter != NULL );
127
128   while( count++ < 10000000 )
129     lfds600_abstraction_increment( shared_counter );
130
131   return( (thread_return_t) EXIT_SUCCESS );
132 }
133
134
135
136
137
138 /****************************************************************************/
139 void abstraction_test_dcas( void )
140 {
141   unsigned int
142     loop,
143     cpu_count;
144
145   thread_state_t
146     *thread_handles;
147
148   struct abstraction_test_dcas_state
149     *atds;
150
151   LFDS600_ALIGN(LFDS600_ALIGN_DOUBLE_POINTER) volatile lfds600_atom_t
152     shared_counter[2] = { 0, 0 };
153
154   lfds600_atom_t
155     local_total = 0;
156
157   /* TRD : here we test lfds600_abstraction_dcas
158
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
166   */
167
168   internal_display_test_name( "Atomic DCAS" );
169
170   cpu_count = abstraction_cpu_count();
171
172   atds = malloc( sizeof(struct abstraction_test_dcas_state) * cpu_count );
173
174   for( loop = 0 ; loop < cpu_count ; loop++ )
175   {
176     (atds+loop)->shared_counter = shared_counter;
177     (atds+loop)->local_counter = 0;
178   }
179
180   thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
181
182   for( loop = 0 ; loop < cpu_count ; loop++ )
183     abstraction_thread_start( &thread_handles[loop], loop, abstraction_test_internal_thread_dcas, atds+loop );
184
185   for( loop = 0 ; loop < cpu_count ; loop++ )
186     abstraction_thread_wait( thread_handles[loop] );
187
188   free( thread_handles );
189
190   // TRD : results
191   for( loop = 0 ; loop < cpu_count ; loop++ )
192     local_total += (atds+loop)->local_counter;
193
194   if( local_total == shared_counter[0] )
195     puts( "passed" );
196
197   if( local_total != shared_counter[0] )
198     puts( "failed" );
199
200   // TRD : cleanup
201   free( atds );
202
203   return;
204 }
205
206
207
208
209
210 /****************************************************************************/
211 thread_return_t CALLING_CONVENTION abstraction_test_internal_thread_dcas( void *abstraction_test_dcas_state )
212 {
213   struct abstraction_test_dcas_state
214     *atds;
215
216   time_t
217     start_time;
218
219   LFDS600_ALIGN(LFDS600_ALIGN_DOUBLE_POINTER) lfds600_atom_t
220     exchange[2],
221     compare[2];
222
223   assert( abstraction_test_dcas_state != NULL );
224
225   atds = (struct abstraction_test_dcas_state *) abstraction_test_dcas_state;
226
227   time( &start_time );
228
229   while( time(NULL) < start_time + 10 )
230   {
231     compare[0] = *atds->shared_counter;
232     compare[1] = *(atds->shared_counter+1);
233
234     do
235     {
236       exchange[0] = compare[0] + 1;
237       exchange[1] = compare[1];
238     }
239     while( 0 == lfds600_abstraction_dcas(atds->shared_counter, exchange, compare) );
240
241     atds->local_counter++;
242   }
243
244   return( (thread_return_t) EXIT_SUCCESS );
245 }
246