7 struct lfds700_btree_au_element
17 insert_existing_count,
20 struct lfds700_btree_au_state
27 /***** private prototypes *****/
28 static int key_compare_function( void const *new_value, void const *value_in_tree );
29 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state );
35 /****************************************************************************/
36 void test_lfds700_btree_au_random_adds_overwrite_on_existing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes )
38 enum lfds700_misc_validity
39 dvs = LFDS700_MISC_VALIDITY_VALID;
42 actual_sum_insert_existing_count,
43 expected_sum_insert_existing_count,
48 number_logical_processors,
52 struct lfds700_list_asu_element
55 struct lfds700_btree_au_element
58 struct lfds700_btree_au_state
61 struct lfds700_misc_prng_state
64 struct lfds700_misc_validation_info
67 struct test_pal_logical_processor
70 struct util_thread_starter_state
76 test_pal_thread_state_t
82 assert( list_of_logical_processors != NULL );
83 // TRD : memory_in_megabytes can be any value in its range
85 /* TRD : we create a single btree_au
86 we generate 10k elements per thread (one per logical processor) in an array
87 we set a random number in each element, which is the key
88 random numbers are generated are from 0 to 5000, so we must have some duplicates
89 (we don't use value, so we always pass in a NULL for that when we insert)
91 each thread loops, adds those elements into the btree, and counts the total number of insert fails
92 (we don't count on a per value basis because of the performance hit - we'll be TLBing all the time)
93 this test has the btree_au set to overwrite on add, so duplicates should be eliminated
95 we then merge the per-thread arrays
97 we should find in the tree one of every value, and the sum of the counts of each value (beyond the
98 first value, which was inserted) in the merged arrays should equal the sum of the existing_baues returned
99 from each thread when they inserted and found an existing element
101 we check the count of unique values in the merged array and use that when calling the btree_au validation function
103 we in-order walk and check that what we have in the tree matches what we have in the merged array
104 and then check the fail counts
107 internal_display_test_name( "Random adds and walking (overwrite on existing key)" );
109 lfds700_misc_prng_init( &ps );
111 lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
113 lfds700_btree_au_init_valid_on_current_logical_core( &baus, key_compare_function, LFDS700_BTREE_AU_EXISTING_KEY_OVERWRITE, NULL );
115 ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors );
116 number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors );
117 for( loop = 0 ; loop < number_logical_processors ; loop++ )
119 (ts+loop)->baus = &baus;
120 (ts+loop)->element_array = util_aligned_malloc( sizeof(struct test_element) * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES );
121 (ts+loop)->number_elements = number_elements;
122 (ts+loop)->insert_existing_count = 0;
124 for( subloop = 0 ; subloop < number_elements ; subloop++ )
126 random_value = LFDS700_MISC_PRNG_GENERATE( &ps );
127 ((ts+loop)->element_array+subloop)->key = (lfds700_pal_uint_t) floor( (number_elements/2) * ((double) random_value / (double) LFDS700_MISC_PRNG_MAX) );
131 thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors );
133 util_thread_starter_new( &tts, number_logical_processors );
135 LFDS700_MISC_BARRIER_STORE;
137 lfds700_misc_force_store();
142 while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) )
144 lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
145 util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_adding, ts+loop );
149 util_thread_starter_run( tts );
151 for( loop = 0 ; loop < number_logical_processors ; loop++ )
152 test_pal_thread_wait( thread_handles[loop] );
154 util_thread_starter_delete( tts );
156 free( thread_handles );
158 LFDS700_MISC_BARRIER_LOAD;
160 /* TRD : now for validation
161 make an array equal to number_elements, set all to 0
162 iterate over every per-thread array, counting the number of each value into this array
163 so we can know how many elements ought to have failed to be inserted
164 as well as being able to work out the actual number of elements which should be present in the btree, for the btree validation call
167 key_count_array = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_elements );
168 for( loop = 0 ; loop < number_elements ; loop++ )
169 *(key_count_array+loop) = 0;
171 for( loop = 0 ; loop < number_logical_processors ; loop++ )
172 for( subloop = 0 ; subloop < number_elements ; subloop++ )
173 ( *(key_count_array+( (ts+loop)->element_array+subloop)->key) )++;
175 // TRD : first, btree validation function
176 vi.min_elements = number_elements;
178 for( loop = 0 ; loop < number_elements ; loop++ )
179 if( *(key_count_array+loop) == 0 )
182 vi.max_elements = vi.min_elements;
184 lfds700_btree_au_query( &baus, LFDS700_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) &dvs );
186 /* TRD : now check the sum of per-thread insert failures
187 is what it should be, which is the sum of key_count_array,
188 but with every count minus one (for the single succesful insert)
189 and where elements of 0 are ignored (i.e. do not have -1 applied)
192 expected_sum_insert_existing_count = 0;
194 for( loop = 0 ; loop < number_elements ; loop++ )
195 if( *(key_count_array+loop) != 0 )
196 expected_sum_insert_existing_count += *(key_count_array+loop) - 1;
198 actual_sum_insert_existing_count = 0;
200 for( loop = 0 ; loop < number_logical_processors ; loop++ )
201 actual_sum_insert_existing_count += (ts+loop)->insert_existing_count;
203 if( expected_sum_insert_existing_count != actual_sum_insert_existing_count )
204 dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA;
206 /* TRD : now compared the combined array and an in-order walk of the tree
207 ignoring array elements with the value 0, we should find an exact match
210 if( dvs == LFDS700_MISC_VALIDITY_VALID )
212 // TRD : in-order walk over btree_au and check key_count_array matches
213 while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position(&baus, &baue, LFDS700_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE) )
215 key = LFDS700_BTREE_AU_GET_KEY_FROM_ELEMENT( *baue );
217 while( *(key_count_array+index) == 0 )
220 if( index++ != (lfds700_pal_uint_t) key )
221 dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA;
226 free( key_count_array );
228 lfds700_btree_au_cleanup( &baus, NULL );
231 for( loop = 0 ; loop < number_logical_processors ; loop++ )
232 util_aligned_free( (ts+loop)->element_array );
236 // TRD : print the test result
237 internal_display_test_result( 1, "btree_au", dvs );
246 /****************************************************************************/
247 #pragma warning( disable : 4100 )
249 static int key_compare_function( void const *new_key, void const *key_in_tree )
254 // TRD : key_new can be any value in its range
255 // TRD : key_in_tree can be any value in its range
257 if( (lfds700_pal_uint_t) new_key < (lfds700_pal_uint_t) key_in_tree )
260 if( (lfds700_pal_uint_t) new_key > (lfds700_pal_uint_t) key_in_tree )
266 #pragma warning( default : 4100 )
272 /****************************************************************************/
273 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state )
275 enum lfds700_btree_au_insert_result
284 struct lfds700_btree_au_element
287 struct lfds700_misc_prng_state
290 struct util_thread_starter_thread_state
293 LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
295 assert( util_thread_starter_thread_state != NULL );
297 tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
298 ts = (struct test_state *) tsts->thread_user_state;
300 lfds700_misc_prng_init( &ps );
302 util_thread_starter_ready_and_wait( tsts );
304 while( index < ts->number_elements )
306 LFDS700_BTREE_AU_SET_KEY_IN_ELEMENT( (ts->element_array+index)->baue, (ts->element_array+index)->key );
307 LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( (ts->element_array+index)->baue, 0 );
308 alr = lfds700_btree_au_insert( ts->baus, &(ts->element_array+index)->baue, &existing_baue, &ps );
310 if( alr == LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE )
311 ts->insert_existing_count++;
316 LFDS700_MISC_BARRIER_STORE;
318 lfds700_misc_force_store();
320 return( (test_pal_thread_return_t) EXIT_SUCCESS );