tests: app_kernel: Add user support

Add user thread support to message queue, semaphore, mutex and
pipe tests. Mailbox and memory map tests are restricted from
executing from user threads.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
This commit is contained in:
Peter Mitsis 2023-10-18 13:23:59 -04:00 committed by Carles Cufí
commit fa33147bf9
14 changed files with 228 additions and 119 deletions

View file

@ -3,8 +3,7 @@ CONFIG_TEST=y
CONFIG_STDOUT_CONSOLE=y
# eliminate timer interrupts during the benchmark
CONFIG_SYS_CLOCK_TICKS_PER_SEC=2
CONFIG_TICKLESS_KERNEL=n
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1
CONFIG_MAIN_THREAD_PRIORITY=6
CONFIG_FORCE_NO_ASSERT=y

View file

@ -0,0 +1,24 @@
CONFIG_TEST=y
# all printf, fprintf to stdout go to console
CONFIG_STDOUT_CONSOLE=y
# eliminate timer interrupts during the benchmark
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1
CONFIG_MAIN_THREAD_PRIORITY=6
CONFIG_FORCE_NO_ASSERT=y
# Disable HW Stack Protection (see #28664)
CONFIG_TEST_HW_STACK_PROTECTION=n
CONFIG_HW_STACK_PROTECTION=n
CONFIG_CBPRINTF_FP_SUPPORT=y
# Can only run under 1 CPU
CONFIG_MP_MAX_NUM_CPUS=1
# Enable pipes
CONFIG_PIPES=y
CONFIG_APPLICATION_DEFINED_SYSCALL=y
CONFIG_TIMING_FUNCTIONS=y
CONFIG_USERSPACE=y

View file

@ -97,17 +97,19 @@ void mailbox_put(uint32_t size, int count, uint32_t *time)
{
int i;
unsigned int t;
timing_t start;
timing_t end;
message.rx_source_thread = K_ANY;
message.tx_target_thread = K_ANY;
/* first sync with the receiver */
k_sem_give(&SEM0);
t = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < count; i++) {
k_mbox_put(&MAILB1, &message, K_FOREVER);
}
t = TIME_STAMP_DELTA_GET(t);
end = timing_timestamp_get();
t = (unsigned int)timing_cycles_get(&start, &end);
*time = SYS_CLOCK_HW_CYCLES_TO_NS_AVG(t, count);
check_result();
}

View file

@ -70,7 +70,8 @@ void mailbox_get(struct k_mbox *mailbox,
unsigned int *time)
{
int i;
unsigned int t;
timing_t start;
timing_t end;
int32_t return_value = 0;
struct k_mbox_msg Message;
@ -79,19 +80,16 @@ void mailbox_get(struct k_mbox *mailbox,
/* sync with the sender */
k_sem_take(&SEM0, K_FOREVER);
t = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < count; i++) {
return_value |= k_mbox_get(mailbox,
&Message,
&data_recv,
K_FOREVER);
}
end = timing_timestamp_get();
*time = timing_cycles_get(&start, &end);
t = TIME_STAMP_DELTA_GET(t);
*time = SYS_CLOCK_HW_CYCLES_TO_NS_AVG(t, count);
if (bench_test_end() < 0) {
PRINT_OVERFLOW_ERROR();
}
if (return_value != 0) {
k_panic();
}

View file

@ -20,11 +20,11 @@
#define RECV_STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
#define TEST_STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
char msg[MAX_MSG];
char data_bench[MESSAGE_SIZE];
BENCH_BMEM char msg[MAX_MSG];
BENCH_BMEM char data_bench[MESSAGE_SIZE];
struct k_pipe *test_pipes[] = {&PIPE_NOBUFF, &PIPE_SMALLBUFF, &PIPE_BIGBUFF};
char sline[SLINE_LEN + 1];
BENCH_DMEM struct k_pipe *test_pipes[] = {&PIPE_NOBUFF, &PIPE_SMALLBUFF, &PIPE_BIGBUFF};
BENCH_BMEM char sline[SLINE_LEN + 1];
/*
* Time in timer cycles necessary to read time.
@ -32,6 +32,13 @@ char sline[SLINE_LEN + 1];
*/
uint32_t tm_off;
static BENCH_DMEM char *test_type_str[] = {
"| K E R N E L - - > K E R N E L | |\n",
"| K E R N E L - - > U S E R | |\n",
"| U S E R - - > K E R N E L | |\n",
"| U S E R - - > U S E R | |\n"
};
/********************************************************************/
/* static allocation */
@ -122,8 +129,8 @@ static timing_t z_vrfy_timing_timestamp_get(void)
*/
static void test_thread_entry(void *p1, void *p2, void *p3)
{
ARG_UNUSED(p1);
ARG_UNUSED(p2);
bool skip_mem_and_mbox = (bool)(uintptr_t)(p2);
ARG_UNUSED(p3);
PRINT_STRING("\n");
@ -131,15 +138,19 @@ static void test_thread_entry(void *p1, void *p2, void *p3)
PRINT_STRING("| S I M P L E S E R V I C E "
"M E A S U R E M E N T S | nsec |\n");
#ifdef CONFIG_USERSPACE
PRINT_STRING((const char *)arg1);
PRINT_STRING((const char *)p1);
#endif
PRINT_STRING(dashline);
message_queue_test();
sema_test();
mutex_test();
if (!skip_mem_and_mbox) {
memorymap_test();
mailbox_test();
}
pipe_test();
}
@ -152,16 +163,28 @@ int main(void)
priority = k_thread_priority_get(k_current_get());
#ifdef CONFIG_USERSPACE
k_mem_domain_add_partition(&k_mem_domain_default,
&bench_mem_partition);
#endif
bench_test_init();
timing_init();
timing_start();
/* ********* All threads are kernel threads ********** */
k_thread_create(&test_thread, test_stack,
K_THREAD_STACK_SIZEOF(test_stack),
test_thread_entry, NULL, NULL, NULL,
test_thread_entry,
test_type_str[0], (void *)(uintptr_t)false, NULL,
priority, 0, K_FOREVER);
k_thread_create(&recv_thread, recv_stack,
K_THREAD_STACK_SIZEOF(recv_stack),
recvtask, NULL, NULL, NULL,
recvtask, (void *)(uintptr_t)false, NULL, NULL,
5, 0, K_FOREVER);
k_thread_start(&recv_thread);
@ -170,6 +193,86 @@ int main(void)
k_thread_join(&test_thread, K_FOREVER);
k_thread_abort(&recv_thread);
#ifdef CONFIG_USERSPACE
/* ****** Main thread is kernel, receiver is user thread ******* */
k_thread_create(&test_thread, test_stack,
K_THREAD_STACK_SIZEOF(test_stack),
test_thread_entry,
test_type_str[1], (void *)(uintptr_t)true, NULL,
priority, 0, K_FOREVER);
k_thread_create(&recv_thread, recv_stack,
K_THREAD_STACK_SIZEOF(recv_stack),
recvtask, (void *)(uintptr_t)true, NULL, NULL,
5, K_USER, K_FOREVER);
k_thread_access_grant(&recv_thread, &DEMOQX1, &DEMOQX4, &MB_COMM,
&CH_COMM, &SEM0, &SEM1, &SEM2, &SEM3, &SEM4,
&STARTRCV, &DEMO_MUTEX,
&PIPE_NOBUFF, &PIPE_SMALLBUFF, &PIPE_BIGBUFF);
k_thread_start(&recv_thread);
k_thread_start(&test_thread);
k_thread_join(&test_thread, K_FOREVER);
k_thread_abort(&recv_thread);
/* ****** Main thread is user, receiver is kernel thread ******* */
k_thread_create(&test_thread, test_stack,
K_THREAD_STACK_SIZEOF(test_stack),
test_thread_entry,
test_type_str[2], (void *)(uintptr_t)true, NULL,
priority, K_USER, K_FOREVER);
k_thread_create(&recv_thread, recv_stack,
K_THREAD_STACK_SIZEOF(recv_stack),
recvtask, (void *)(uintptr_t)true, NULL, NULL,
5, 0, K_FOREVER);
k_thread_access_grant(&test_thread, &DEMOQX1, &DEMOQX4, &MB_COMM,
&CH_COMM, &SEM0, &SEM1, &SEM2, &SEM3, &SEM4,
&STARTRCV, &DEMO_MUTEX,
&PIPE_NOBUFF, &PIPE_SMALLBUFF, &PIPE_BIGBUFF);
k_thread_start(&recv_thread);
k_thread_start(&test_thread);
k_thread_join(&test_thread, K_FOREVER);
k_thread_abort(&recv_thread);
/* ********* All threads are user threads ********** */
k_thread_create(&test_thread, test_stack,
K_THREAD_STACK_SIZEOF(test_stack),
test_thread_entry,
test_type_str[3], (void *)(uintptr_t)true, NULL,
priority, K_USER, K_FOREVER);
k_thread_create(&recv_thread, recv_stack,
K_THREAD_STACK_SIZEOF(recv_stack),
recvtask, (void *)(uintptr_t)true, NULL, NULL,
5, K_USER, K_FOREVER);
k_thread_access_grant(&test_thread, &DEMOQX1, &DEMOQX4, &MB_COMM,
&CH_COMM, &SEM0, &SEM1, &SEM2, &SEM3, &SEM4,
&STARTRCV, &DEMO_MUTEX,
&PIPE_NOBUFF, &PIPE_SMALLBUFF, &PIPE_BIGBUFF);
k_thread_access_grant(&recv_thread, &DEMOQX1, &DEMOQX4, &MB_COMM,
&CH_COMM, &SEM0, &SEM1, &SEM2, &SEM3, &SEM4,
&STARTRCV, &DEMO_MUTEX,
&PIPE_NOBUFF, &PIPE_SMALLBUFF, &PIPE_BIGBUFF);
k_thread_start(&recv_thread);
k_thread_start(&test_thread);
k_thread_join(&test_thread, K_FOREVER);
k_thread_abort(&recv_thread);
#endif /* CONFIG_USERSPACE */
timing_stop();
PRINT_STRING("| END OF TESTS "
" |\n");
PRINT_STRING(dashline);

View file

@ -122,25 +122,6 @@ extern struct k_mem_slab MAP1;
PRINT_STRING(sline); \
}
#define PRINT_OVERFLOW_ERROR() \
PRINT_F(__FILE__":%d Error: tick occurred\n", __LINE__)
static inline uint32_t BENCH_START(void)
{
uint32_t et;
bench_test_start();
et = TIME_STAMP_DELTA_GET(0);
return et;
}
static inline void check_result(void)
{
if (bench_test_end() < 0) {
PRINT_OVERFLOW_ERROR();
}
}
__syscall void test_thread_priority_set(k_tid_t thread, int prio);
__syscall timing_t timing_timestamp_get(void);

View file

@ -15,12 +15,14 @@
void memorymap_test(void)
{
uint32_t et; /* elapsed time */
timing_t start;
timing_t end;
int i;
void *p;
int alloc_status;
PRINT_STRING(dashline);
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_MAP_RUNS; i++) {
alloc_status = k_mem_slab_alloc(&MAP1, &p, K_FOREVER);
if (alloc_status != 0) {
@ -30,8 +32,8 @@ void memorymap_test(void)
}
k_mem_slab_free(&MAP1, p);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT, "average alloc and dealloc memory page",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, (2 * NR_OF_MAP_RUNS)));

View file

@ -15,66 +15,68 @@ void message_queue_test(void)
{
uint32_t et; /* elapsed time */
int i;
timing_t start;
timing_t end;
PRINT_STRING(dashline);
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_MSGQ_RUNS; i++) {
k_msgq_put(&DEMOQX1, data_bench, K_FOREVER);
}
et = TIME_STAMP_DELTA_GET(et);
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT, "enqueue 1 byte msg in MSGQ",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_MSGQ_RUNS));
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_MSGQ_RUNS; i++) {
k_msgq_get(&DEMOQX1, data_bench, K_FOREVER);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT, "dequeue 1 byte msg from MSGQ",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_MSGQ_RUNS));
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_MSGQ_RUNS; i++) {
k_msgq_put(&DEMOQX4, data_bench, K_FOREVER);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT, "enqueue 4 bytes msg in MSGQ",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_MSGQ_RUNS));
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_MSGQ_RUNS; i++) {
k_msgq_get(&DEMOQX4, data_bench, K_FOREVER);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT, "dequeue 4 bytes msg in MSGQ",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_MSGQ_RUNS));
k_sem_give(&STARTRCV);
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_MSGQ_RUNS; i++) {
k_msgq_put(&DEMOQX1, data_bench, K_FOREVER);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT,
"enqueue 1 byte msg in MSGQ to a waiting higher priority task",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_MSGQ_RUNS));
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_MSGQ_RUNS; i++) {
k_msgq_put(&DEMOQX4, data_bench, K_FOREVER);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT,
"enqueue 4 bytes in MSGQ to a waiting higher priority task",

View file

@ -15,15 +15,17 @@ void mutex_test(void)
{
uint32_t et; /* elapsed time */
int i;
timing_t start;
timing_t end;
PRINT_STRING(dashline);
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_MUTEX_RUNS; i++) {
k_mutex_lock(&DEMO_MUTEX, K_FOREVER);
k_mutex_unlock(&DEMO_MUTEX);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT, "average lock and unlock mutex",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, (2 * NR_OF_MUTEX_RUNS)));

View file

@ -115,7 +115,7 @@ void pipe_test(void)
PRINT_STRING("| "
"non-matching sizes (1_TO_N) to lower priority"
" |\n");
k_thread_priority_set(k_current_get(), TaskPrio - 2);
test_thread_priority_set(k_current_get(), TaskPrio - 2);
}
PRINT_STRING(dashline);
PRINT_1_TO_N_HEADER();
@ -136,7 +136,7 @@ void pipe_test(void)
PRINT_1_TO_N();
}
PRINT_STRING(dashline);
k_thread_priority_set(k_current_get(), TaskPrio);
test_thread_priority_set(k_current_get(), TaskPrio);
}
}
@ -160,12 +160,14 @@ int pipeput(struct k_pipe *pipe,
{
int i;
unsigned int t;
timing_t start;
timing_t end;
size_t sizexferd_total = 0;
size_t size2xfer_total = size * count;
/* first sync with the receiver */
k_sem_give(&SEM0);
t = BENCH_START();
start = timing_timestamp_get();
for (i = 0; option == _1_TO_N || (i < count); i++) {
size_t sizexferd = 0;
size_t size2xfer = MIN(size, size2xfer_total - sizexferd_total);
@ -195,15 +197,10 @@ int pipeput(struct k_pipe *pipe,
}
}
t = TIME_STAMP_DELTA_GET(t);
end = timing_timestamp_get();
t = (unsigned int)timing_cycles_get(&start, &end);
*time = SYS_CLOCK_HW_CYCLES_TO_NS_AVG(t, count);
if (bench_test_end() < 0) {
if (high_timer_overflow()) {
PRINT_STRING("| Timer overflow. Results are invalid ");
} else {
PRINT_STRING("| Tick occurred. Results may be inaccurate ");
}
PRINT_STRING(" |\n");
}
return 0;
}

View file

@ -84,12 +84,14 @@ int pipeget(struct k_pipe *pipe, enum pipe_options option, int size, int count,
{
int i;
unsigned int t;
timing_t start;
timing_t end;
size_t sizexferd_total = 0;
size_t size2xfer_total = size * count;
/* sync with the sender */
k_sem_take(&SEM0, K_FOREVER);
t = BENCH_START();
start = timing_timestamp_get();
for (i = 0; option == _1_TO_N || (i < count); i++) {
size_t sizexferd = 0;
size_t size2xfer = MIN(size, size2xfer_total - sizexferd_total);
@ -116,17 +118,9 @@ int pipeget(struct k_pipe *pipe, enum pipe_options option, int size, int count,
}
}
t = TIME_STAMP_DELTA_GET(t);
end = timing_timestamp_get();
t = (unsigned int) timing_cycles_get(&start, &end);
*time = SYS_CLOCK_HW_CYCLES_TO_NS_AVG(t, count);
if (bench_test_end() < 0) {
if (high_timer_overflow()) {
PRINT_STRING("| Timer overflow. "
"Results are invalid ");
} else {
PRINT_STRING("| Tick occurred. "
"Results may be inaccurate ");
}
PRINT_STRING(" |\n");
}
return 0;
}

View file

@ -17,7 +17,7 @@
#include "receiver.h"
char data_recv[MESSAGE_SIZE] = { 0 };
BENCH_DMEM char data_recv[MESSAGE_SIZE] = { 0 };
void dequtask(void);
void waittask(void);
@ -29,6 +29,11 @@ void piperecvtask(void);
*/
void recvtask(void *p1, void *p2, void *p3)
{
bool skip_mbox = (bool)(uintptr_t)(p1);
ARG_UNUSED(p2);
ARG_UNUSED(p3);
/* order must be compatible with master.c ! */
k_sem_take(&STARTRCV, K_FOREVER);
@ -37,8 +42,10 @@ void recvtask(void *p1, void *p2, void *p3)
k_sem_take(&STARTRCV, K_FOREVER);
waittask();
if (!skip_mbox) {
k_sem_take(&STARTRCV, K_FOREVER);
mailrecvtask();
}
k_sem_take(&STARTRCV, K_FOREVER);
piperecvtask();

View file

@ -9,22 +9,22 @@
#include "master.h"
/**
*
* @brief Semaphore signal speed test
*
*/
void sema_test(void)
{
uint32_t et; /* elapsed Time */
int i;
timing_t start;
timing_t end;
PRINT_STRING(dashline);
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_SEMA_RUNS; i++) {
k_sem_give(&SEM0);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT, "signal semaphore",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_SEMA_RUNS));
@ -32,24 +32,23 @@ void sema_test(void)
k_sem_reset(&SEM1);
k_sem_give(&STARTRCV);
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_SEMA_RUNS; i++) {
k_sem_give(&SEM1);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT, "signal to waiting high pri task",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_SEMA_RUNS));
et = BENCH_START();
start = timing_timestamp_get();
for (i = 0; i < NR_OF_SEMA_RUNS; i++) {
k_sem_give(&SEM1);
}
et = TIME_STAMP_DELTA_GET(et);
check_result();
end = timing_timestamp_get();
et = (uint32_t)timing_cycles_get(&start, &end);
PRINT_F(FORMAT, "signal to waiting high pri task, with timeout",
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(et, NR_OF_SEMA_RUNS));
}

View file

@ -12,9 +12,7 @@
/* semaphore signal speed test */
/**
*
* @brief Receive task (Wait task)
*
*/
void waittask(void)
{
@ -23,6 +21,7 @@ void waittask(void)
for (i = 0; i < NR_OF_SEMA_RUNS; i++) {
k_sem_take(&SEM1, K_FOREVER);
}
for (i = 0; i < NR_OF_SEMA_RUNS; i++) {
k_sem_take(&SEM1, K_MSEC(SEMA_WAIT_TIME));
}