]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.1.0/test_and_benchmark/libtest/src/libtest_misc/libtest_misc_determine_erg.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.1.0 / test_and_benchmark / libtest / src / libtest_misc / libtest_misc_determine_erg.c
1 /***** includes *****/
2 #include "libtest_misc_internal.h"
3
4 /***** defines *****/
5 #define MAX_ARM_ERG_LENGTH_IN_BYTES 2048
6
7
8
9 /****************************************************************************/
10 #if( defined LIBTEST_PAL_LOAD_LINKED && defined LIBTEST_PAL_STORE_CONDITIONAL )
11
12   /***** structs *****/
13   struct erg_director_state
14   {
15     enum flag volatile
16       quit_flag;
17
18     lfds710_pal_uint_t
19       (*count_array)[10],
20       number_threads;
21
22     lfds710_pal_uint_t volatile
23       **ack_pointer_array,
24       (*memory_pointer)[ (MAX_ARM_ERG_LENGTH_IN_BYTES+sizeof(lfds710_pal_uint_t)) / sizeof(lfds710_pal_uint_t)],
25       *write_pointer;
26   };
27
28   struct erg_helper_state
29   {
30     enum flag volatile
31       *quit_flag;
32
33     lfds710_pal_uint_t volatile
34       **ack_pointer,
35       **write_pointer;
36
37     lfds710_pal_uint_t
38       thread_number;
39   };
40
41   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_erg_director( void *libtest_threadset_per_thread_state );
42   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_erg_helper( void *libtest_threadset_per_thread_state );
43
44   /****************************************************************************/
45   void libtest_misc_determine_erg( struct libshared_memory_state *ms, lfds710_pal_uint_t (*count_array)[10], enum libtest_misc_determine_erg_result *der, lfds710_pal_uint_t *erg_length_in_bytes )
46   {
47     lfds710_pal_uint_t
48       erg_size = 10,
49       loop = 0,
50       number_logical_processors;
51
52     lfds710_pal_uint_t volatile LFDS710_PAL_ALIGN( MAX_ARM_ERG_LENGTH_IN_BYTES )
53       memory[ (MAX_ARM_ERG_LENGTH_IN_BYTES+sizeof(lfds710_pal_uint_t)) / sizeof(lfds710_pal_uint_t)];
54
55     struct erg_director_state
56       *eds;
57
58     struct erg_helper_state
59       *ehs_array;
60
61     struct lfds710_list_asu_element
62       *lasue = NULL;
63
64     struct lfds710_list_asu_state
65       list_of_logical_processors;
66
67     struct libtest_logical_processor
68       *lp;
69
70     struct libtest_threadset_per_thread_state
71       *pts;
72
73     struct libtest_threadset_state
74       ts;
75
76     LFDS710_PAL_ASSERT( ms != NULL );
77     LFDS710_PAL_ASSERT( count_array != NULL );
78     LFDS710_PAL_ASSERT( der != NULL );
79     LFDS710_PAL_ASSERT( erg_length_in_bytes != NULL );
80
81     /* TRD : ARM chips have a local and a global monitor
82              the local monitor has few guarantees and so you can't figure out ERG from it
83              because you can write even directly TO the LL/SC target and it thinks things are fine
84              so we have to hit the global monitor, which means running threads
85              in test, we know nothing about topology, so we just have to run one thread on each logical core
86              and get them to perform our necessary test memory writes
87
88              the code itself works by having a buffer of 2048 bytes, aligned at 2048 bytes - so it will
89              be aligned with an ERG
90              we LL/SC always on the first word
91              between the LL and SC, we get the other threads to perform a memory write into the buffer
92              the location of the write is the last word in each progressively larger ERG size, i.e.
93              ERG can be 8, 16, 32, 64, etc, so we LL location 0, then write to 1, 3, 7, 15, etc
94              we can then see which ERG sizes work and which fail
95     */
96
97     for( loop = 0 ; loop < 10 ; loop++ )
98       (*count_array)[loop] = 0;
99
100     libtest_pal_get_full_logical_processor_set( &list_of_logical_processors, ms );
101
102     lfds710_list_asu_query( &list_of_logical_processors, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
103
104     if( number_logical_processors == 1 )
105     {
106       *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_ONE_PHYSICAL_CORE;
107       return;
108     }
109
110     pts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct libtest_threadset_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
111
112     ehs_array = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct erg_helper_state) * (number_logical_processors-1), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
113     eds = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct erg_director_state), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
114     eds->ack_pointer_array = libshared_memory_alloc_from_unknown_node( ms, sizeof(lfds710_pal_uint_t *) * (number_logical_processors-1), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
115
116     eds->quit_flag = LOWERED;
117     eds->count_array = count_array;
118     eds->number_threads = number_logical_processors - 1;
119     eds->write_pointer = NULL;
120     eds->memory_pointer = &memory;
121     for( loop = 0 ; loop < (number_logical_processors-1) ; loop++ )
122       eds->ack_pointer_array[loop] = NULL;
123
124     libtest_threadset_init( &ts, NULL );
125
126     loop = 0;
127
128     while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(list_of_logical_processors, lasue) )
129     {
130       lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
131
132       if( loop == number_logical_processors-1 )
133         libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_erg_director, (void *) eds );
134       else
135       {
136         ehs_array[loop].quit_flag = &eds->quit_flag;
137         ehs_array[loop].thread_number = loop;
138         ehs_array[loop].ack_pointer = &eds->ack_pointer_array[loop];
139         ehs_array[loop].write_pointer = &eds->write_pointer;
140         libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_erg_helper, (void *) &ehs_array[loop] );
141       }
142
143       loop++;
144     }
145
146     LFDS710_MISC_BARRIER_STORE;
147     lfds710_misc_force_store();
148
149     libtest_threadset_run( &ts );
150
151     libtest_threadset_cleanup( &ts );
152
153     for( loop = 0 ; loop < 10 ; loop++ )
154       if( count_array[loop] > 0 )
155         erg_size = loop;
156
157     if( erg_size == 0 )
158       *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_ONE_PHYSICAL_CORE_OR_NO_LLSC;
159
160     if( erg_size >= 1 and erg_size <= 9 )
161     {
162       *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_SUCCESS;
163       *erg_length_in_bytes = 1UL < (erg_size+2);
164     }
165
166     if( erg_size == 10 )
167       *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_NO_LLSC;
168
169     return;
170   }
171
172   /****************************************************************************/
173   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_erg_director( void *libtest_threadset_per_thread_state )
174   {
175     lfds710_pal_uint_t
176       ack_count,
177       count_index,
178       erg_length_in_bytes,
179       loop,
180       register_memory_zero,
181       stored_flag,
182       subloop;
183
184     struct erg_director_state
185       *eds;
186
187     struct libtest_threadset_per_thread_state
188       *pts;
189
190     LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
191
192     LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
193
194     pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
195
196     eds = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
197
198     libtest_threadset_thread_ready_and_wait( pts );
199
200     for( loop = 0 ; loop < 1024 ; loop++ )
201       for( erg_length_in_bytes = MAX_ARM_ERG_LENGTH_IN_BYTES, count_index = 9 ; erg_length_in_bytes >= 4 ; erg_length_in_bytes /= 2, count_index-- )
202       {
203         LIBTEST_PAL_LOAD_LINKED( register_memory_zero, &(*eds->memory_pointer)[0] );
204
205         eds->write_pointer = &(*eds->memory_pointer)[erg_length_in_bytes / sizeof(lfds710_pal_uint_t)];
206
207         // TRD : wait for all threads to change their ack_pointer to the new write_pointer
208         do
209         {
210           ack_count = 0;
211
212           for( subloop = 0 ; subloop < eds->number_threads ; subloop++ )
213             if( eds->ack_pointer_array[subloop] == eds->write_pointer )
214             {
215               LFDS710_MISC_BARRIER_LOAD; // TRD : yes, really here!
216               ack_count++;
217             }
218         }
219         while( ack_count != eds->number_threads );
220
221         LIBTEST_PAL_STORE_CONDITIONAL( &(*eds->memory_pointer)[0], register_memory_zero, stored_flag );
222
223         if( stored_flag == 0 )
224           (*eds->count_array)[count_index]++;
225       }
226
227     eds->quit_flag = RAISED;
228
229     LFDS710_MISC_BARRIER_STORE;
230     lfds710_misc_force_store();
231
232     return (libshared_pal_thread_return_t) RETURN_SUCCESS;
233   }
234
235   /****************************************************************************/
236   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_erg_helper( void *libtest_threadset_per_thread_state )
237   {
238     struct erg_helper_state
239       *ehs;
240
241     struct libtest_threadset_per_thread_state
242       *pts;
243
244     LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
245
246     LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
247
248     pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
249
250     ehs = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
251
252     libtest_threadset_thread_ready_and_wait( pts );
253
254     while( *ehs->quit_flag == LOWERED )
255     {
256       if( *ehs->write_pointer != NULL )
257         **ehs->write_pointer = ehs->thread_number; // TRD : can be any value though - thread_number just seems nice
258       LFDS710_MISC_BARRIER_STORE;
259       *ehs->ack_pointer = *ehs->write_pointer;
260     }
261
262     LFDS710_MISC_BARRIER_STORE;
263     lfds710_misc_force_store();
264
265     return (libshared_pal_thread_return_t) RETURN_SUCCESS;
266   }
267
268 #endif
269
270
271
272
273
274 /****************************************************************************/
275 #pragma warning( disable : 4100 )
276
277 #if( !defined LIBTEST_PAL_LOAD_LINKED || !defined LIBTEST_PAL_STORE_CONDITIONAL )
278
279   void libtest_misc_determine_erg( struct libshared_memory_state *ms, lfds710_pal_uint_t (*count_array)[10], enum libtest_misc_determine_erg_result *der, lfds710_pal_uint_t *erg_length_in_bytes )
280   {
281     lfds710_pal_uint_t
282       loop;
283
284     LFDS710_PAL_ASSERT( ms != NULL );
285     LFDS710_PAL_ASSERT( count_array != NULL );
286     LFDS710_PAL_ASSERT( der != NULL );
287     LFDS710_PAL_ASSERT( erg_length_in_bytes != NULL );
288
289     for( loop = 0 ; loop < 10 ; loop++ )
290       (*count_array)[loop] = 0;
291
292     *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_NOT_SUPPORTED;
293
294     return;
295   }
296
297 #endif
298
299 #pragma warning( default : 4100 )
300