9 struct lfds700_freelist_state
17 *fs_thread_local_te_array;
22 struct lfds700_freelist_element
30 /***** private prototypes *****/
31 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_popping( void *util_thread_starter_thread_state );
32 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_pushing( void *util_thread_starter_thread_state );
38 /****************************************************************************/
39 void test_lfds700_freelist_popping_and_pushing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes )
41 enum lfds700_misc_validity
47 number_logical_processors,
50 struct lfds700_list_asu_element
53 struct lfds700_freelist_state
56 struct lfds700_misc_prng_state
59 struct lfds700_misc_validation_info
62 struct test_pal_logical_processor
65 struct util_thread_starter_state
74 test_pal_thread_state_t
77 assert( list_of_logical_processors != NULL );
78 // TRD : memory_in_megabytes can be any value in its range
80 /* TRD : we have two threads per CPU
81 the threads loop for ten seconds
82 the first thread pushes 10000 elements then pops 10000 elements
83 the second thread pops 10000 elements then pushes 10000 elements
84 all pushes and pops go onto the single main freelist
85 with a per-thread local freelist to store the pops
87 after time is up, all threads push what they have remaining onto
90 we then validate the main freelist
93 internal_display_test_name( "Popping and pushing (%d seconds)", TEST_DURATION_IN_SECONDS );
95 lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
97 lfds700_misc_prng_init( &ps );
99 number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors * 2 );
101 lfds700_freelist_init_valid_on_current_logical_core( &fs, NULL );
103 // TRD : we allocate half the total elements here, and half again later, which is why *2 above, but not here
104 te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements * number_logical_processors, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES );
106 // TRD : initial elements in the main freelist so the popping threads can start immediately
107 for( loop = 0 ; loop < number_elements * number_logical_processors ; loop++ )
109 (te_array+loop)->datum = loop;
110 LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( (te_array+loop)->fe, te_array+loop );
111 lfds700_freelist_push( &fs, &(te_array+loop)->fe, &ps );
114 ts = util_aligned_malloc( sizeof(struct test_state) * number_logical_processors * 2, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES );
116 for( loop = 0 ; loop < number_logical_processors ; loop++ )
118 // TRD : first set of threads (poppers)
120 (ts+loop)->number_elements = number_elements;
121 lfds700_freelist_init_valid_on_current_logical_core( &(ts+loop)->fs_thread_local, NULL );
123 // TRD : second set of threads (pushers - who need elements in their per-thread freelists)
124 (ts+loop+number_logical_processors)->fs = &fs;
125 (ts+loop+number_logical_processors)->number_elements = number_elements;
126 lfds700_freelist_init_valid_on_current_logical_core( &(ts+loop+number_logical_processors)->fs_thread_local, NULL );
128 // TRD : fill the pushing thread freelists
129 (ts+loop+number_logical_processors)->fs_thread_local_te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES );
131 for( subloop = 0 ; subloop < number_elements ; subloop++ )
133 ((ts+loop+number_logical_processors)->fs_thread_local_te_array+subloop)->datum = loop;
134 LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( ((ts+loop+number_logical_processors)->fs_thread_local_te_array+subloop)->thread_local_fe, (ts+loop+number_logical_processors)->fs_thread_local_te_array+subloop );
135 lfds700_freelist_push( &(ts+loop+number_logical_processors)->fs_thread_local, &((ts+loop+number_logical_processors)->fs_thread_local_te_array+subloop)->thread_local_fe, &ps );
139 thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors * 2 );
141 util_thread_starter_new( &tts, number_logical_processors * 2 );
143 LFDS700_MISC_BARRIER_STORE;
145 lfds700_misc_force_store();
150 while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) )
152 lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
153 util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_popping_and_pushing_start_popping, ts+loop );
154 util_thread_starter_start( tts, &thread_handles[loop+number_logical_processors], loop+number_logical_processors, lp, thread_popping_and_pushing_start_pushing, ts+loop+number_logical_processors );
158 util_thread_starter_run( tts );
160 for( loop = 0 ; loop < number_logical_processors * 2 ; loop++ )
161 test_pal_thread_wait( thread_handles[loop] );
163 util_thread_starter_delete( tts );
165 free( thread_handles );
167 LFDS700_MISC_BARRIER_LOAD;
169 vi.min_elements = vi.max_elements = number_elements * number_logical_processors * 2;
171 lfds700_freelist_query( &fs, LFDS700_FREELIST_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) &dvs );
173 lfds700_freelist_cleanup( &fs, NULL );
175 for( loop = 0 ; loop < number_logical_processors ; loop++ )
177 lfds700_freelist_cleanup( &(ts+loop)->fs_thread_local, NULL );
178 lfds700_freelist_cleanup( &(ts+loop+number_logical_processors)->fs_thread_local, NULL );
179 util_aligned_free( (ts+loop+number_logical_processors)->fs_thread_local_te_array );
182 util_aligned_free( ts );
184 util_aligned_free( te_array );
186 // TRD : print the test result
187 internal_display_test_result( 1, "freelist", dvs );
197 /****************************************************************************/
198 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_popping( void *util_thread_starter_thread_state )
203 struct lfds700_freelist_element
206 struct lfds700_misc_prng_state
209 struct util_thread_starter_thread_state
218 LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
220 assert( util_thread_starter_thread_state != NULL );
222 tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
223 ts = (struct test_state *) tsts->thread_user_state;
225 lfds700_misc_prng_init( &ps );
227 util_thread_starter_ready_and_wait( tsts );
229 start_time = time( NULL );
231 while( time(NULL) < start_time + TEST_DURATION_IN_SECONDS )
235 while( count < ts->number_elements )
236 if( lfds700_freelist_pop(ts->fs, &fe, &ps) )
238 // TRD : we do nothing with the test data, so there'ss no GET or SET here
239 lfds700_freelist_push( &ts->fs_thread_local, fe, &ps );
243 // TRD : return our local freelist to the main freelist
244 while( lfds700_freelist_pop(&ts->fs_thread_local, &fe, &ps) )
245 lfds700_freelist_push( ts->fs, fe, &ps );
248 LFDS700_MISC_BARRIER_STORE;
250 lfds700_misc_force_store();
252 return( (test_pal_thread_return_t) EXIT_SUCCESS );
259 /****************************************************************************/
260 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_pushing( void *util_thread_starter_thread_state )
265 struct lfds700_freelist_element
268 struct lfds700_misc_prng_state
274 struct util_thread_starter_thread_state
280 LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
282 assert( util_thread_starter_thread_state != NULL );
284 tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
285 ts = (struct test_state *) tsts->thread_user_state;
287 lfds700_misc_prng_init( &ps );
289 util_thread_starter_ready_and_wait( tsts );
291 start_time = time( NULL );
293 while( time(NULL) < start_time + TEST_DURATION_IN_SECONDS )
295 // TRD : return our local freelist to the main freelist
296 while( lfds700_freelist_pop(&ts->fs_thread_local, &fe, &ps) )
297 lfds700_freelist_push( ts->fs, fe, &ps );
301 while( count < ts->number_elements )
302 if( lfds700_freelist_pop(ts->fs, &fe, &ps) )
304 lfds700_freelist_push( &ts->fs_thread_local, fe, &ps );
309 // TRD : now push whatever we have in our local freelist
310 while( lfds700_freelist_pop(&ts->fs_thread_local, &fe, &ps) )
311 lfds700_freelist_push( ts->fs, fe, &ps );
313 LFDS700_MISC_BARRIER_STORE;
315 lfds700_misc_force_store();
317 return( (test_pal_thread_return_t) EXIT_SUCCESS );