freertos: Refactor vTaskDelay() and vTaskDelayUntil() unit tests

This commit refactors the existing vTaskDelayUntil() unit test according to
the FreeRTOS unit test guidelines, and adds a new vTaskDelay() unit test.
This commit is contained in:
Darian Leung
2022-09-21 13:25:05 +08:00
parent 193e30bbf7
commit aaf7547665
2 changed files with 146 additions and 59 deletions

View File

@@ -5,9 +5,12 @@
*/
#include "test_utils.h"
#include "esp_cpu.h"
#define configTEST_DEFAULT_STACK_SIZE 4096
#define configTEST_UNITY_TASK_PRIORITY UNITY_FREERTOS_PRIORITY
#define portTEST_GET_TIME() ((UBaseType_t) esp_cpu_get_cycle_count())
#define portTEST_REF_CLOCK_TYPE uint32_t
#define portTEST_REF_CLOCK_INIT() ref_clock_init()
#define portTEST_REF_CLOCK_DEINIT() ref_clock_deinit()
#define portTEST_REF_CLOCK_GET_TIME() ((uint32_t) ref_clock_get())
#define portTEST_TICKS_TO_REF_CLOCK(ticks) ((ticks) * (1000000/configTICK_RATE_HZ))

View File

@@ -4,76 +4,160 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "unity.h"
#include "freertos_test_utils.h"
#include "portTestMacro.h"
/* ------------------------------------------------------------------------------------------------------------------ */
/*
Test for FreeRTOS vTaskDelayUntil() function by comparing the delay period of
the function to comparing it to ref clock.
Test vTaskDelay
Purpose:
- Test that vTaskDelay is accurate
Procedure:
- The test contains TEST_VTASKDELAY_ITERATIONS number of iterations. For each iteration...
- vTaskDelay(1) to align to next tick boundary
- Store current tick count and current time (using ref clock)
- vTaskDelay for TEST_VTASKDELAY_TICKS
- Get post delay tick count and ref clock time
- For single core, run the test directly from the UnityTask
- For SMP, run the test once on each core (using vTestOnAllCores())
Expected:
- The elapsed ticks should be TEST_VTASKDELAY_TICKS, with 1 tick of error allowed (in case ref clock functions last
long enough to cross a tick boundary).
- The elapsed time should be equivalent to TEST_VTASKDELAY_TICKS tick periods, with 1 tick period of error allowed
(in case ref clock functions last longer that a tick period).
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "unity.h"
#include "test_utils.h"
#if ( INCLUDE_vTaskDelay == 1 )
#define TSK_PRIORITY (UNITY_FREERTOS_PRIORITY + 1)
#define TEST_VTASKDELAY_TICKS 5 // Number of ticks to delay in test
#define TEST_VTASKDELAY_ITERATIONS 5 // Number of iterations in test
#define NO_OF_CYCLES 5
#define NO_OF_TASKS_PER_CORE 2
#define TICKS_TO_DELAY 10
#define TICK_RATE configTICK_RATE_HZ
#define TICK_PERIOD_US (1000000/TICK_RATE)
#define IDEAL_DELAY_PERIOD_MS ((1000*TICKS_TO_DELAY)/TICK_RATE)
#define IDEAL_DELAY_PERIOD_US (IDEAL_DELAY_PERIOD_MS*1000)
#define TICKS_TO_MS(x) (((x)*1000)/TICK_RATE)
#define REF_TO_ROUND_MS(x) (((x)+500)/1000)
static SemaphoreHandle_t task_delete_semphr;
static void delaying_task(void* arg)
static void test_vTaskDelay(void *arg)
{
uint64_t ref_prev, ref_current;
TickType_t last_wake_time;
TickType_t ticks_before_delay;
for (int i = 0; i < TEST_VTASKDELAY_ITERATIONS; i++) {
TickType_t tick_start, tick_end;
portTEST_REF_CLOCK_TYPE ref_clock_start, ref_clock_end;
vTaskDelay(1); //Delay until next tick to synchronize operations to tick boundaries
/* Delay until the next tick boundary */
vTaskDelay(1);
last_wake_time = xTaskGetTickCount();
ticks_before_delay = last_wake_time;
ref_prev = ref_clock_get();
/* Get the current tick count and ref clock time */
tick_start = xTaskGetTickCount();
ref_clock_start = portTEST_REF_CLOCK_GET_TIME();
for(int i = 0; i < NO_OF_CYCLES; i++){
//Delay of TICKS_TO_DELAY
vTaskDelayUntil(&last_wake_time, TICKS_TO_DELAY);
//Get current ref clock
TEST_ASSERT_EQUAL(IDEAL_DELAY_PERIOD_MS, TICKS_TO_MS(xTaskGetTickCount() - ticks_before_delay));
ref_current = ref_clock_get();
TEST_ASSERT_UINT32_WITHIN(TICK_PERIOD_US, IDEAL_DELAY_PERIOD_US, (uint32_t)(ref_current - ref_prev));
ref_prev = ref_current;
ticks_before_delay = last_wake_time;
vTaskDelay(TEST_VTASKDELAY_TICKS);
/* Get the post delay tick count and ref clock time */
tick_end = xTaskGetTickCount();
ref_clock_end = portTEST_REF_CLOCK_GET_TIME();
/* Check that elapsed ticks and ref clock is accurate. We allow 1 tick of error in case vTaskDelay() was called
* right before/after the tick boundary. */
#if ( configUSE_16_BIT_TICKS == 1 )
TEST_ASSERT_UINT16_WITHIN(1, TEST_VTASKDELAY_TICKS, tick_end - tick_start);
#else
TEST_ASSERT_UINT32_WITHIN(1, TEST_VTASKDELAY_TICKS, tick_end - tick_start);
#endif
TEST_ASSERT_UINT32_WITHIN(portTEST_TICKS_TO_REF_CLOCK(1),
portTEST_TICKS_TO_REF_CLOCK(TEST_VTASKDELAY_TICKS),
ref_clock_end - ref_clock_start);
}
//Delete Task after prescribed number of cycles
xSemaphoreGive(task_delete_semphr);
vTaskDelete(NULL);
}
TEST_CASE("Test vTaskDelayUntil", "[freertos]")
TEST_CASE("Tasks: Test vTaskDelay", "[freertos]")
{
task_delete_semphr = xQueueCreateCountingSemaphore(NO_OF_TASKS_PER_CORE*portNUM_PROCESSORS, 0);
ref_clock_init();
portTEST_REF_CLOCK_INIT();
for(int i = 0; i < portNUM_PROCESSORS; i++){
xTaskCreatePinnedToCore(delaying_task, "delay_pinned", 1024, NULL, TSK_PRIORITY, NULL, i);
xTaskCreatePinnedToCore(delaying_task, "delay_no_aff", 1024, NULL, TSK_PRIORITY, NULL, tskNO_AFFINITY);
}
#if ( configNUM_CORES > 1 )
vTestOnAllCores(test_vTaskDelay, NULL, configTEST_DEFAULT_STACK_SIZE, configTEST_UNITY_TASK_PRIORITY - 1);
#else
/* Test vTaskDelay directly on the current core */
test_vTaskDelay(NULL);
#endif
for(int i = 0; i < NO_OF_TASKS_PER_CORE*portNUM_PROCESSORS; i++){
xSemaphoreTake(task_delete_semphr, portMAX_DELAY);
}
//Cleanup
vSemaphoreDelete(task_delete_semphr);
ref_clock_deinit();
portTEST_REF_CLOCK_DEINIT();
}
#endif /* ( INCLUDE_vTaskDelay == 1 ) */
/* ------------------------------------------------------------------------------------------------------------------ */
/*
Test vTaskDelayUntil
Purpose:
- Test that vTaskDelayUntil is accurate
Procedure:
- The test contains TEST_VTASKDELAYUNTIL_ITERATIONS number of iterations. For each iteration...
- vTaskDelay(1) to align to next tick boundary
- Store current tick count and current time (using ref clock)
- Call vTaskDelayUntil() for TEST_VTASKDELAYUNTIL_TICKS, using the stored tick count as the previous wake time
- Get post delay tick count and ref clock time
- For single core, run the test directly from the UnityTask
- For SMP, run the test once on each core (using vTestOnAllCores())
Expected:
- The elapsed ticks should be exactly TEST_VTASKDELAYUNTIL_TICKS since vTaskDelayUntil() is relative to the previous
wake time
- The elapsed time should be equivalent to TEST_VTASKDELAYUNTIL_TICKS tick periods, with 1 tick period of error
allowed (in case ref clock functions last longer that a tick period).
*/
#if ( INCLUDE_xTaskDelayUntil == 1 )
#define TEST_VTASKDELAYUNTIL_TICKS 5 // Number of ticks to delay in test
#define TEST_VTASKDELAYUNTIL_ITERATIONS 5 // Number of iterations in test
static void test_vTaskDelayUntil(void *arg)
{
/* Delay until the next tick boundary */
vTaskDelay(1);
for (int i = 0; i < TEST_VTASKDELAYUNTIL_ITERATIONS; i++) {
TickType_t tick_start, tick_end, last_wake_tick;
portTEST_REF_CLOCK_TYPE ref_clock_start, ref_clock_end;
/* Get the current tick count and ref clock time */
tick_start = xTaskGetTickCount();
last_wake_tick = tick_start;
ref_clock_start = portTEST_REF_CLOCK_GET_TIME();
vTaskDelayUntil(&last_wake_tick, TEST_VTASKDELAYUNTIL_TICKS);
/* Get the post delay tick count and ref clock time */
tick_end = xTaskGetTickCount();
ref_clock_end = portTEST_REF_CLOCK_GET_TIME();
/* Check that the elapsed ticks is accurate. Elapsed ticks should be exact as vTaskDelayUntil() executes a
* delay relative to last_wake_tick. */
TEST_ASSERT_EQUAL(TEST_VTASKDELAYUNTIL_TICKS, tick_end - tick_start);
TEST_ASSERT_EQUAL(tick_end, last_wake_tick);
/* Check that the elapsed ref clock time is accurate. We allow 1 tick time worth of error to account for the
* the execution time of the ref clock functions. */
TEST_ASSERT_UINT32_WITHIN(portTEST_TICKS_TO_REF_CLOCK(1),
portTEST_TICKS_TO_REF_CLOCK(TEST_VTASKDELAYUNTIL_TICKS),
ref_clock_end - ref_clock_start);
}
}
TEST_CASE("Tasks: Test vTaskDelayUntil", "[freertos]")
{
portTEST_REF_CLOCK_INIT();
#if ( configNUM_CORES > 1 )
vTestOnAllCores(test_vTaskDelayUntil, NULL, configTEST_DEFAULT_STACK_SIZE, configTEST_UNITY_TASK_PRIORITY - 1);
#else
/* Test vTaskDelay directly on the current core */
test_vTaskDelayUntil(NULL);
#endif
portTEST_REF_CLOCK_DEINIT();
}
#endif /* ( INCLUDE_xTaskDelayUntil == 1 ) */