mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-06 14:14:33 +02:00
Merge branch 'feature/freertos_task_delay_test_refactor' into 'master'
FreeRTOS: Refactor vTaskDelay() tests See merge request espressif/esp-idf!20271
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
# For refactored FreeRTOS unit tests, we need to support #include "xxx.h" of FreeRTOS headers
|
# For refactored FreeRTOS unit tests, we need to support #include "xxx.h" of FreeRTOS headers
|
||||||
idf_component_get_property(FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
|
idf_component_get_property(FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
|
||||||
|
|
||||||
idf_component_register(SRC_DIRS integration/event_groups
|
idf_component_register(SRC_DIRS integration # For freertos_test_utils.c
|
||||||
|
integration/event_groups
|
||||||
integration/queue
|
integration/queue
|
||||||
integration/stream_buffer
|
integration/stream_buffer
|
||||||
integration/tasks
|
integration/tasks
|
||||||
|
72
components/freertos/test/integration/freertos_test_utils.c
Normal file
72
components/freertos/test/integration/freertos_test_utils.c
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
#include "freertos_test_utils.h"
|
||||||
|
|
||||||
|
#if ( configNUM_CORES > 1 )
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const TestFunction_t pxTestCode;
|
||||||
|
void * const pvTestCodeArg;
|
||||||
|
const SemaphoreHandle_t xTaskDoneSem;
|
||||||
|
} TestArgs_t;
|
||||||
|
|
||||||
|
static void test_func_task( void * pvParameters )
|
||||||
|
{
|
||||||
|
TestArgs_t * pxTestArgs = ( TestArgs_t * ) pvParameters;
|
||||||
|
/* Call the test function */
|
||||||
|
pxTestArgs->pxTestCode( pxTestArgs->pvTestCodeArg );
|
||||||
|
/* Indicate completion to the creation task and wait to be deleted. */
|
||||||
|
xSemaphoreGive( pxTestArgs->xTaskDoneSem );
|
||||||
|
vTaskSuspend( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
void vTestOnAllCores( TestFunction_t pxTestCode, void * pvTestCodeArg, uint32_t ulStackDepth, UBaseType_t uxPriority )
|
||||||
|
{
|
||||||
|
SemaphoreHandle_t xTaskDoneSem = xSemaphoreCreateCounting( configNUM_CORES, 0 );
|
||||||
|
TaskHandle_t xTaskHandles[ configNUM_CORES ];
|
||||||
|
TestArgs_t xTestArgs = {
|
||||||
|
.pxTestCode = pxTestCode,
|
||||||
|
.pvTestCodeArg = pvTestCodeArg,
|
||||||
|
.xTaskDoneSem = xTaskDoneSem,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Create a separate task on each core to run the test function */
|
||||||
|
for( BaseType_t xCoreID = 0; xCoreID < configNUM_CORES; xCoreID++ ) {
|
||||||
|
#if ( CONFIG_FREERTOS_SMP == 1 )
|
||||||
|
xTaskCreateAffinitySet( test_func_task,
|
||||||
|
"task",
|
||||||
|
ulStackDepth,
|
||||||
|
( void * ) &xTestArgs,
|
||||||
|
uxPriority,
|
||||||
|
( UBaseType_t ) ( 1 << xCoreID ),
|
||||||
|
&( xTaskHandles[ xCoreID ] ) );
|
||||||
|
#else
|
||||||
|
xTaskCreatePinnedToCore( test_func_task,
|
||||||
|
"task",
|
||||||
|
ulStackDepth,
|
||||||
|
( void * ) &xTestArgs,
|
||||||
|
uxPriority,
|
||||||
|
&( xTaskHandles[ xCoreID ] ),
|
||||||
|
xCoreID );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for each tasks to complete test */
|
||||||
|
for( BaseType_t xCoreID = 0; xCoreID < configNUM_CORES; xCoreID++ ) {
|
||||||
|
xSemaphoreTake( xTaskDoneSem, portMAX_DELAY );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
for( BaseType_t xCoreID = 0; xCoreID < configNUM_CORES; xCoreID++ ) {
|
||||||
|
vTaskDelete( xTaskHandles[ xCoreID ] );
|
||||||
|
}
|
||||||
|
vSemaphoreDelete( xTaskDoneSem );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ( configNUM_CORES > 1 ) */
|
32
components/freertos/test/integration/freertos_test_utils.h
Normal file
32
components/freertos/test/integration/freertos_test_utils.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
|
||||||
|
#if ( configNUM_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prototype for test function.
|
||||||
|
*
|
||||||
|
* A test function can be passed to vTestOnAllCores() which will run the test function from a task on each core.
|
||||||
|
*/
|
||||||
|
typedef void (* TestFunction_t)( void * );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Run a test function on each core
|
||||||
|
*
|
||||||
|
* This function will internally create a task pinned to each core, where each task will call the provided test
|
||||||
|
* function. This function will block until all cores finish executing the test function.
|
||||||
|
*
|
||||||
|
* @param pxTestCode Test function
|
||||||
|
* @param pvTestCodeArg Argument provided to test function
|
||||||
|
* @param ulStackDepth Stack depth of the created tasks
|
||||||
|
* @param uxPriority Priority of the created tasks
|
||||||
|
*/
|
||||||
|
void vTestOnAllCores( TestFunction_t pxTestCode, void * pvTestCodeArg, uint32_t ulStackDepth, UBaseType_t uxPriority );
|
||||||
|
|
||||||
|
#endif /* ( configNUM_CORES > 1 ) */
|
@@ -5,9 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "test_utils.h"
|
#include "test_utils.h"
|
||||||
#include "esp_cpu.h"
|
|
||||||
|
|
||||||
#define configTEST_DEFAULT_STACK_SIZE 4096
|
#define configTEST_DEFAULT_STACK_SIZE 4096
|
||||||
#define configTEST_UNITY_TASK_PRIORITY UNITY_FREERTOS_PRIORITY
|
#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))
|
||||||
|
@@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Test for FreeRTOS vTaskDelayUntil() function by comparing the delay period of
|
|
||||||
the function to comparing it to ref clock.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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"
|
|
||||||
|
|
||||||
#define TSK_PRIORITY (UNITY_FREERTOS_PRIORITY + 1)
|
|
||||||
|
|
||||||
#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)
|
|
||||||
{
|
|
||||||
uint64_t ref_prev, ref_current;
|
|
||||||
TickType_t last_wake_time;
|
|
||||||
TickType_t ticks_before_delay;
|
|
||||||
|
|
||||||
vTaskDelay(1); //Delay until next tick to synchronize operations to tick boundaries
|
|
||||||
|
|
||||||
last_wake_time = xTaskGetTickCount();
|
|
||||||
ticks_before_delay = last_wake_time;
|
|
||||||
ref_prev = ref_clock_get();
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Delete Task after prescribed number of cycles
|
|
||||||
xSemaphoreGive(task_delete_semphr);
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Test vTaskDelayUntil", "[freertos]")
|
|
||||||
{
|
|
||||||
task_delete_semphr = xQueueCreateCountingSemaphore(NO_OF_TASKS_PER_CORE*portNUM_PROCESSORS, 0);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
163
components/freertos/test/integration/tasks/test_task_delay.c
Normal file
163
components/freertos/test/integration/tasks/test_task_delay.c
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* 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 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).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if ( INCLUDE_vTaskDelay == 1 )
|
||||||
|
|
||||||
|
#define TEST_VTASKDELAY_TICKS 5 // Number of ticks to delay in test
|
||||||
|
#define TEST_VTASKDELAY_ITERATIONS 5 // Number of iterations in test
|
||||||
|
|
||||||
|
static void test_vTaskDelay(void *arg)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Delay until the next tick boundary */
|
||||||
|
vTaskDelay(1);
|
||||||
|
|
||||||
|
/* Get the current tick count and ref clock time */
|
||||||
|
tick_start = xTaskGetTickCount();
|
||||||
|
ref_clock_start = portTEST_REF_CLOCK_GET_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Tasks: Test vTaskDelay", "[freertos]")
|
||||||
|
{
|
||||||
|
portTEST_REF_CLOCK_INIT();
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
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 ) */
|
Reference in New Issue
Block a user