This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
commit 1b8c90c12d3f59b839fcbb2a18e51c9f55a25e0c Author: jiangtao16 <[email protected]> AuthorDate: Fri Jun 20 16:41:02 2025 +0800 ostest: Add spinlock/rspinlock. This commit added spinlock/rspinlock test. Signed-off-by: jiangtao16 <[email protected]> --- testing/ostest/CMakeLists.txt | 2 +- testing/ostest/Kconfig | 9 +++ testing/ostest/Makefile | 2 +- testing/ostest/ostest.h | 4 + testing/ostest/ostest_main.c | 4 + testing/ostest/spinlock.c | 184 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 203 insertions(+), 2 deletions(-) diff --git a/testing/ostest/CMakeLists.txt b/testing/ostest/CMakeLists.txt index 777c68744..35b0c5596 100644 --- a/testing/ostest/CMakeLists.txt +++ b/testing/ostest/CMakeLists.txt @@ -22,7 +22,7 @@ if(CONFIG_TESTING_OSTEST) - set(SRCS getopt.c libc_memmem.c restart.c sighelper.c) + set(SRCS getopt.c libc_memmem.c restart.c sighelper.c spinlock.c) if(CONFIG_ENABLE_ALL_SIGNALS) list(APPEND SRCS sighand.c signest.c) diff --git a/testing/ostest/Kconfig b/testing/ostest/Kconfig index 83054fa68..100afb73e 100644 --- a/testing/ostest/Kconfig +++ b/testing/ostest/Kconfig @@ -115,4 +115,13 @@ config TESTING_OSTEST_POWEROFF default n depends on BOARDCTL_POWEROFF && TESTING_OSTEST_WAITRESULT +config TESTING_OSTEST_SPINLOCK_THREADS + int "Number of spinlock test threads" + default 2 + range 1 32 + +config TEST_LOOP_SCALE + int "Loop scale of spinlock test (N x 10,000)" + default 100 + endif # TESTING_OSTEST diff --git a/testing/ostest/Makefile b/testing/ostest/Makefile index 1fedfcf54..b8be63a62 100644 --- a/testing/ostest/Makefile +++ b/testing/ostest/Makefile @@ -31,7 +31,7 @@ MODULE = $(CONFIG_TESTING_OSTEST) # NuttX OS Test -CSRCS = getopt.c libc_memmem.c restart.c sighelper.c +CSRCS = getopt.c libc_memmem.c restart.c sighelper.c spinlock.c ifeq ($(CONFIG_ENABLE_ALL_SIGNALS),y) CSRCS += sighand.c signest.c diff --git a/testing/ostest/ostest.h b/testing/ostest/ostest.h index 321ecd2d3..1a396ba28 100644 --- a/testing/ostest/ostest.h +++ b/testing/ostest/ostest.h @@ -286,6 +286,10 @@ void setjmp_test(void); void smp_call_test(void); #endif +/* spinlock.c ***************************************************************/ + +void spinlock_test(void); + /* APIs exported (conditionally) by the OS specifically for testing of * priority inheritance */ diff --git a/testing/ostest/ostest_main.c b/testing/ostest/ostest_main.c index 4e2ca3484..58ccc87fb 100644 --- a/testing/ostest/ostest_main.c +++ b/testing/ostest/ostest_main.c @@ -547,6 +547,10 @@ static int user_main(int argc, char *argv[]) #endif #endif + printf("\nuser_main: spinlock test\n"); + spinlock_test(); + check_test_memory_usage(); + #ifdef CONFIG_BUILD_FLAT printf("\nuser_main: wdog test\n"); wdog_test(); diff --git a/testing/ostest/spinlock.c b/testing/ostest/spinlock.c new file mode 100644 index 000000000..2d71ea18f --- /dev/null +++ b/testing/ostest/spinlock.c @@ -0,0 +1,184 @@ +/**************************************************************************** + * apps/testing/ostest/spinlock.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdio.h> +#include <pthread.h> +#include <sys/time.h> +#include <stdint.h> +#include <unistd.h> +#include <assert.h> +#include <inttypes.h> +#include <nuttx/spinlock.h> + +/**************************************************************************** + * Preprocessor Definitions + ****************************************************************************/ + +#define THREAD_NUM CONFIG_TESTING_OSTEST_SPINLOCK_THREADS +#define LOOP_TIMES (CONFIG_TEST_LOOP_SCALE * 10000) + +enum lock_type_e +{ + RSPINLOCK, + SPINLOCK +}; + +struct spinlock_pub_args_s +{ + volatile uint32_t counter; + pthread_barrier_t barrier; + union + { + rspinlock_t rlock; + spinlock_t lock; + }; +}; + +struct spinlock_thread_args_s +{ + uint64_t delta; + FAR struct spinlock_pub_args_s *pub; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Helper functions for timespec calculating */ + +static inline uint64_t calc_diff(FAR struct timespec *start, + FAR struct timespec *end) +{ + uint64_t diff_sec = end->tv_sec - start->tv_sec; + long diff_nsec = end->tv_nsec - start->tv_nsec; + if (diff_nsec < 0) + { + diff_sec -= 1; + diff_nsec += 1000000000L; + } + + return diff_sec * 1000000000ULL + diff_nsec; +} + +#define LOCK_TEST_FUNC(lock_type, lock_func, unlock_func) \ +FAR static void * lock_type##_test_thread(FAR void *arg) \ +{ \ + struct spinlock_thread_args_s *param = \ + (struct spinlock_thread_args_s *)arg; \ + irqstate_t flags; \ + struct timespec start; \ + struct timespec end; \ + int i; \ + pthread_barrier_wait(¶m->pub->barrier); \ + clock_gettime(CLOCK_REALTIME, &start); \ + for (i = 0; i < LOOP_TIMES; i++) \ + { \ + flags = lock_func(¶m->pub->lock_type); \ + param->pub->counter++; \ + unlock_func(¶m->pub->lock_type, flags); \ + } \ + clock_gettime(CLOCK_REALTIME, &end); \ + param->delta = calc_diff(&start, &end); \ + return NULL; \ +} + +LOCK_TEST_FUNC(rlock, rspin_lock_irqsave, rspin_unlock_irqrestore) +LOCK_TEST_FUNC(lock, spin_lock_irqsave, spin_unlock_irqrestore) + +static inline void run_test_thread( + enum lock_type_e lock_type, + FAR void *(*thread_func)(FAR void *arg) + ) +{ + const char *test_type = (lock_type == RSPINLOCK) + ? "RSpin lock" : "Spin lock"; + printf("Test type: %s\n", test_type); + pthread_t tid[THREAD_NUM]; + struct spinlock_pub_args_s pub; + struct spinlock_thread_args_s param[THREAD_NUM]; + struct timespec stime; + struct timespec etime; + int i; + + pthread_barrier_init(&pub.barrier, NULL, THREAD_NUM + 1); + pub.counter = 0; + if (lock_type == RSPINLOCK) + { + rspin_lock_init(&pub.rlock); + } + else + { + spin_lock_init(&pub.lock); + } + + clock_gettime(CLOCK_REALTIME, &stime); + for (i = 0; i < THREAD_NUM; i++) + { + param[i].pub = &pub; + param[i].delta = 0; + pthread_create(&tid[i], NULL, thread_func, ¶m[i]); + } + + pthread_barrier_wait(&pub.barrier); + + for (i = 0; i < THREAD_NUM; i++) + { + pthread_join(tid[i], NULL); + } + + clock_gettime(CLOCK_REALTIME, &etime); + pthread_barrier_destroy(&pub.barrier); + uint64_t total_ns = 0; + for (i = 0; i < THREAD_NUM; i++) + { + total_ns += param[i].delta; + } + + printf("%s: Test Results:\n", test_type); + printf("%s: Final counter: %" PRIu32 "\n", test_type, pub.counter); + assert(pub.counter == THREAD_NUM * LOOP_TIMES); + printf("%s: Average time per thread: %" PRIu64 " ns\n" + , test_type, total_ns / THREAD_NUM); + printf("%s: Total execution time: %" PRIu64 " ns\n \n" + , test_type, calc_diff(&stime, &etime)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spinlock_test + ****************************************************************************/ + +void spinlock_test(void) +{ + printf("Start Spin lock test:\n"); + printf("Thread num: %d, Loop times: %d\n\n", THREAD_NUM, LOOP_TIMES); + + run_test_thread(SPINLOCK, lock_test_thread); + + run_test_thread(RSPINLOCK, rlock_test_thread); +}
