esp-idf/components/freertos/test_apps/freertos/kernel/tasks/test_preemption.c

124 wiersze
3.8 KiB
C

/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
Unit tests for FreeRTOS preemption
*/
#include <esp_types.h>
#include <stdio.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "unity.h"
#include "esp_cpu.h"
#include "test_utils.h"
#include "sdkconfig.h"
static volatile bool trigger;
static volatile bool flag;
#ifndef CONFIG_FREERTOS_SMP
#define MAX_YIELD_COUNT 10000
#else
//TODO: IDF-5081
#define MAX_YIELD_COUNT 17000
#endif // CONFIG_FREERTOS_SMP
/* Task:
- Waits for 'trigger' variable to be set
- Reads the cycle count on this CPU
- Pushes it into a queue supplied as a param
- Busy-waits until the main task terminates it
*/
static void task_send_to_queue(void *param)
{
QueueHandle_t queue = (QueueHandle_t) param;
uint32_t ccount;
while (!trigger) {}
ccount = esp_cpu_get_cycle_count();
flag = true;
xQueueSendToBack(queue, &ccount, 0);
/* This is to ensure that higher priority task
won't wake anyhow, due to this task terminating.
The task runs until terminated by the main task.
*/
while (1) {}
}
TEST_CASE("Yield from lower priority task, same CPU", "[freertos]")
{
/* Do this 3 times, mostly for the benchmark value - the first
run includes a cache miss so uses more cycles than it should. */
for (int i = 0; i < 3; i++) {
TaskHandle_t sender_task;
QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
flag = false;
trigger = false;
/* "yield" task sits on our CPU, lower priority to us */
xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1, &sender_task, UNITY_FREERTOS_CPU);
vTaskDelay(1); /* make sure everything is set up */
trigger = true;
uint32_t yield_ccount, now_ccount, delta;
TEST_ASSERT(xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS));
now_ccount = esp_cpu_get_cycle_count();
TEST_ASSERT(flag);
delta = now_ccount - yield_ccount;
printf("Yielding from lower priority task took %"PRIu32" cycles\n", delta);
TEST_ASSERT(delta < MAX_YIELD_COUNT);
vTaskDelete(sender_task);
vQueueDelete(queue);
}
}
#if (CONFIG_FREERTOS_NUMBER_OF_CORES == 2) && !CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
TEST_CASE("Yield from lower priority task, other CPU", "[freertos]")
{
uint32_t trigger_ccount, yield_ccount, now_ccount, delta;
/* Do this 3 times, mostly for the benchmark value - the first
run includes a cache miss so uses more cycles than it should. */
for (int i = 0; i < 3; i++) {
TaskHandle_t sender_task;
QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
trigger = false;
flag = false;
/* "send_to_queue" task sits on the other CPU, lower priority to us */
xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1,
&sender_task, !UNITY_FREERTOS_CPU);
vTaskDelay(2); /* make sure everything is set up */
trigger = true;
trigger_ccount = esp_cpu_get_cycle_count();
// yield_ccount is not useful in this test as it's the other core's CCOUNT
// so we use trigger_ccount instead
TEST_ASSERT(xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS));
now_ccount = esp_cpu_get_cycle_count();
TEST_ASSERT(flag);
delta = now_ccount - trigger_ccount;
printf("Yielding from task on other core took %"PRIu32" cycles\n", delta);
TEST_ASSERT(delta < MAX_YIELD_COUNT);
vQueueDelete(queue);
vTaskDelete(sender_task);
}
}
#endif