From f2952de3a58c3d5d705d84c17ee7a15b3b6d7327 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 13 Feb 2017 16:53:33 +1100 Subject: [PATCH] freertos spinlocks/portmux: Add combination unit tests & microbenchmarks --- components/freertos/test/test_spinlocks.c | 133 ++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 components/freertos/test/test_spinlocks.c diff --git a/components/freertos/test/test_spinlocks.c b/components/freertos/test/test_spinlocks.c new file mode 100644 index 0000000000..2ddbb07f85 --- /dev/null +++ b/components/freertos/test/test_spinlocks.c @@ -0,0 +1,133 @@ +/* + Combined unit tests & benchmarking for spinlock "portMUX" functionality +*/ + +#include +#include +#include "rom/ets_sys.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/xtensa_api.h" +#include "unity.h" +#include "soc/uart_reg.h" +#include "soc/dport_reg.h" +#include "soc/io_mux_reg.h" +#include "soc/cpu.h" + +#define REPEAT_OPS 10000 + +static uint32_t start, end; + +#define BENCHMARK_START() do { \ + RSR(CCOUNT, start); \ + } while(0) + +#define BENCHMARK_END(OPERATION) do { \ + RSR(CCOUNT, end); \ + printf("%s took %d cycles/op (%d cycles for %d ops)\n", \ + OPERATION, (end - start)/REPEAT_OPS, \ + (end - start), REPEAT_OPS); \ + } while(0) + +TEST_CASE("portMUX spinlocks (no contention)", "[freertos]") +{ + portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; + BENCHMARK_START(); + + for (int i = 0; i < REPEAT_OPS; i++) { + portENTER_CRITICAL(&mux); + portEXIT_CRITICAL(&mux); + } + BENCHMARK_END("no contention lock"); +} + +TEST_CASE("portMUX recursive locks (no contention)", "[freertos]") +{ + portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; + BENCHMARK_START(); + + const int RECURSE_COUNT = 25; + + for (int i = 0; i < REPEAT_OPS / RECURSE_COUNT; i++) { + for (int j = 0; j < RECURSE_COUNT; j++) { + portENTER_CRITICAL(&mux); + } + for (int j = 0; j < RECURSE_COUNT; j++) { + portEXIT_CRITICAL(&mux); + } + } + BENCHMARK_END("no contention recursive"); +} + +static volatile int shared_value; +static portMUX_TYPE shared_mux; +static xSemaphoreHandle done_sem; + +static void task_shared_value_increment(void *ignore) +{ + for (int i = 0; i < REPEAT_OPS; i++) { + portENTER_CRITICAL(&shared_mux); + shared_value++; + portEXIT_CRITICAL(&shared_mux); + } + xSemaphoreGive(done_sem); + vTaskDelete(NULL); +} + +TEST_CASE("portMUX cross-core locking", "[freertos]") +{ + done_sem = xSemaphoreCreateCounting(2, 0); + vPortCPUInitializeMutex(&shared_mux); + shared_value = 0; + + BENCHMARK_START(); + + xTaskCreatePinnedToCore(task_shared_value_increment, "INC0", 2048, NULL, UNITY_FREERTOS_PRIORITY + 1, NULL, UNITY_FREERTOS_CPU ? 0 : 1); + xTaskCreatePinnedToCore(task_shared_value_increment, "INC1", 2048, NULL, UNITY_FREERTOS_PRIORITY + 1, NULL, UNITY_FREERTOS_CPU); + + for(int i = 0; i < 2; i++) { + if(!xSemaphoreTake(done_sem, 10000/portTICK_PERIOD_MS)) { + TEST_FAIL_MESSAGE("done_sem not released by test task"); + } + } + + BENCHMARK_END("cross-core incrementing"); + vSemaphoreDelete(done_sem); + + TEST_ASSERT_EQUAL_INT(REPEAT_OPS * 2, shared_value); +} + +TEST_CASE("portMUX high contention", "[freertos]") +{ + const int TOTAL_TASKS = 8; /* half on each core */ + done_sem = xSemaphoreCreateCounting(TOTAL_TASKS, 0); + vPortCPUInitializeMutex(&shared_mux); + shared_value = 0; + + BENCHMARK_START(); + + for (int i = 0; i < TOTAL_TASKS / 2; i++) { + /* as each task has a higher priority than previous, expect + them to preempt the earlier created task, at least on the + other core (this core has the unity task, until that + blocks)... */ + xTaskCreatePinnedToCore(task_shared_value_increment, "INC0", 2048, NULL, tskIDLE_PRIORITY + 1 + i, NULL, UNITY_FREERTOS_CPU ? 0 : 1); + xTaskCreatePinnedToCore(task_shared_value_increment, "INC1", 2048, NULL, tskIDLE_PRIORITY + 1 + i, NULL, UNITY_FREERTOS_CPU); + } + + for(int i = 0; i < TOTAL_TASKS; i++) { + if(!xSemaphoreTake(done_sem, 10000/portTICK_PERIOD_MS)) { + TEST_FAIL_MESSAGE("done_sem not released by test task"); + } + } + + BENCHMARK_END("cross-core high contention"); + vSemaphoreDelete(done_sem); + + TEST_ASSERT_EQUAL_INT(REPEAT_OPS * TOTAL_TASKS, shared_value); +} + + -- 2.40.0