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);
|
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
|
* @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