board: native_posix: Add test for k_busy_wait and cpu_hold
Add a new test for k_busy_wait and cpu_hold Signed-off-by: Alberto Escolar Piedras <alpi@oticon.com> Signed-off-by: Wolfgang Puffitsch <wopu@demant.com>
This commit is contained in:
parent
6d3476117b
commit
fe516b93a9
5 changed files with 324 additions and 0 deletions
|
@ -47,6 +47,14 @@ static void np_timer_isr(const void *arg)
|
|||
z_clock_announce(elapsed_ticks);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function exists only to enable tests to call into the timer ISR
|
||||
*/
|
||||
void np_timer_isr_test_hook(const void *arg)
|
||||
{
|
||||
np_timer_isr(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Initialize system timer driver
|
||||
*
|
||||
|
|
8
tests/boards/native_posix/cpu_wait/CMakeLists.txt
Normal file
8
tests/boards/native_posix/cpu_wait/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(cpu_wait)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
3
tests/boards/native_posix/cpu_wait/prj.conf
Normal file
3
tests/boards/native_posix/cpu_wait/prj.conf
Normal file
|
@ -0,0 +1,3 @@
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_TICKLESS_KERNEL=n
|
||||
CONFIG_ZTEST_THREAD_PRIORITY=1
|
301
tests/boards/native_posix/cpu_wait/src/main.c
Normal file
301
tests/boards/native_posix/cpu_wait/src/main.c
Normal file
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ztest.h>
|
||||
#include <zephyr.h>
|
||||
#include <sys/printk.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "board_soc.h"
|
||||
|
||||
/**
|
||||
* @brief Basic test of the POSIX arch k_busy_wait() and cpu_hold()
|
||||
* functions
|
||||
*
|
||||
* In this basic case, only one k_busy_wait() or posix_cpu_hold executes
|
||||
* at a time
|
||||
*/
|
||||
static void test_cpu_hold_basic(void)
|
||||
{
|
||||
uint32_t wait_times[] = {1, 30, 0, 121, 10000};
|
||||
uint64_t time2, time1 = posix_get_hw_cycle();
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(wait_times); i++) {
|
||||
k_busy_wait(wait_times[i]);
|
||||
time2 = posix_get_hw_cycle();
|
||||
zassert_true(time2 - time1 == wait_times[i],
|
||||
"k_busy_wait failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, wait_times[i]);
|
||||
time1 = time2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(wait_times); i++) {
|
||||
posix_cpu_hold(wait_times[i]);
|
||||
time2 = posix_get_hw_cycle();
|
||||
zassert_true(time2 - time1 == wait_times[i],
|
||||
"posix_cpu_hold failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, wait_times[i]);
|
||||
time1 = time2;
|
||||
}
|
||||
}
|
||||
|
||||
#define WASTED_TIME 1000 /* 1ms */
|
||||
#define THREAD_PRIO 0
|
||||
#define THREAD_DELAY 0
|
||||
/* Note: the duration of WASTED_TIME and thread priorities should not be changed
|
||||
* without thought, as they do matter for the test
|
||||
*/
|
||||
|
||||
#define ONE_TICK_TIME (1000000ul / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
|
||||
#define TWO_TICKS_TIME (2*1000000ul / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
|
||||
#define ONE_AND_HALF_TICKS (ONE_TICK_TIME + (ONE_TICK_TIME>>1))
|
||||
#define TWO_AND_HALF_TICKS ((ONE_TICK_TIME<<1) + (ONE_TICK_TIME>>1))
|
||||
|
||||
#if (WASTED_TIME > ONE_TICK_TIME/2)
|
||||
#error "This test will not work with this system tick period"
|
||||
#endif
|
||||
|
||||
static void thread_entry(void *p1, void *p2, void *p3);
|
||||
|
||||
K_THREAD_DEFINE(TIME_WASTER, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE,
|
||||
thread_entry, 0, 0, 0,
|
||||
THREAD_PRIO, 0, THREAD_DELAY);
|
||||
K_SEM_DEFINE(start_sema, 0, 1);
|
||||
K_SEM_DEFINE(end_sema, 0, 1);
|
||||
|
||||
/**
|
||||
* Thread meant to come up and waste time during the k_busy_wait() and
|
||||
* posix_cpu_hold() calls of test_cpu_hold_with_another_thread()
|
||||
*/
|
||||
static void thread_entry(void *p1, void *p2, void *p3)
|
||||
{
|
||||
int i;
|
||||
|
||||
ARG_UNUSED(p1);
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
/* Synchronize start of subtest with test thread */
|
||||
k_sem_take(&start_sema, K_FOREVER);
|
||||
/* Sleep until next tick
|
||||
* This sleep will take 2 ticks as the semaphore will
|
||||
* be given just after the previous tick boundary
|
||||
*/
|
||||
k_sleep(Z_TIMEOUT_TICKS(1));
|
||||
/* Waste time */
|
||||
k_busy_wait(WASTED_TIME);
|
||||
/* Synchronize end of subtest with test thread */
|
||||
k_sem_give(&end_sema);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test the POSIX arch k_busy_wait and cpu_hold while another thread
|
||||
* takes time during this test thread waits
|
||||
*
|
||||
* Note: This test relies on the exact timing of the ticks.
|
||||
* For native_posix it works, with a tick of 10ms. In general this test will
|
||||
* probably give problems if the tick time is not a relatively even number
|
||||
* of microseconds
|
||||
*/
|
||||
static void test_cpu_hold_with_another_thread(void)
|
||||
{
|
||||
uint64_t time2, time1;
|
||||
|
||||
/* k_busy_wait part: */
|
||||
|
||||
k_sleep(Z_TIMEOUT_TICKS(1)); /* Wait until tick boundary */
|
||||
k_sem_give(&start_sema);
|
||||
|
||||
time1 = posix_get_hw_cycle();
|
||||
k_busy_wait(TWO_TICKS_TIME + 1);
|
||||
/* The thread should have switched in and have used
|
||||
* WASTED_TIME us (1ms) right after 2*one_tick_time
|
||||
* As that is longer than 2 ticks + 1us, the total
|
||||
* should be 2 ticks + WASTED_TIME
|
||||
*/
|
||||
time2 = posix_get_hw_cycle();
|
||||
|
||||
zassert_true(time2 - time1 == TWO_TICKS_TIME + WASTED_TIME,
|
||||
"k_busy_wait failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, TWO_TICKS_TIME + WASTED_TIME);
|
||||
|
||||
k_sem_take(&end_sema, K_FOREVER);
|
||||
|
||||
k_sleep(Z_TIMEOUT_TICKS(1)); /* Wait until tick boundary */
|
||||
k_sem_give(&start_sema);
|
||||
|
||||
time1 = posix_get_hw_cycle();
|
||||
k_busy_wait(TWO_AND_HALF_TICKS);
|
||||
/* The thread should have used WASTED_TIME us (1ms) after
|
||||
* 2*one_tick_time, but as that is lower than 2.5 ticks, in
|
||||
* total the wait should be 2.5 ticks
|
||||
*/
|
||||
time2 = posix_get_hw_cycle();
|
||||
|
||||
zassert_true(time2 - time1 == TWO_AND_HALF_TICKS,
|
||||
"k_busy_wait failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, TWO_AND_HALF_TICKS);
|
||||
|
||||
k_sem_take(&end_sema, K_FOREVER);
|
||||
|
||||
/* CPU hold part: */
|
||||
|
||||
k_sleep(Z_TIMEOUT_TICKS(1)); /* Wait until tick boundary */
|
||||
k_sem_give(&start_sema);
|
||||
|
||||
time1 = posix_get_hw_cycle();
|
||||
posix_cpu_hold(TWO_TICKS_TIME + 1);
|
||||
/* The thread should have used WASTED_TIME us after 2*one_tick_time,
|
||||
* so the total should be 2 ticks + WASTED_TIME + 1.
|
||||
* That is we spend 2 ticks + 1 us in this context as requested.
|
||||
*/
|
||||
time2 = posix_get_hw_cycle();
|
||||
|
||||
zassert_true(time2 - time1 == TWO_TICKS_TIME + WASTED_TIME + 1,
|
||||
"k_busy_wait failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, TWO_TICKS_TIME + WASTED_TIME + 1);
|
||||
|
||||
k_sem_take(&end_sema, K_FOREVER);
|
||||
|
||||
k_sleep(Z_TIMEOUT_TICKS(1)); /* Wait until tick boundary */
|
||||
k_sem_give(&start_sema);
|
||||
|
||||
time1 = posix_get_hw_cycle();
|
||||
posix_cpu_hold(TWO_AND_HALF_TICKS);
|
||||
/* The thread should have used WASTED_TIME us after 2*one_tick_time,
|
||||
* so the total wait should be 2.5 ticks + WASTED_TIME.
|
||||
* That is 2.5 ticks in this context, and WASTED_TIME in the other
|
||||
* thread context
|
||||
*/
|
||||
|
||||
time2 = posix_get_hw_cycle();
|
||||
|
||||
zassert_true(time2 - time1 == TWO_AND_HALF_TICKS + WASTED_TIME,
|
||||
"k_busy_wait failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, TWO_AND_HALF_TICKS + WASTED_TIME);
|
||||
|
||||
k_sem_take(&end_sema, K_FOREVER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement system tick timer interrupt handler which wastes time
|
||||
* before calling the real one
|
||||
*/
|
||||
static void np_timer_isr_test_replacement(const void *arg)
|
||||
{
|
||||
ARG_UNUSED(arg);
|
||||
|
||||
k_busy_wait(WASTED_TIME);
|
||||
|
||||
void np_timer_isr_test_hook(const void *arg);
|
||||
np_timer_isr_test_hook(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test posix arch k_busy_wait and cpu_hold with interrupts that take
|
||||
* time.
|
||||
* The test is timed so that interrupts arrive during the wait times.
|
||||
*
|
||||
* The kernel is configured as NOT-tickless, and the default tick period is
|
||||
* 10ms
|
||||
*/
|
||||
static void test_cpu_hold_with_interrupts(void)
|
||||
{
|
||||
#if defined(CONFIG_BOARD_NATIVE_POSIX)
|
||||
/* So far we only have a test for native_posix.
|
||||
* As the test hooks into an interrupt to cause an extra delay
|
||||
* this is very platform specific
|
||||
*/
|
||||
uint64_t time2, time1;
|
||||
|
||||
k_sleep(Z_TIMEOUT_TICKS(1)); /* Wait until a tick boundary */
|
||||
|
||||
IRQ_CONNECT(TIMER_TICK_IRQ, 1, np_timer_isr_test_replacement, 0, 0);
|
||||
|
||||
time1 = posix_get_hw_cycle();
|
||||
k_busy_wait(ONE_TICK_TIME + 1);
|
||||
/* Just after ONE_TICK_TIME (10ms) the timer interrupt has come,
|
||||
* causing a delay of WASTED_TIME (1ms), so the k_busy_wait()
|
||||
* returns immediately as it was waiting for 10.001 ms
|
||||
*/
|
||||
time2 = posix_get_hw_cycle();
|
||||
|
||||
zassert_true(time2 - time1 == ONE_TICK_TIME + WASTED_TIME,
|
||||
"k_busy_wait failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, ONE_TICK_TIME);
|
||||
|
||||
|
||||
k_sleep(Z_TIMEOUT_TICKS(1)); /* Wait until tick boundary */
|
||||
|
||||
time1 = posix_get_hw_cycle();
|
||||
k_busy_wait(ONE_AND_HALF_TICKS);
|
||||
/* Just after ONE_TICK_TIME (10ms) the timer interrupt has come,
|
||||
* causing a delay of WASTED_TIME (1ms), after that, the k_busy_wait()
|
||||
* continues until 15ms
|
||||
*/
|
||||
time2 = posix_get_hw_cycle();
|
||||
|
||||
zassert_true(time2 - time1 == ONE_AND_HALF_TICKS,
|
||||
"k_busy_wait failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, ONE_TICK_TIME);
|
||||
|
||||
|
||||
|
||||
k_sleep(Z_TIMEOUT_TICKS(1)); /* Wait until tick boundary */
|
||||
|
||||
time1 = posix_get_hw_cycle();
|
||||
posix_cpu_hold(ONE_TICK_TIME + 1);
|
||||
/* Just after ONE_TICK_TIME (10ms) the timer interrupt has come,
|
||||
* causing a delay of WASTED_TIME (1ms), but posix_cpu_hold continues
|
||||
* until it spends 10.001 ms in this context. That is 11.001ms in total
|
||||
*/
|
||||
time2 = posix_get_hw_cycle();
|
||||
|
||||
zassert_true(time2 - time1 == ONE_TICK_TIME + 1 + WASTED_TIME,
|
||||
"k_busy_wait failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, ONE_TICK_TIME);
|
||||
|
||||
|
||||
k_sleep(Z_TIMEOUT_TICKS(1)); /* Wait until tick boundary */
|
||||
|
||||
time1 = posix_get_hw_cycle();
|
||||
posix_cpu_hold(ONE_AND_HALF_TICKS);
|
||||
/* Just after ONE_TICK_TIME (10ms) the timer interrupt has come,
|
||||
* causing a delay of WASTED_TIME (1ms), but posix_cpu_hold continues
|
||||
* until it spends 15ms in this context. That is 16ms in total
|
||||
*/
|
||||
time2 = posix_get_hw_cycle();
|
||||
|
||||
zassert_true(time2 - time1 == ONE_AND_HALF_TICKS + WASTED_TIME,
|
||||
"k_busy_wait failed "
|
||||
PRIu64"-"PRIu64"!="PRIu32"\n",
|
||||
time2, time1, ONE_TICK_TIME);
|
||||
|
||||
#endif /* defined(CONFIG_BOARD_NATIVE_POSIX) */
|
||||
}
|
||||
|
||||
void test_main(void)
|
||||
{
|
||||
ztest_test_suite(native_cpu_hold,
|
||||
ztest_unit_test(test_cpu_hold_basic),
|
||||
ztest_unit_test(test_cpu_hold_with_another_thread),
|
||||
ztest_unit_test(test_cpu_hold_with_interrupts)
|
||||
);
|
||||
|
||||
ztest_run_test_suite(native_cpu_hold);
|
||||
}
|
4
tests/boards/native_posix/cpu_wait/testcase.yaml
Normal file
4
tests/boards/native_posix/cpu_wait/testcase.yaml
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Test of the posix_arch k_busy_wait & cpu_hold() functionality
|
||||
tests:
|
||||
boards.native_posix.cpu_wait:
|
||||
platform_allow: native_posix native_posix_64
|
Loading…
Add table
Add a link
Reference in a new issue