[utest] add smp testcases

This commit is contained in:
Yaochenger 2024-08-27 17:13:17 +08:00 committed by Rbb666
parent 0d87b028ed
commit f33312abe0
11 changed files with 826 additions and 0 deletions

View File

@ -77,4 +77,8 @@ config UTEST_SCHEDULER_TC
bool "scheduler test"
default n
if RT_USING_SMP
rsource "smp/Kconfig"
endif
endmenu

View File

@ -62,4 +62,9 @@ if GetDepend(['UTEST_SCHEDULER_TC']):
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
list = os.listdir(cwd)
for item in list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
group = group + SConscript(os.path.join(item, 'SConscript'))
Return('group')

View File

@ -0,0 +1,23 @@
menu "Kernel SMP Testcase"
config UTEST_SMP_AFFFINITY_TC
bool "smp affinity and thread priority test1"
default n
config UTEST_SMP_ASSIGNED_IDLE_CORE_TC
bool "smp threads auto assign to idle cores for test"
default n
config UTEST_SMP_INTERRUPT_PRI_TC
bool "smp interrupt priority test"
default n
config UTEST_SMP_SPINLOCK_TC
bool "smp spinlock test"
default n
config UTEST_SMP_THREAD_PREEMPTION_TC
bool "smp threads preemption test"
default n
endmenu

View File

@ -0,0 +1,27 @@
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = []
CPPPATH = [cwd]
if GetDepend(['UTEST_SMP_SPINLOCK_TC']):
src += ['smp_spinlock_tc.c']
if GetDepend(['UTEST_SMP_ASSIGNED_IDLE_CORE_TC']):
src += ['smp_assigned_idle_cores_tc.c']
if GetDepend(['UTEST_SMP_INTERRUPT_PRI_TC']):
src += ['smp_interrupt_pri_tc.c']
if GetDepend(['UTEST_SMP_THREAD_PREEMPTION_TC']):
src += ['smp_thread_preemption_tc.c']
if GetDepend(['UTEST_SMP_AFFFINITY_TC']):
src += ['smp_bind_affinity_tc.c']
src += ['smp_affinity_pri1_tc.c']
src += ['smp_affinity_pri2_tc.c']
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-08-10 RV the first version
*/
#include <rtthread.h>
#include "utest.h"
/**
* @brief Test that threads with low-priority bound cores do not preempt high-priority threads.
*
* @note Create RT_CPUS_NR threads, thread 0 is bound to core 0, lower priority, the priority of the other threads
* for the system's highest and the thread entry function does not let out the CPU control, run the specified
* number of times in thread 0 to create a high-priority not bound to the core of the thread, the thread will
* be preempted by the core 0 is running on the thread!
*/
/* Number of thread runs */
static int run_num = 10;
#define THREAD_STACK_SIZE 1024
#define THREAD_PRIORITY 2
#define LOW_PRIORITY 50
#define THIGH_PRIORITY 10
static rt_thread_t threads[RT_CPUS_NR];
static rt_thread_t temp_thread;
static struct rt_spinlock lock;
static int thread_inc = 0;
static int num = 0;
static void thread_temp_entry(void *parameter)
{
int id = 0;
while (1)
{
id = rt_hw_cpu_id();
uassert_int_equal(id, 0);
extern long list_thread(void);
list_thread();
rt_thread_delete(temp_thread);
}
}
static void thread_entry(void *parameter)
{
int id = 0;
int para = *(int *)parameter;
while (1)
{
thread_inc++;
id = rt_hw_cpu_id();
if (para == 0)
{
if (thread_inc == run_num)
{
uassert_int_equal(id, 0);
extern long list_thread(void);
list_thread();
/* Creating high-priority untied core threads */
temp_thread = rt_thread_create("Tn", thread_temp_entry, RT_NULL, THREAD_STACK_SIZE, THIGH_PRIORITY, 20);
if (temp_thread != RT_NULL)
{
rt_thread_startup(temp_thread);
}
}
rt_thread_delay(5);
}
else
{
uassert_int_not_equal(id, 0);
while (1);
}
}
}
static void smp_affinity_pri1_tc(void)
{
static int params[RT_CPUS_NR] = {0};
char thread_name[8];
int i;
for (i = 0; i < RT_CPUS_NR; i++)
{
params[i] = i;
}
/* Creating threads with low priority bindings to core 0 */
threads[0] = rt_thread_create("T0", thread_entry, (int *)&params[0], THREAD_STACK_SIZE, LOW_PRIORITY, 20);
if (threads[0] != RT_NULL)
{
rt_thread_control(threads[0], RT_THREAD_CTRL_BIND_CPU, (void *)0);
rt_thread_startup(threads[0]);
}
/* Create high-priority unbound threads with thread functions that don't let out CPU control */
for (i = 1; i < RT_CPUS_NR; i++)
{
rt_snprintf(thread_name, sizeof(thread_name), "T%d", i);
threads[i] = rt_thread_create(thread_name, thread_entry, (int *)&params[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
if (threads[i] != RT_NULL)
{
rt_thread_control(threads[i], RT_THREAD_CTRL_BIND_CPU, (void *)i);
rt_thread_startup(threads[i]);
}
}
rt_thread_delay(100);
}
static rt_err_t utest_tc_init(void)
{
rt_spin_lock_init(&lock);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
for (num = 0; num < RT_CPUS_NR; num++)
{
rt_thread_delete(threads[num]);
}
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(smp_affinity_pri1_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.smp.affinity_pri1_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-08-10 RV the first version
*/
#include <rtthread.h>
#include "utest.h"
/**
* @brief Threads are automatically balanced across cores.
*
* @note Create RT_CPUS_NR threads, thread 0 is not bound to core 0, higher priority, the priority of the other
* threads for the system's highest and the thread entry function does not let out the CPU control, run the
* specified number of times after the creation of thread 0 in thread 0, a low-priority bound to the core 0,
* the thread will not preempt the core 0 is running on threads
*/
/* Number of thread runs */
static int run_num = 10;
#define THREAD_STACK_SIZE 1024
#define THREAD_PRIORITY 2
#define LOW_PRIORITY 50
#define THIGH_PRIORITY 10
static rt_thread_t threads[RT_CPUS_NR];
static rt_thread_t temp_thread;
static struct rt_spinlock lock;
static int thread_inc = 0;
static int run_flag = 0;
static int num = 0;
static void thread_temp_entry(void *parameter)
{
run_flag = 1;
rt_thread_delete(temp_thread);
}
static void thread_entry(void *parameter)
{
int id = 0;
int para = *(int *)parameter;
while (1)
{
thread_inc++;
id = rt_hw_cpu_id();
if (para == 0)
{
if (thread_inc == run_num)
{
uassert_int_equal(id, 0);
temp_thread = rt_thread_create("Tn", thread_temp_entry, RT_NULL, THREAD_STACK_SIZE, LOW_PRIORITY, 20);
if (temp_thread != RT_NULL)
{
rt_thread_control(temp_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
rt_thread_startup(temp_thread);
uassert_int_not_equal(run_flag, 1);
}
}
rt_thread_delay(5);
}
else
{
uassert_int_not_equal(id, 0);
while (1);
}
}
}
static void smp_affinity_pri2_tc(void)
{
static int params[RT_CPUS_NR] = {0};
char thread_name[8];
int i;
for (i = 0; i < RT_CPUS_NR; i++)
{
params[i] = i;
}
threads[0] = rt_thread_create("T0", thread_entry, (int *)&params[0], THREAD_STACK_SIZE, THIGH_PRIORITY, 20);
if (threads[0] != RT_NULL)
{
uassert_true(1);
rt_thread_startup(threads[0]);
}
/* Create high-priority unbound threads with thread functions that don't let out CPU control */
for (i = 1; i < RT_CPUS_NR; i++)
{
rt_snprintf(thread_name, sizeof(thread_name), "T%d", i);
threads[i] = rt_thread_create(thread_name, thread_entry, (int *)&params[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
if (threads[i] != RT_NULL)
{
uassert_true(1);
rt_thread_control(threads[i], RT_THREAD_CTRL_BIND_CPU, (void *)i);
rt_thread_startup(threads[i]);
}
}
rt_thread_delay(50);
}
static rt_err_t utest_tc_init(void)
{
rt_spin_lock_init(&lock);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
for (num = 0; num < RT_CPUS_NR; num++)
{
rt_thread_delete(threads[num]);
}
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(smp_affinity_pri2_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.smp.affinity_pri2_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-08-10 RV the first version
*/
#include <rtthread.h>
#include "utest.h"
/**
* @brief Threads are automatically balanced across cores.
*
* @note Create multiple threads untied core threads, run them for a while on each core to see
* if the threads are automatically distributed evenly, run for a while to output the threads
* running on each core.
*/
#define THREAD_STACK_SIZE 1024
#define THREAD_PRIORITY 20
static rt_thread_t threads[RT_CPUS_NR];
static int tick = 0, finsh_flag = 0;
static int num = 0;
/* thread entry function */
static void thread_entry(void *parameter)
{
while (1)
{
tick++;
if (tick == 100)
{
/* Output the current core running threads */
extern long list_thread(void);
list_thread();
finsh_flag = 0xA55A;
uassert_true(1);
}
rt_thread_delay(5);
}
}
static void thread_on_idle_core_tc(void)
{
static int params[RT_CPUS_NR] = {0};
char thread_name[8];
int i;
/* Initialise the thread entry parameters */
for (i = 0; i < RT_CPUS_NR; i++)
{
params[i] = i;
}
/* Create RT_CPUS_NR threads and pass the entry parameters for each thread */
for (i = 0; i < RT_CPUS_NR; i++)
{
rt_snprintf(thread_name, sizeof(thread_name), "T%d", i);
threads[i] = rt_thread_create(thread_name, thread_entry, &params[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
if (threads[i] != RT_NULL)
{
uassert_true(1);
rt_thread_startup(threads[i]);
}
}
/* Waiting for test cases to finish */
while (finsh_flag != 0xA55A);
}
static rt_err_t utest_tc_init(void)
{
rt_kprintf("[Test case]: created threads are automatically assigned to run on idle cores\r\n");
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
for (num = 0; num < RT_CPUS_NR; num++)
{
rt_thread_delete(threads[num]);
}
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(thread_on_idle_core_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.smp.assigned_idle_cores_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-08-10 RV the first version
*/
#include <rtthread.h>
#include "utest.h"
/**
* @brief Binding core affinity testcase.
*
* @note Create RT_CPUS_NR threads, thread 0 is bound to core 0, other threads are not bound to specific cores,
* after running for a set number of times, count the number of times each core is run on the corresponding core,
* thread 0 should always be run on core 0, other threads will be run on different cores.
*/
/* Number of thread runs */
static int run_num = 100;
#define THREAD_STACK_SIZE 1024
#define THREAD_PRIORITY 20
static rt_thread_t threads[RT_CPUS_NR];
static struct rt_spinlock lock;
static int thread_inc[RT_CPUS_NR] = {0};
static int thread_tic[RT_CPUS_NR] = {0};
static int finsh_flag = 0;
static int num = 0;
static void thread_entry(void *parameter)
{
int id = 0;
int para = *(int *)parameter;
while (1)
{
thread_tic[para]++;
id = rt_hw_cpu_id();
if (para == id)
{
thread_inc[para]++;
}
if (thread_tic[para] == run_num)
{
if (para == 0)
uassert_int_equal(thread_inc[para], thread_tic[para]);
else
uassert_int_not_equal(thread_inc[para], thread_tic[para]);
finsh_flag ++;
}
rt_thread_delay(5);
}
}
static void thread_bind_affinity_tc(void)
{
static int params[RT_CPUS_NR] = {0};
char thread_name[8];
int i, j;
for (i = 0; i < RT_CPUS_NR; i++)
{
params[i] = i;
}
/* Create RT_CPUS_NR threads Thread 0 is bound to core 0 Other threads are not bound */
for (i = 0; i < RT_CPUS_NR; i++)
{
rt_snprintf(thread_name, sizeof(thread_name), "thread%d", i);
threads[i] = rt_thread_create(thread_name, thread_entry, (int *)&params[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
if (i == 0)
{
rt_thread_control(threads[0], RT_THREAD_CTRL_BIND_CPU, (void *)0);
}
if (threads[i] != RT_NULL)
{
rt_thread_startup(threads[i]);
}
}
while (finsh_flag != RT_CPUS_NR);
/* Displays the number of times a thread was executed on the relevant core */
for (j = 0; j < RT_CPUS_NR; j++)
{
rt_spin_lock(&lock);
rt_kprintf("Total runs[%d], Number of times thread[%d] run on [core%d]: [%4d], always run at core%d ? %s \r\n", run_num, j, j, thread_inc[j], j, (thread_inc[j] == run_num) ? "yes" : "no");
rt_spin_unlock(&lock);
}
}
static rt_err_t utest_tc_init(void)
{
rt_spin_lock_init(&lock);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
for (num = 0; num < RT_CPUS_NR; num++)
{
rt_thread_delete(threads[num]);
}
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(thread_bind_affinity_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.smp.bind_affinity_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-08-10 RV the first version
*/
#include <rtthread.h>
#include "utest.h"
#include <interrupt.h>
/**
* @brief Setting the Interrupt Priority Test.
*
* @note Without turning off interrupts, interrupts respond in the order in which they are triggered.
* With interrupts turned off, low and high priority interrupts are triggered sequentially,
* and when interrupts are turned on, high priority interrupts respond first.
*/
#define RES_VAL 0X0
#define SET_VAL 0XA
#define RT_SPI_1 1
#define RT_SPI_2 2
#define RT_SPI_PRI_HIGH 120
#define RT_SPI_PRI_LOW 140
static int mode = 0;
static int ipi_val[2] = {0, 0};
/* Software Interrupt 1 Service Functions */
static void rt_scheduler_ipi1_handler(int vector, void *param)
{
ipi_val[0] = SET_VAL;
if (mode == 0)
{
uassert_true(ipi_val[0] > ipi_val[1]);
}
else
{
ipi_val[0] = RES_VAL;
ipi_val[1] = RES_VAL;
}
}
/* Software Interrupt 2 Service Functions */
static void rt_scheduler_ipi2_handler(int vector, void *param)
{
ipi_val[1] = SET_VAL;
if (mode == 0)
{
ipi_val[0] = RES_VAL;
ipi_val[1] = RES_VAL;
}
else
{
uassert_true(ipi_val[0] < ipi_val[1]);
}
}
/* Interrupt priority testcases 1 */
static void int_pri1_tc(void)
{
mode = 0;
unsigned int pri1, pri2;
pri1 = rt_hw_interrupt_get_priority(RT_SPI_1);
pri2 = rt_hw_interrupt_get_priority(RT_SPI_2);
if (pri1 < pri2)
uassert_true(pri1 < pri2);
/* Trigger interrupt */
rt_hw_ipi_send(RT_SPI_1, 0x1);
rt_hw_ipi_send(RT_SPI_2, 0x1);
rt_thread_delay(5);
}
/* Interrupt priority testcases 2 */
static void int_pri2_tc(void)
{
mode = 1;
unsigned int pri1, pri2;
pri1 = rt_hw_interrupt_get_priority(RT_SPI_1);
pri2 = rt_hw_interrupt_get_priority(RT_SPI_2);
if (pri1 < pri2)
uassert_true(pri1 < pri2);
rt_base_t level = rt_hw_local_irq_disable();
/* Trigger interrupt */
rt_hw_ipi_send(RT_SPI_1, 0x1);
rt_hw_ipi_send(RT_SPI_2, 0x1);
rt_hw_local_irq_enable(level);
rt_thread_delay(5);
}
static rt_err_t utest_tc_init(void)
{
/* Setting the priority of software interrupts */
rt_hw_interrupt_set_priority(RT_SPI_1, RT_SPI_PRI_LOW);
rt_hw_interrupt_set_priority(RT_SPI_2, RT_SPI_PRI_HIGH);
/* Register software interrupt service functions */
rt_hw_ipi_handler_install(RT_SPI_1, rt_scheduler_ipi1_handler);
rt_hw_ipi_handler_install(RT_SPI_2, rt_scheduler_ipi2_handler);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(int_pri1_tc);
UTEST_UNIT_RUN(int_pri2_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.smp.interrupt_pri_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-08-13 RV the first version
*/
#include <rtthread.h>
#include "utest.h"
#include <interrupt.h>
/**
* @brief Spinlock testcase.
*
* @note Create multiple threads and use spinlocks to protect shared memory
*/
#define THREAD_PRIORITY 20
#define THREAD_TIMESLICE 20
#define THREAD_STACK_SIZE 1024
static rt_thread_t thread1;
static rt_thread_t thread2;
static rt_uint8_t finsh_flag = 0;
static struct rt_spinlock lock;
static rt_uint8_t number1, number2 = 0;
static void rt_thread_entry1(void *parameter)
{
while (1)
{
rt_spin_lock(&lock);
number1++;
rt_thread_yield();
number2++;
rt_spin_unlock(&lock);
rt_thread_delay(5);
}
}
static void rt_thread_entry2(void *parameter)
{
while (1)
{
rt_spin_lock(&lock);
uassert_int_equal(number1, number2);
number1++;
number2++;
rt_spin_unlock(&lock);
if (number1 >= 10)
{
finsh_flag = 1;
}
rt_thread_delay(5);
}
}
static void smp_spinlock_tc(void)
{
thread1 = rt_thread_create("T1", rt_thread_entry1, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
if (thread1 != RT_NULL)
{
rt_thread_startup(thread1);
}
thread2 = rt_thread_create("T2", rt_thread_entry2, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY - 1, 20);
if (thread2 != RT_NULL)
{
rt_thread_startup(thread2);
}
while (finsh_flag == 0);
}
static rt_err_t utest_tc_init(void)
{
rt_spin_lock_init(&lock);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_thread_delete(thread1);
rt_thread_delete(thread2);
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(smp_spinlock_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.smp.spinlock_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-08-10 RV the first version
*/
#include <rtthread.h>
#include "utest.h"
/**
* @brief Thread Preemption Test with Different Priorities.
*
* @note Create multiple threads, low-priority threads run first,
* high-priority threads preempt low-priority threads, and
* print the current status of each core in the thread's entry function.
*/
#define THREAD_PRIORITY_HIGH 21
#define THREAD_PRIORITY_LOW 30
static rt_thread_t threads[2];
static struct rt_spinlock lock;
/* High Priority Thread */
static void thread_high_entry(void *parameter)
{
uassert_true(1);
rt_spin_lock(&lock);
rt_kprintf("High priority thread is running\n");
extern long list_thread(void);
list_thread();
rt_spin_unlock(&lock);
}
/* Low Priority Thread */
static void thread_low_entry(void *parameter)
{
uassert_true(1);
rt_spin_lock(&lock);
rt_kprintf("Low priority thread is running\n");
extern long list_thread(void);
list_thread();
rt_spin_unlock(&lock);
}
static void thread_preemptions_tc(void)
{
/* Creating low-priority thread */
threads[0] = rt_thread_create("tlow", thread_low_entry, RT_NULL, 1024, THREAD_PRIORITY_LOW, 10);
if (threads[0] != RT_NULL)
{
uassert_true(1);
rt_thread_startup(threads[0] );
}
rt_thread_delay(5);
/* Creating high-priority thread */
threads[1] = rt_thread_create("thigh", thread_high_entry, RT_NULL, 1024, THREAD_PRIORITY_HIGH, 10);
if (threads[1] != RT_NULL)
{
uassert_true(1);
rt_thread_startup(threads[1]);
}
rt_thread_delay(50);
}
static rt_err_t utest_tc_init(void)
{
rt_spin_lock_init(&lock);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(thread_preemptions_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.smp.thread_preemptions_tc", utest_tc_init, utest_tc_cleanup, 10);