Skip to content

Commit c3d6034

Browse files
committed
testing/ostest: refactor the spinlock test.
This commit refactored the spinlock test for better accuracy and minimized jitters introduced by scheduling. Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
1 parent 6e67e24 commit c3d6034

File tree

1 file changed

+129
-72
lines changed

1 file changed

+129
-72
lines changed

testing/ostest/spinlock.c

Lines changed: 129 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,23 @@
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

5952
struct 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(&param->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(&param->pub->lock_type); \
104-
param->pub->counter++; \
105-
unlock_func(&param->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

Comments
 (0)