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