3030#include <unistd.h>
3131#include <assert.h>
3232#include <inttypes.h>
33+ #include <nuttx/atomic.h>
3334#include <nuttx/spinlock.h>
35+ #include <nuttx/seqlock.h>
3436
3537/****************************************************************************
3638 * Preprocessor Definitions
3739 ****************************************************************************/
3840
39- #define THREAD_NUM CONFIG_TESTING_OSTEST_SPINLOCK_THREADS
40- #define LOOP_TIMES (CONFIG_TEST_LOOP_SCALE * 10000 )
41+ #define MAX_THREAD_NUM (CONFIG_SMP_NCPUS)
42+ #define LOOP_TIMES (CONFIG_TEST_LOOP_SCALE * 100000 )
4143
42- enum lock_type_e
43- {
44- RSPINLOCK ,
45- SPINLOCK
46- };
47-
48- struct spinlock_pub_args_s
44+ aligned_data (64 ) struct spinlock_pub_args_s
4945{
46+ FAR void * lock ;
5047 volatile uint32_t counter ;
51- pthread_barrier_t barrier ;
52- union
53- {
54- rspinlock_t rlock ;
55- spinlock_t lock ;
56- };
48+ atomic_t barrier ;
49+ uint32_t thread_num ;
5750};
5851
5952struct spinlock_thread_args_s
@@ -90,103 +83,145 @@ FAR static void * lock_type##_test_thread(FAR void *arg) \
9083 irqstate_t flags; \
9184 struct timespec start; \
9285 struct timespec end; \
93- int i; \
94- int ret; \
95- ret = pthread_barrier_wait(¶m->pub->barrier); \
96- if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) \
86+ uint32_t i; \
87+ FAR struct spinlock_pub_args_s *pub = param->pub; \
88+ FAR lock_type *l = (FAR lock_type *)pub->lock; \
89+ atomic_fetch_add(&pub->barrier, 1); \
90+ while (atomic_read(&pub->barrier) != pub->thread_num) \
9791 { \
98- ASSERT(false ); \
92+ sched_yield( ); \
9993 } \
10094 clock_gettime(CLOCK_REALTIME, &start); \
10195 for (i = 0; i < LOOP_TIMES; i++) \
10296 { \
103- flags = lock_func(¶m->pub->lock_type ); \
104- param-> pub->counter++; \
105- unlock_func(¶m->pub->lock_type , flags); \
97+ flags = lock_func(l ); \
98+ pub->counter++; \
99+ unlock_func(l , flags); \
106100 } \
107101 clock_gettime(CLOCK_REALTIME, &end); \
108102 param->delta = calc_diff(&start, &end); \
109103 return NULL; \
110104}
111105
112- LOCK_TEST_FUNC (rlock , rspin_lock_irqsave , rspin_unlock_irqrestore )
113- LOCK_TEST_FUNC (lock , spin_lock_irqsave , spin_unlock_irqrestore )
106+ LOCK_TEST_FUNC (spinlock_t , spin_lock_irqsave , spin_unlock_irqrestore )
107+ LOCK_TEST_FUNC (rspinlock_t , rspin_lock_irqsave , rspin_unlock_irqrestore )
108+ LOCK_TEST_FUNC (seqcount_t , write_seqlock_irqsave , write_sequnlock_irqrestore )
114109
115- static inline void run_test_thread (
116- enum lock_type_e lock_type ,
117- FAR void * (* thread_func )(FAR void * arg )
118- )
110+ static inline
111+ void run_test_thread (void * lock , FAR void * (* thread_func )(FAR void * arg ),
112+ uint32_t thread_num , const char * lock_type )
119113{
120- const char * test_type = (lock_type == RSPINLOCK )
121- ? "RSpin lock" : "Spin lock" ;
122- printf ("Test type: %s\n" , test_type );
123- pthread_t tid [THREAD_NUM ];
114+ pthread_t tid [MAX_THREAD_NUM ];
124115 struct spinlock_pub_args_s pub ;
125- struct spinlock_thread_args_s param [THREAD_NUM ];
116+ pthread_attr_t attr ;
117+ struct sched_param sparam ;
118+ struct spinlock_thread_args_s param [MAX_THREAD_NUM ];
126119 struct timespec stime ;
127120 struct timespec etime ;
121+ cpu_set_t cpu_set = 1u ;
122+ uint64_t total_ns = 0u ;
123+ int status ;
128124 int i ;
129- int ret ;
130125
131- ret = pthread_barrier_init (& pub .barrier , NULL , THREAD_NUM + 1 );
132- if (ret != 0 )
126+ /* Initialize the public parameters. */
127+
128+ printf ("Test type: %s\n" , lock_type );
129+
130+ pub .lock = lock ;
131+ pub .counter = 0u ;
132+ pub .thread_num = thread_num ;
133+ atomic_set_release (& pub .barrier , 0u );
134+
135+ /* Set affinity to CPU0 */
136+
137+ #ifdef CONFIG_SMP
138+ if (OK != sched_setaffinity (getpid (), sizeof (cpu_set_t ), & cpu_set ))
133139 {
140+ printf ("spinlock_test: ERROR: nxsched_set_affinity failed" );
134141 ASSERT (false);
135142 }
143+ #else
144+ UNUSED (cpu_set );
145+ #endif
146+
147+ /* Boost to maximum priority for test threads. */
136148
137- pub . counter = 0 ;
138- if (lock_type == RSPINLOCK )
149+ status = pthread_attr_init ( & attr ) ;
150+ if (status != 0 )
139151 {
140- rspin_lock_init (& pub .rlock );
152+ printf ("spinlock_test: ERROR: "
153+ "pthread_attr_init failed, status=%d\n" , status );
154+ ASSERT (false);
141155 }
142- else
156+
157+ sparam .sched_priority = SCHED_PRIORITY_MAX ;
158+ status = pthread_attr_setschedparam (& attr , & sparam );
159+ if (status != OK )
143160 {
144- spin_lock_init (& pub .lock );
161+ printf ("spinlock_test: ERROR: "
162+ "pthread_attr_setschedparam failed, status=%d\n" , status );
163+ ASSERT (false);
145164 }
146165
147166 clock_gettime (CLOCK_REALTIME , & stime );
148- for (i = 0 ; i < THREAD_NUM ; i ++ )
167+
168+ /* Create new test threads. */
169+
170+ for (i = 0 ; i < thread_num ; i ++ )
149171 {
150172 param [i ].pub = & pub ;
151173 param [i ].delta = 0 ;
152- ret = pthread_create (& tid [i ], NULL , thread_func , & param [i ]);
153- if (ret != 0 )
174+
175+ /* Set affinity */
176+
177+ #ifdef CONFIG_SMP
178+ cpu_set = 1u << ((i + 1 ) % CONFIG_SMP_NCPUS );
179+
180+ status = pthread_attr_setaffinity_np (& attr , sizeof (cpu_set_t ),
181+ & cpu_set );
182+ if (status != OK )
154183 {
184+ printf ("spinlock_test: ERROR: "
185+ "pthread_attr_setaffinity_np failed, status=%d\n" , status );
155186 ASSERT (false);
156187 }
157- }
188+ #endif
158189
159- ret = pthread_barrier_wait (& pub .barrier );
160- if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD )
161- {
162- ASSERT (false);
190+ status = pthread_create (& tid [i ], & attr , thread_func , & param [i ]);
191+ if (status != 0 )
192+ {
193+ printf ("spinlock_test: ERROR: "
194+ "pthread_create failed, status=%d\n" , status );
195+ ASSERT (false);
196+ }
163197 }
164198
165- for (i = 0 ; i < THREAD_NUM ; i ++ )
199+ for (i = 0 ; i < thread_num ; i ++ )
166200 {
167- pthread_join (tid [i ], NULL );
201+ status = pthread_join (tid [i ], NULL );
202+ if (status != 0 )
203+ {
204+ printf ("spinlock_test: ERROR: "
205+ "pthread_join failed, status=%d\n" , status );
206+ ASSERT (false);
207+ }
168208 }
169209
170- clock_gettime (CLOCK_REALTIME , & etime );
171- ret = pthread_barrier_destroy (& pub .barrier );
172- if (ret != 0 )
173- {
174- ASSERT (false);
175- }
210+ /* Calculate the average throughput. */
176211
177- uint64_t total_ns = 0 ;
178- for (i = 0 ; i < THREAD_NUM ; i ++ )
212+ clock_gettime ( CLOCK_REALTIME , & etime ) ;
213+ for (i = 0 ; i < thread_num ; i ++ )
179214 {
180215 total_ns += param [i ].delta ;
181216 }
182217
183- printf ("%s: Test Results:\n" , test_type );
184- printf ("%s: Final counter: %" PRIu32 "\n" , test_type , pub .counter );
185- assert (pub .counter == THREAD_NUM * LOOP_TIMES );
186- printf ("%s: Average time per thread : %" PRIu64 " ns \n"
187- , test_type , total_ns / THREAD_NUM );
188- printf ("%s: Total execution time: %" PRIu64 " ns\n \n"
189- , test_type , calc_diff (& stime , & etime ));
218+ printf ("%s: Test Results:\n" , lock_type );
219+ printf ("%s: Final counter: %" PRIu32 "\n" , lock_type , pub .counter );
220+ assert (pub .counter == thread_num * LOOP_TIMES );
221+ printf ("%s: Average throughput : %" PRIu64 " op/s \n" , lock_type ,
222+ ( uint64_t ) NSEC_PER_SEC * LOOP_TIMES * thread_num / total_ns );
223+ printf ("%s: Total execution time: %" PRIu64 " ns\n \n" ,
224+ lock_type , calc_diff (& stime , & etime ));
190225}
191226
192227/****************************************************************************
@@ -197,12 +232,34 @@ static inline void run_test_thread(
197232 * Name: spinlock_test
198233 ****************************************************************************/
199234
200- void spinlock_test ( void )
235+ static void spinlock_test_thread_num ( unsigned thread_num )
201236{
202- printf ("Start Spin lock test:\n" );
203- printf ("Thread num: %d, Loop times: %d\n\n" , THREAD_NUM , LOOP_TIMES );
237+ aligned_data (64 ) union
238+ {
239+ spinlock_t spinlock ;
240+ rspinlock_t rspinlock ;
241+ seqcount_t seqcount ;
242+ } lock ;
243+
244+ printf ("Start Lock test:\n" );
245+ printf ("Thread num: %u, Loop times: %d\n\n" , thread_num , LOOP_TIMES );
246+
247+ spin_lock_init (& lock .spinlock );
248+ run_test_thread (& lock , spinlock_t_test_thread , thread_num , "spinlock" );
249+
250+ rspin_lock_init (& lock .rspinlock );
251+ run_test_thread (& lock , rspinlock_t_test_thread , thread_num , "rspinlock" );
252+
253+ seqlock_init (& lock .seqcount );
254+ run_test_thread (& lock , seqcount_t_test_thread , thread_num , "seqcount" );
255+ }
204256
205- run_test_thread (SPINLOCK , lock_test_thread );
257+ void spinlock_test (void )
258+ {
259+ unsigned tnr ;
206260
207- run_test_thread (RSPINLOCK , rlock_test_thread );
261+ for (tnr = 1 ; tnr < MAX_THREAD_NUM ; tnr ++ )
262+ {
263+ spinlock_test_thread_num (tnr );
264+ }
208265}
0 commit comments