2 #include "libtest_tests_internal.h"
7 struct lfds710_hash_a_element
15 struct test_per_thread_state
21 number_elements_per_thread;
23 struct lfds710_hash_a_state
30 /***** private prototypes *****/
31 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_adding( void *libtest_threadset_per_thread_state );
32 static int key_compare_function( void const *new_key, void const *existing_key );
33 static void key_hash_function( void const *key, lfds710_pal_uint_t *hash );
39 /****************************************************************************/
40 void libtest_tests_hash_a_random_adds_fail_on_existing( 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_elements_total,
46 number_logical_processors,
51 struct lfds710_hash_a_element
54 struct lfds710_hash_a_state
57 struct lfds710_list_asu_element
60 struct lfds710_btree_au_state
63 struct lfds710_prng_state
66 struct lfds710_misc_validation_info
69 struct libtest_logical_processor
72 struct libtest_threadset_per_thread_state
75 struct libtest_threadset_state
81 struct test_per_thread_state
84 LFDS710_PAL_ASSERT( list_of_logical_processors != NULL );
85 LFDS710_PAL_ASSERT( ms != NULL );
86 LFDS710_PAL_ASSERT( dvs != NULL );
88 /* TRD : we create a single hash_a
89 we generate 100k elements per thread (with one thread per logical processor) in an array
90 each element is unique
91 we randomly sort the elements
92 then each thread loops, adds those elements into the hash_a
93 we check that each datum inserts okay - failure will occur on non-unique data, i.e. two identical keys
94 we should have no failures
95 we then call the hash_a validation function
96 then using the hash_a get() we check all the elements we added are present
99 *dvs = LFDS710_MISC_VALIDITY_VALID;
102 lfds710_list_asu_query( list_of_logical_processors, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
103 tpts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct test_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
104 pts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct libtest_threadset_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
105 baus = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct lfds710_btree_au_state) * 1000, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
106 element_array = libshared_memory_alloc_largest_possible_array_from_unknown_node( ms, sizeof(struct test_element), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES, &number_elements_total );
108 // TRD : for correct rounding, for later code
109 number_elements_per_thread = number_elements_total / number_logical_processors;
110 number_elements_total = number_elements_per_thread * number_logical_processors;
112 lfds710_prng_init_valid_on_current_logical_core( &ps, LFDS710_PRNG_SEED );
114 lfds710_hash_a_init_valid_on_current_logical_core( &has, baus, 1000, key_compare_function, key_hash_function, LFDS710_HASH_A_EXISTING_KEY_FAIL, NULL );
116 // TRD : created an ordered list of unique numbers
117 for( loop = 0 ; loop < number_elements_total ; loop++ )
119 (element_array+loop)->key = loop;
120 // TRD : + number_elements just to make it different to the key
121 (element_array+loop)->datum = loop + number_elements_total;
124 // TRD : now randomize them
125 for( loop = 0 ; loop < number_elements_total ; loop++ )
127 LFDS710_PRNG_GENERATE( ps, offset );
128 offset %= number_elements_total;
129 temp = (element_array + offset)->key;
130 (element_array + offset)->key = (element_array + loop)->key;
131 (element_array + loop)->key = temp;
134 // TRD : get the threads ready
135 libtest_threadset_init( &ts, NULL );
139 while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors,lasue) )
141 lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
142 (tpts+loop)->has = &has;
143 (tpts+loop)->element_array = element_array + number_elements_per_thread*loop;
144 (tpts+loop)->error_flag = LOWERED;
145 (tpts+loop)->number_elements_per_thread = number_elements_per_thread;
146 libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_adding, &tpts[loop] );
150 LFDS710_MISC_BARRIER_STORE;
152 lfds710_misc_force_store();
154 // TRD : run the test
155 libtest_threadset_run( &ts );
157 libtest_threadset_cleanup( &ts );
160 LFDS710_MISC_BARRIER_LOAD;
162 // TRD : now for validation
163 vi.min_elements = vi.max_elements = number_elements_total;
164 lfds710_hash_a_query( &has, LFDS710_HASH_A_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) dvs );
166 /* TRD : now we attempt to lfds710_hash_a_get_by_key() for every element in number_array
167 any failure to find is an error
168 we also check we've obtained the correct element
171 for( loop = 0 ; *dvs == LFDS710_MISC_VALIDITY_VALID and loop < number_elements_total ; loop++ )
172 if( 0 == lfds710_hash_a_get_by_key(&has, NULL, NULL, (void *) (tpts->element_array+loop)->key, &hae) )
173 *dvs = LFDS710_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;
176 value = (lfds710_pal_uint_t) LFDS710_HASH_A_GET_VALUE_FROM_ELEMENT( *hae );
177 if( (tpts->element_array+loop)->datum != value )
178 *dvs = LFDS710_MISC_VALIDITY_INVALID_TEST_DATA;
181 // TRD : just check error_flags weren't raised
182 if( *dvs == LFDS710_MISC_VALIDITY_VALID )
183 for( loop = 0 ; loop < number_logical_processors ; loop++ )
184 if( (tpts+loop)->error_flag == RAISED )
185 *dvs = LFDS710_MISC_VALIDITY_INVALID_TEST_DATA;
188 lfds710_hash_a_cleanup( &has, NULL );
197 /****************************************************************************/
198 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_adding( void *libtest_threadset_per_thread_state )
200 enum lfds710_hash_a_insert_result
206 struct test_per_thread_state
209 struct libtest_threadset_per_thread_state
212 LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
214 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
216 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
218 tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
220 libtest_threadset_thread_ready_and_wait( pts );
222 while( index < tpts->number_elements_per_thread )
224 LFDS710_HASH_A_SET_KEY_IN_ELEMENT( (tpts->element_array+index)->hae, (tpts->element_array+index)->key );
225 LFDS710_HASH_A_SET_VALUE_IN_ELEMENT( (tpts->element_array+index)->hae, (tpts->element_array+index)->datum );
226 apr = lfds710_hash_a_insert( tpts->has, &(tpts->element_array+index)->hae, NULL );
228 if( apr == LFDS710_HASH_A_PUT_RESULT_FAILURE_EXISTING_KEY )
229 tpts->error_flag = RAISED;
234 LFDS710_MISC_BARRIER_STORE;
236 lfds710_misc_force_store();
238 return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);
245 /****************************************************************************/
246 #pragma warning( disable : 4100 )
248 static int key_compare_function( void const *new_key, void const *existing_key )
253 // TRD : new_key can be NULL (i.e. 0)
254 // TRD : existing_key can be NULL (i.e. 0)
256 if( (lfds710_pal_uint_t) new_key < (lfds710_pal_uint_t) existing_key )
259 if( (lfds710_pal_uint_t) new_key > (lfds710_pal_uint_t) existing_key )
265 #pragma warning( default : 4100 )
271 /****************************************************************************/
272 #pragma warning( disable : 4100 )
274 static void key_hash_function( void const *key, lfds710_pal_uint_t *hash )
276 // TRD : key can be NULL
277 LFDS710_PAL_ASSERT( hash != NULL );
281 /* TRD : this function iterates over the user data
282 and we are using the void pointer *as* key data
283 so here we need to pass in the addy of key
286 LFDS710_HASH_A_HASH_FUNCTION( (void *) &key, sizeof(lfds710_pal_uint_t), *hash );
291 #pragma warning( default : 4100 )