2 #include "libtest_tests_internal.h"
5 struct test_per_thread_state
7 struct lfds710_prng_state
15 /***** private prototyps *****/
16 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_generate( void *libtest_threadset_per_thread_state );
22 /****************************************************************************/
23 void libtest_tests_prng_generate( struct lfds710_list_asu_state *list_of_logical_processors, struct libshared_memory_state *ms, enum lfds710_misc_validity *dvs )
26 duplicate_flag = LOWERED,
27 finished_flag = LOWERED;
34 *merged_output_arrays,
35 merged_write_index = 0,
36 number_logical_processors,
41 struct lfds710_list_asu_element
44 struct libtest_logical_processor
47 struct lfds710_prng_state
50 struct libtest_threadset_per_thread_state
53 struct libtest_threadset_state
56 struct test_per_thread_state
59 LFDS710_PAL_ASSERT( list_of_logical_processors != NULL );
60 LFDS710_PAL_ASSERT( ms != NULL );
61 LFDS710_PAL_ASSERT( dvs != NULL );
63 /* TRD : here we test the atomic PRNG
64 we create an array, an output buffer, of 128 elements per thread
65 we have a single, global PRNG
66 we start all the threads and let them run for test duration seconds
67 (to ensure they are all running together)
68 each thread loops, writing new numbers to its output array
69 obviously in test duration seconds it will write many more than 128 elements -
70 it just loops over the output array
72 then when we're done we merge sort the output arrays (no qsort, not using standard library)
73 the number of duplicates should be 0
74 and the standard deviation should be 25% of LFDS710_PRNG_MAX
77 *dvs = LFDS710_MISC_VALIDITY_VALID;
80 lfds710_list_asu_query( list_of_logical_processors, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
81 tpts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct test_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
82 pts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct libtest_threadset_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
83 output_arrays = libshared_memory_alloc_from_unknown_node( ms, sizeof(lfds710_pal_uint_t) * 128 * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
84 merged_output_arrays = libshared_memory_alloc_from_unknown_node( ms, sizeof(lfds710_pal_uint_t) * 128 * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
86 lfds710_prng_init_valid_on_current_logical_core( &ps, LFDS710_PRNG_SEED );
88 libtest_threadset_init( &ts, NULL );
90 while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors,lasue) )
92 lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
94 (tpts+loop)->ps = &ps;
95 (tpts+loop)->output_array = output_arrays + (loop * 128);
96 (tpts+loop)->read_index = 0; // TRD : convenient to alloc here, as we need one per thread, used in validation
98 libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_generate, &tpts[loop] );
103 LFDS710_MISC_BARRIER_STORE;
105 lfds710_misc_force_store();
107 // TRD : run the test
108 libtest_threadset_run( &ts );
109 libtest_threadset_cleanup( &ts );
112 LFDS710_MISC_BARRIER_LOAD;
114 // TRD : merge sort the counter arrays into merged_output_array
115 while( finished_flag == LOWERED )
117 smallest_prng_value = LFDS710_PRNG_MAX;
118 finished_flag = RAISED;
120 for( loop = 0 ; loop < number_logical_processors ; loop++ )
121 if( tpts[loop].read_index < 128 and tpts[loop].output_array[ tpts[loop].read_index ] < smallest_prng_value )
123 smallest_prng_value = tpts[loop].output_array[ tpts[loop].read_index ];
124 thread_to_bump = loop;
125 finished_flag = LOWERED;
128 tpts[thread_to_bump].read_index++;
129 merged_output_arrays[ merged_write_index++ ] = smallest_prng_value;
132 // TRD : now check for duplicates
133 while( duplicate_flag == LOWERED and index < (128 * number_logical_processors) - 2 )
135 if( merged_output_arrays[index] == merged_output_arrays[index+1] )
136 duplicate_flag = RAISED;
140 if( duplicate_flag == RAISED )
141 *dvs = LFDS710_MISC_VALIDITY_INVALID_TEST_DATA;
143 // TRD : now for standard deviation (integer math only is allowed, and we can't sum the outputs because we'll overflow)
144 for( loop = 0 ; loop < 128 * number_logical_processors ; loop++ )
145 mean += merged_output_arrays[loop] / (128*number_logical_processors);
147 /* TRD : the mean of an unsigned 64 bit is 9223372036854775808
148 the mean of an unsigned 32 bit is 2147483648
149 there are 128 random numbers per thread
150 the more numbers there are, the more closely we should approach the expected mean
151 it'd take me a while - if I could - to work out the expected deviation for a given number of numbers
152 empirically, a single logical core (128 numbers) shouldn't be more than 10% off
155 ten_percent = LFDS710_PRNG_MAX / 10;
157 if( mean < (LFDS710_PRNG_MAX / 2) - ten_percent or mean > (LFDS710_PRNG_MAX / 2) + ten_percent )
158 *dvs = LFDS710_MISC_VALIDITY_INVALID_TEST_DATA;
160 // TRD : should add a standard deviation check here
169 /****************************************************************************/
170 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_generate( void *libtest_threadset_per_thread_state )
176 struct test_per_thread_state
179 struct libtest_threadset_per_thread_state
186 LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
188 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
190 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
191 tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
193 libtest_threadset_thread_ready_and_wait( pts );
195 current_time = start_time = time( NULL );
197 while( current_time < start_time + TEST_DURATION_IN_SECONDS )
199 LFDS710_PRNG_GENERATE( *tpts->ps, tpts->output_array[index] );
201 // TRD : 128 element array, so masking on 128-1 makes us loop, much faster than modulus
202 index = ( (index+1) & 0x7F );
204 if( time_loop++ == TIME_LOOP_COUNT )
207 time( ¤t_time );
211 LFDS710_MISC_BARRIER_STORE;
213 lfds710_misc_force_store();
215 return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);