]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_and_dequeuing_with_free.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.0.0 / test / src / test_lfds700_queue_enqueuing_and_dequeuing_with_free.c
1 /***** includes *****/
2 #include "internal.h"
3
4 /***** structs *****/
5 struct test_state
6 {
7   lfds700_pal_uint_t
8     number_of_elements_per_thread;
9
10   struct lfds700_queue_state
11     *qs;
12 };
13
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 );
17
18
19
20
21
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 )
24 {
25   enum lfds700_misc_validity
26     dvs = LFDS700_MISC_VALIDITY_VALID;
27
28   lfds700_pal_uint_t
29     loop,
30     number_elements,
31     number_logical_processors,
32     number_of_elements_per_thread;
33
34   struct lfds700_list_asu_element
35     *lasue;
36
37   struct lfds700_misc_prng_state
38     ps;
39
40   struct lfds700_queue_element
41     *qe;
42
43   struct lfds700_queue_state
44     qs;
45
46   struct lfds700_misc_validation_info
47     vi;
48
49   struct test_pal_logical_processor
50     *lp;
51
52   struct test_state
53     *ts;
54
55   struct util_thread_starter_state
56     *tts;
57
58   test_pal_thread_state_t
59     *thread_handles;
60
61   assert( list_of_logical_processors != NULL );
62   // TRD : memory_in_megabytes can be any value in its range
63
64   /* TRD : the M&Q queue supports free()ing queue elements after they've been dequeued
65            we need to test this
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
76   */
77
78   internal_display_test_name( "Enqueuing and dequeuing with free" );
79
80   lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
81
82   lfds700_misc_prng_init( &ps );
83
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 );
88
89   ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors );
90
91   for( loop = 0 ; loop < number_logical_processors ; loop++ )
92   {
93     (ts+loop)->qs = &qs;
94     (ts+loop)->number_of_elements_per_thread = number_of_elements_per_thread;
95   }
96
97   thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors );
98
99   util_thread_starter_new( &tts, number_logical_processors );
100
101   LFDS700_MISC_BARRIER_STORE;
102
103   lfds700_misc_force_store();
104
105   loop = 0;
106   lasue = NULL;
107
108   while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) )
109   {
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 );
112     loop++;
113   }
114
115   util_thread_starter_run( tts );
116
117   for( loop = 0 ; loop < number_logical_processors ; loop++ )
118     test_pal_thread_wait( thread_handles[loop] );
119
120   util_thread_starter_delete( tts );
121
122   free( thread_handles );
123
124   LFDS700_MISC_BARRIER_LOAD;
125
126   vi.min_elements = 0;
127   vi.max_elements = 0;
128
129   lfds700_queue_query( &qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs );
130
131   lfds700_queue_cleanup( &qs, queue_element_cleanup_callback );
132
133   free( ts );
134
135   internal_display_test_result( 1, "queue", dvs );
136
137   return;
138 }
139
140
141
142
143
144 /****************************************************************************/
145 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueue_dequeuer_with_free( void *util_thread_starter_thread_state )
146 {
147   enum flag
148     finished_flag = LOWERED;
149
150   lfds700_pal_uint_t
151     loop;
152
153   struct lfds700_misc_prng_state
154     ps;
155
156   struct lfds700_freelist_element
157     *fe,
158     *fe_array;
159
160   struct lfds700_freelist_state
161     fs;
162
163   struct lfds700_queue_element
164     *qe;
165
166   struct test_state
167     *ts;
168
169   struct util_thread_starter_thread_state
170     *tsts;
171
172   LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
173
174   assert( util_thread_starter_thread_state != NULL );
175
176   tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
177   ts = (struct test_state *) tsts->thread_user_state;
178
179   lfds700_misc_prng_init( &ps );
180
181   lfds700_freelist_init_valid_on_current_logical_core( &fs, NULL );
182
183   fe_array = util_malloc_wrapper( sizeof(struct lfds700_freelist_element) * ts->number_of_elements_per_thread );
184
185   for( loop = 0 ; loop < ts->number_of_elements_per_thread ; loop++ )
186   {
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 );
190   }
191
192   util_thread_starter_ready_and_wait( tsts );
193
194   while( finished_flag == LOWERED )
195   {
196     loop = 0;
197     while( loop++ < 1000 and lfds700_freelist_pop(&fs, &fe, &ps) )
198     {
199       qe = LFDS700_FREELIST_GET_VALUE_FROM_ELEMENT( *fe );
200       lfds700_queue_enqueue( ts->qs, qe, &ps );
201     }
202
203     if( loop < 1000 )
204       finished_flag = RAISED;
205
206     loop = 0;
207     while( loop++ < 1000 and lfds700_queue_dequeue(ts->qs, &qe, &ps) )
208       util_aligned_free( qe );
209   }
210
211   LFDS700_MISC_BARRIER_STORE;
212
213   lfds700_misc_force_store();
214
215   lfds700_freelist_cleanup( &fs, NULL );
216
217   free( fe_array );
218
219   return( (test_pal_thread_return_t) EXIT_SUCCESS );
220 }
221
222
223
224
225
226 /****************************************************************************/
227 #pragma warning( disable : 4100 )
228
229 static void queue_element_cleanup_callback( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag )
230 {
231   assert( qs != NULL );
232   assert( qe != NULL );
233   // TRD : dummy_element_flag can be any value in its range
234
235   util_aligned_free( qe );
236
237   return;
238 }
239
240 #pragma warning( default : 4100 )
241