8 number_of_elements_per_thread;
10 struct lfds700_queue_state
14 /***** private prototypes *****/
15 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueue_dequeuer_with_free( void *util_thread_starter_thread_state );
16 static void queue_element_cleanup_callback( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag );
22 /****************************************************************************/
23 void test_lfds700_queue_enqueuing_and_dequeuing_with_free( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes )
25 enum lfds700_misc_validity
26 dvs = LFDS700_MISC_VALIDITY_VALID;
31 number_logical_processors,
32 number_of_elements_per_thread;
34 struct lfds700_list_asu_element
37 struct lfds700_misc_prng_state
40 struct lfds700_queue_element
43 struct lfds700_queue_state
46 struct lfds700_misc_validation_info
49 struct test_pal_logical_processor
55 struct util_thread_starter_state
58 test_pal_thread_state_t
61 assert( list_of_logical_processors != NULL );
62 // TRD : memory_in_megabytes can be any value in its range
64 /* TRD : the M&Q queue supports free()ing queue elements after they've been dequeued
66 we spawn one thread per logical core
67 there's one master queue which all threads work on
68 we create one freelist per thread
69 and allocate as many queue elements as we can (no payload)
70 - but note each allocate is its own malloc()
71 each freelist receives an equal share (i.e. we get the mallocs out of the way)
72 each thread enqueues as rapidly as possible
73 and dequeues as rapidly as possible
74 (i.e. each thread loops, doing an enqueue and a dequeue)
75 when the dequeue is done, the element is free()ed
78 internal_display_test_name( "Enqueuing and dequeuing with free" );
80 lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
82 lfds700_misc_prng_init( &ps );
84 number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct lfds700_freelist_element) + sizeof(struct lfds700_queue_element) );
85 number_of_elements_per_thread = number_elements / number_logical_processors;
86 qe = util_aligned_malloc( sizeof(struct lfds700_queue_element), (lfds700_pal_uint_t) LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES );
87 lfds700_queue_init_valid_on_current_logical_core( &qs, qe, &ps, NULL );
89 ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors );
91 for( loop = 0 ; loop < number_logical_processors ; loop++ )
94 (ts+loop)->number_of_elements_per_thread = number_of_elements_per_thread;
97 thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors );
99 util_thread_starter_new( &tts, number_logical_processors );
101 LFDS700_MISC_BARRIER_STORE;
103 lfds700_misc_force_store();
108 while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) )
110 lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
111 util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_enqueue_dequeuer_with_free, ts+loop );
115 util_thread_starter_run( tts );
117 for( loop = 0 ; loop < number_logical_processors ; loop++ )
118 test_pal_thread_wait( thread_handles[loop] );
120 util_thread_starter_delete( tts );
122 free( thread_handles );
124 LFDS700_MISC_BARRIER_LOAD;
129 lfds700_queue_query( &qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs );
131 lfds700_queue_cleanup( &qs, queue_element_cleanup_callback );
135 internal_display_test_result( 1, "queue", dvs );
144 /****************************************************************************/
145 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueue_dequeuer_with_free( void *util_thread_starter_thread_state )
148 finished_flag = LOWERED;
153 struct lfds700_misc_prng_state
156 struct lfds700_freelist_element
160 struct lfds700_freelist_state
163 struct lfds700_queue_element
169 struct util_thread_starter_thread_state
172 LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
174 assert( util_thread_starter_thread_state != NULL );
176 tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
177 ts = (struct test_state *) tsts->thread_user_state;
179 lfds700_misc_prng_init( &ps );
181 lfds700_freelist_init_valid_on_current_logical_core( &fs, NULL );
183 fe_array = util_malloc_wrapper( sizeof(struct lfds700_freelist_element) * ts->number_of_elements_per_thread );
185 for( loop = 0 ; loop < ts->number_of_elements_per_thread ; loop++ )
187 qe = util_aligned_malloc( sizeof(struct lfds700_queue_element), LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES );
188 LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( fe_array[loop], qe );
189 lfds700_freelist_push( &fs, &fe_array[loop], &ps );
192 util_thread_starter_ready_and_wait( tsts );
194 while( finished_flag == LOWERED )
197 while( loop++ < 1000 and lfds700_freelist_pop(&fs, &fe, &ps) )
199 qe = LFDS700_FREELIST_GET_VALUE_FROM_ELEMENT( *fe );
200 lfds700_queue_enqueue( ts->qs, qe, &ps );
204 finished_flag = RAISED;
207 while( loop++ < 1000 and lfds700_queue_dequeue(ts->qs, &qe, &ps) )
208 util_aligned_free( qe );
211 LFDS700_MISC_BARRIER_STORE;
213 lfds700_misc_force_store();
215 lfds700_freelist_cleanup( &fs, NULL );
219 return( (test_pal_thread_return_t) EXIT_SUCCESS );
226 /****************************************************************************/
227 #pragma warning( disable : 4100 )
229 static void queue_element_cleanup_callback( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag )
231 assert( qs != NULL );
232 assert( qe != NULL );
233 // TRD : dummy_element_flag can be any value in its range
235 util_aligned_free( qe );
240 #pragma warning( default : 4100 )