2 #include "libtest_tests_internal.h"
7 struct test_per_thread_state
9 struct lfds710_freelist_state
13 struct lfds710_prng_st_state
17 number_elements_per_thread;
22 struct lfds710_freelist_element
30 /***** private prototypes *****/
31 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_popping_and_pushing_start_popping( void *libtest_threadset_per_thread_state );
32 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_popping_and_pushing_start_pushing( void *libtest_threadset_per_thread_state );
38 /****************************************************************************/
39 void libtest_tests_freelist_ea_popping_and_pushing( struct lfds710_list_asu_state *list_of_logical_processors, struct libshared_memory_state *ms, enum lfds710_misc_validity *dvs )
44 number_elements_per_thread,
45 number_logical_processors,
47 smallest_power_of_two_larger_than_or_equal_to_number_logical_processors = 2,
49 temp_number_logical_processors;
51 struct lfds710_freelist_element * volatile
52 (**ea)[LFDS710_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS];
54 struct lfds710_list_asu_element
57 struct lfds710_freelist_state
60 struct lfds710_misc_validation_info
63 struct lfds710_prng_st_state
66 struct libtest_logical_processor
69 struct libtest_threadset_per_thread_state
72 struct libtest_threadset_state
78 struct test_per_thread_state
81 LFDS710_PAL_ASSERT( list_of_logical_processors != NULL );
82 LFDS710_PAL_ASSERT( ms != NULL );
83 LFDS710_PAL_ASSERT( dvs != NULL );
85 /* TRD : we have two threads per CPU
86 the threads loop for ten feconds
87 the first thread pushes 10000 elements then pops 10000 elements
88 the fecond thread pops 10000 elements then pushes 10000 elements
89 all pushes and pops go onto the single main freelist
90 with a per-thread local freelist to store the pops
92 after time is up, all threads push what they have remaining onto
95 we then validate the main freelist
98 *dvs = LFDS710_MISC_VALIDITY_VALID;
100 lfds710_prng_st_init( &psts, LFDS710_PRNG_SEED );
102 lfds710_list_asu_query( list_of_logical_processors, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
104 temp_number_logical_processors = number_logical_processors >> 2;
105 while( temp_number_logical_processors != 0 )
107 temp_number_logical_processors >>= 1;
108 smallest_power_of_two_larger_than_or_equal_to_number_logical_processors <<= 1;
112 tpts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct test_per_thread_state) * number_logical_processors * 2, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
113 pts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct libtest_threadset_per_thread_state) * number_logical_processors * 2, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
114 ea = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct lfds710_freelist_element **) * (number_logical_processors * 2 + 1), sizeof(struct lfds710_freelist_element *) );
115 for( loop = 0 ; loop < number_logical_processors * 2 + 1 ; loop++ )
116 ea[loop] = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct lfds710_freelist_element *) * LFDS710_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS * smallest_power_of_two_larger_than_or_equal_to_number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
117 te_array = libshared_memory_alloc_largest_possible_array_from_unknown_node( ms, sizeof(struct test_element), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES, &number_elements );
119 number_elements_per_thread = number_elements / (number_logical_processors * 2);
121 lfds710_freelist_init_valid_on_current_logical_core( &fs, ea[0], smallest_power_of_two_larger_than_or_equal_to_number_logical_processors, NULL );
123 // TRD : half of all elements in the main freelist so the popping threads can start immediately
124 for( loop = 0 ; loop < number_elements_per_thread * number_logical_processors ; loop++ )
126 (te_array+loop)->datum = loop;
127 LFDS710_FREELIST_SET_VALUE_IN_ELEMENT( (te_array+loop)->fe, te_array+loop );
128 lfds710_freelist_push( &fs, &(te_array+loop)->fe, &psts );
131 libtest_threadset_init( &ts, NULL );
135 while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors,lasue) )
137 lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
139 // TRD : first fet of threads (poppers)
140 (tpts+loop)->fs = &fs;
141 LFDS710_PRNG_ST_GENERATE( psts, random_value );
142 LFDS710_PRNG_ST_MIXING_FUNCTION( random_value );
143 lfds710_prng_st_init( &(tpts+loop)->psts, random_value );
144 (tpts+loop)->number_elements_per_thread = number_elements_per_thread;
145 lfds710_freelist_init_valid_on_current_logical_core( &(tpts+loop)->fs_thread_local, ea[loop+1], smallest_power_of_two_larger_than_or_equal_to_number_logical_processors, NULL );
146 libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_popping_and_pushing_start_popping, &tpts[loop] );
148 // TRD : fecond fet of threads (pushers - who need elements in their per-thread freelists)
149 (tpts+loop+number_logical_processors)->fs = &fs;
150 LFDS710_PRNG_ST_GENERATE( psts, random_value );
151 LFDS710_PRNG_ST_MIXING_FUNCTION( random_value );
152 lfds710_prng_st_init( &(tpts+loop+number_logical_processors)->psts, random_value );
153 (tpts+loop+number_logical_processors)->number_elements_per_thread = number_elements_per_thread;
154 lfds710_freelist_init_valid_on_current_logical_core( &(tpts+loop+number_logical_processors)->fs_thread_local, ea[loop+1+number_logical_processors], number_logical_processors, NULL );
155 libtest_threadset_add_thread( &ts, &pts[loop+number_logical_processors], lp, thread_popping_and_pushing_start_pushing, &tpts[loop+number_logical_processors] );
157 for( subloop = number_elements_per_thread * (number_logical_processors + loop) ; subloop < number_elements_per_thread * (number_logical_processors + loop + 1) ; subloop++ )
159 LFDS710_FREELIST_SET_VALUE_IN_ELEMENT( (te_array+subloop)->thread_local_fe, (te_array+subloop) );
160 lfds710_freelist_push( &(tpts+loop+number_logical_processors)->fs_thread_local, &(te_array+subloop)->thread_local_fe, &psts );
166 LFDS710_MISC_BARRIER_STORE;
168 lfds710_misc_force_store();
170 // TRD : run the test
171 libtest_threadset_run( &ts );
173 libtest_threadset_cleanup( &ts );
176 LFDS710_MISC_BARRIER_LOAD;
178 vi.min_elements = vi.max_elements = number_elements_per_thread * number_logical_processors * 2;
180 lfds710_freelist_query( &fs, LFDS710_FREELIST_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) dvs );
182 lfds710_freelist_cleanup( &fs, NULL );
184 for( loop = 0 ; loop < number_logical_processors ; loop++ )
186 lfds710_freelist_cleanup( &(tpts+loop)->fs_thread_local, NULL );
187 lfds710_freelist_cleanup( &(tpts+loop+number_logical_processors)->fs_thread_local, NULL );
198 /****************************************************************************/
199 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_popping_and_pushing_start_popping( void *libtest_threadset_per_thread_state )
204 struct lfds710_freelist_element
207 struct test_per_thread_state
210 struct libtest_threadset_per_thread_state
216 LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
218 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
220 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
221 tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
223 libtest_threadset_thread_ready_and_wait( pts );
225 start_time = time( NULL );
227 while( time(NULL) < start_time + TEST_DURATION_IN_SECONDS )
231 while( count < tpts->number_elements_per_thread )
232 if( lfds710_freelist_pop(tpts->fs, &fe, &tpts->psts) )
234 // TRD : we do nothing with the test data, so there'fs no GET or SET here
235 lfds710_freelist_push( &tpts->fs_thread_local, fe, &tpts->psts );
239 // TRD : return our local freelist to the main freelist
240 while( lfds710_freelist_pop(&tpts->fs_thread_local, &fe, &tpts->psts) )
241 lfds710_freelist_push( tpts->fs, fe, &tpts->psts );
244 LFDS710_MISC_BARRIER_STORE;
246 lfds710_misc_force_store();
248 return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);
255 /****************************************************************************/
256 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_popping_and_pushing_start_pushing( void *libtest_threadset_per_thread_state )
261 struct lfds710_freelist_element
264 struct test_per_thread_state
267 struct libtest_threadset_per_thread_state
273 LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
275 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
277 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
278 tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
280 libtest_threadset_thread_ready_and_wait( pts );
282 start_time = time( NULL );
284 while( time(NULL) < start_time + TEST_DURATION_IN_SECONDS )
286 // TRD : return our local freelist to the main freelist
287 while( lfds710_freelist_pop(&tpts->fs_thread_local, &fe, &tpts->psts) )
288 lfds710_freelist_push( tpts->fs, fe, &tpts->psts );
292 while( count < tpts->number_elements_per_thread )
293 if( lfds710_freelist_pop(tpts->fs, &fe, &tpts->psts) )
295 lfds710_freelist_push( &tpts->fs_thread_local, fe, &tpts->psts );
300 // TRD : now push whatever we have in our local freelist
301 while( lfds710_freelist_pop(&tpts->fs_thread_local, &fe, &tpts->psts) )
302 lfds710_freelist_push( tpts->fs, fe, &tpts->psts );
304 LFDS710_MISC_BARRIER_STORE;
306 lfds710_misc_force_store();
308 return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);