From 1e376573859c588a3dc975823176e3af1999cc70 Mon Sep 17 00:00:00 2001 From: Alwin Berger Date: Sun, 26 Feb 2023 22:44:59 +0100 Subject: [PATCH] add micro bench for interrupt times --- .../Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile | 6 + .../CORTEX_M3_MPS2_QEMU_GCC/arbitrary_loads.c | 4 +- FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c | 6 +- .../CORTEX_M3_MPS2_QEMU_GCC/main_micro_int.c | 207 ++++++++++++++++++ .../CORTEX_M3_MPS2_QEMU_GCC/main_waters.c | 28 ++- 5 files changed, 237 insertions(+), 14 deletions(-) create mode 100644 FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_micro_int.c diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile index 7e60d068..522a47a5 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile @@ -98,6 +98,11 @@ ifeq ($(BRANCHLESS_DEMO), 1) SOURCE_FILES += main_micro_branchless.c CFLAGS := -DmainCREATE_BRANCHLESS_DEMO=1 +else +ifeq ($(INT_DEMO), 1) + SOURCE_FILES += main_micro_int.c + + CFLAGS := -DmainCREATE_INT_DEMO=1 else SOURCE_FILES += main_blinky.c @@ -111,6 +116,7 @@ endif endif endif endif +endif DEFINES := -DQEMU_SOC_MPS2 -DHEAP3 diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/arbitrary_loads.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/arbitrary_loads.c index cb16149f..da366b97 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/arbitrary_loads.c +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/arbitrary_loads.c @@ -6,7 +6,9 @@ volatile long _NONSENSE_VAR = 0; #define NS_PER_INS (1000000000 / configCPU_CLOCK_HZ) // 20MHz #define INS_PER_LOOP 5 // got this multiplier by testing with the goal of getting a 100 ms or 100 tick period #define INS_PER_PRINT 117 // got this multiplier by testing with the goal of getting a 100 ms or 100 tick period, 2 digits -#define GLOBAL_WCET_MULT 16 // Multiplier to increase all waiting periods to make the schedule more tight an force preemptions +#ifndef GLOBAL_WCET_MULT + #define GLOBAL_WCET_MULT 1 // Multiplier to increase all waiting periods to make the schedule more tight an force preemptions +#endif #define WASTE_TIME(X) for (int i=0; i<=((X*GLOBAL_WCET_MULT)/(NS_PER_INS*INS_PER_LOOP)); i++) {_NONSENSE_VAR+=i;} #define PRINT_TIME(X,Y) for (int i=0; i<=((X*GLOBAL_WCET_MULT)/((NS_PER_INS*INS_PER_PRINT))); i++) {puts(Y);} // #define PRINT_TIME(X,Y) WASTE_TIME(X) diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c index bf0b9a80..cf74e0c3 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c @@ -95,8 +95,12 @@ int main() { main_branchless(); } + #elif ( mainCREATE_INT_DEMO == 1 ) + { + main_micro_int(); + } #else - + { #error "Invalid Selection...\nPlease Select a Demo application from the main command" } diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_micro_int.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_micro_int.c new file mode 100644 index 00000000..b7448c9e --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_micro_int.c @@ -0,0 +1,207 @@ +/* + * FreeRTOS V202111.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#include +#include +#include +#include +#include +#include "arbitrary_loads.c" +/* +Interrupt Demo without priority inheritance +Async | I +A | RxxP xxxVD +B | RxxxD +C RxxxPx xx xxxV xxxD +*/ +// #undef PRINT_TIME +// #define PRINT_TIME(X,Y) WASTE_TIME(X) +#define WCET_CLAMP(X, LB, UB, LABEL) PRINT_TIME(UB,LABEL) + +__attribute__((noinline)) static void trigger_Qemu_break( void ) +{ + puts("Trigger"); +} + +// Begin Input Stuff +volatile unsigned char FUZZ_INPUT[4096] = {0xa,0xb,0xc,0xd,0xe,0xf}; +volatile uint32_t FUZZ_LENGTH = 32; +volatile uint32_t FUZZ_POINTER = 0; + +static unsigned char fuzz_char_next(void) { + // printf("Get next Input from %lx \n",FUZZ_INPUT); + if (FUZZ_POINTER < FUZZ_LENGTH) { + FUZZ_POINTER++; + // printf("Input no. %d %x\n",FUZZ_POINTER-1,FUZZ_INPUT[FUZZ_POINTER-1]); + return FUZZ_INPUT[FUZZ_POINTER-1]; + } else { + // puts("End of Input"); + // Exausted inputs early + trigger_Qemu_break(); + } +} +static uint16_t fuzz_short_next(void) { + unsigned char field[2]; + field[0]=fuzz_char_next(); + field[1]=fuzz_char_next(); + uint16_t* sf = (uint16_t*) field; + return *sf; +} +static uint32_t fuzz_long_next(void) { + unsigned char field[4]; + field[0]=fuzz_char_next(); + field[1]=fuzz_char_next(); + field[2]=fuzz_char_next(); + field[3]=fuzz_char_next(); + uint32_t* sf = (uint32_t*) field; + return *sf; +} +// End Input Stuff +static void prvReplicaA( void * pvParameters ); +static void prvReplicaB( void * pvParameters ); +static void prvReplicaC( void * pvParameters ); +static void prvSpor( void * pvParameters ); + +#define mainREPLICA_SPOR_TASK_PRIORITY ( tskIDLE_PRIORITY + 6 ) +#define mainREPLICA_A_TASK_PRIORITY ( tskIDLE_PRIORITY + 5 ) +#define mainREPLICA_B_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 ) +#define mainREPLICA_C_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) + +// Handles for direct messages +static TaskHandle_t xReplA = NULL; +static TaskHandle_t xReplB = NULL; +static TaskHandle_t xReplC = NULL; + +static SemaphoreHandle_t xSemaphoreAC; + +void main_micro_int( void ) +{ + xSemaphoreAC = xSemaphoreCreateBinary(); + xSemaphoreGive(xSemaphoreAC); + + if( xSemaphoreAC != NULL ) + { + /* Start the two tasks as described in the comments at the top of this + * file. */ + xTaskCreate( prvReplicaA, /* The function that implements the task. */ + "ReplA", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ + configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this case. */ + mainREPLICA_A_TASK_PRIORITY, /* The priority assigned to the task. */ + &xReplA ); /* The task handle is not required, so NULL is passed. */ + + xTaskCreate( prvReplicaB, /* The function that implements the task. */ + "ReplB", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ + configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this case. */ + mainREPLICA_B_TASK_PRIORITY, /* The priority assigned to the task. */ + &xReplB ); /* The task handle is not required, so NULL is passed. */ + + xTaskCreate( prvReplicaC, /* The function that implements the task. */ + "ReplC", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ + configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this case. */ + mainREPLICA_C_TASK_PRIORITY, /* The priority assigned to the task. */ + &xReplC ); /* The task handle is not required, so NULL is passed. */ + + xTaskCreate( prvSpor, /* The function that implements the task. */ + "Spor", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ + configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this case. */ + mainREPLICA_SPOR_TASK_PRIORITY, /* The priority assigned to the task. */ + NULL ); /* The task handle is not required, so NULL is passed. */ + + /* Start the tasks and timer running. */ + vTaskStartScheduler(); + } + + /* If all is well, the scheduler will now be running, and the following + * line will never be reached. If the following line does execute, then + * there was insufficient FreeRTOS heap memory available for the Idle and/or + * timer tasks to be created. See the memory management section on the + * FreeRTOS web site for more details on the FreeRTOS heap + * http://www.freertos.org/a00111.html. */ + for( ; ; ) + { + } +} + +static void prvReplicaA( void * pvParameters ) +{ + TickType_t xLastWakeTime = xTaskGetTickCount(); + vTaskDelayUntil( &xLastWakeTime, 5 / portTICK_PERIOD_MS ); + puts("A Ready"); + while (1) + { + xSemaphoreTake(xSemaphoreAC, portMAX_DELAY); + uint32_t x = fuzz_long_next(); + WCET_CLAMP(x>>5,0, 5 * 1000 * 1000, "A ") + xSemaphoreGive(xSemaphoreAC); + trigger_Qemu_break(); + while (1) { + } + } +} +static void prvReplicaB( void * pvParameters ) +{ + while (1) + { + ulTaskNotifyTake(pdTRUE,portMAX_DELAY); + uint32_t x = fuzz_long_next(); + WCET_CLAMP(x>>5,0, 5 * 1000 * 1000, "B ") + } +} +static void prvReplicaC( void * pvParameters ) +{ + while (1) + { + xSemaphoreTake(xSemaphoreAC, portMAX_DELAY); + uint32_t x = fuzz_long_next(); + WCET_CLAMP(x>>5, 6 * 1000 * 1000, 10 * 1000 * 1000, "C ") + xSemaphoreGive(xSemaphoreAC); + } +} +static void prvSpor( void * pvParameters ) +{ + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = 7 / portTICK_PERIOD_MS; + vTaskDelayUntil( &xLastWakeTime, xFrequency ); + while (1) + { + puts("Fire"); + xTaskNotifyGive(xReplB); + vTaskDelayUntil( &xLastWakeTime, xFrequency * 10000 ); + } + +} + +void isr_starter( void ) +{ + puts("Fire"); + xTaskNotifyGive(xReplB); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_waters.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_waters.c index 6af0a0b7..d6861e8c 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_waters.c +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_waters.c @@ -41,8 +41,8 @@ prvVoterTask will wait on ReplicateA&B If they disagree ReplicateC will be started by mutex. If all the Replicates disagree now the sampler will be engaged once more */ -// include tacle benches +#define GLOBAL_WCET_MULT 16 // Multiplier to increase all waiting periods to make the schedule more tight an force preemptions #include "arbitrary_loads.c" __attribute__((noinline)) static void trigger_Qemu_break( void ) @@ -439,18 +439,21 @@ static void prvTask1129( void * pvParameters ) { for( ;; ){ // if (--period_counter==0) {puts("End");} // Actions -------------------------------------- - // Exectime: f(x,y) = if !y ? 80000+x : x (<40k) - // Output: g(x) = x % 4 + // Exectime: f(x,y) = if y && rng(x) ? c1+x : c2+x + // Output: g(x) = y && rng(x) + // longmax - shortmax: 69505 + // most likely long case, which causes a short case in next task uint32_t x = (uint32_t)fuzz_short_next(); int y = ulTaskNotifyTake(pdFALSE, 0); + int do_short_run = y && CHANCE_1_IN_POWOF2(x, 3); int torun = 0; - if (!y) { - torun = 80000 + x; + if (do_short_run) { + torun = 10000 + x; } else { - torun = x; + torun = 80000 + x; } WCET_CLAMP(torun, 0, 145040, TASK_1129_MESSAGE) - xTaskNotify(xTask416, x % 4, eSetValueWithOverwrite); + xTaskNotify(xTask416, do_short_run, eSetValueWithOverwrite); // --------------------------------------------- vTaskDelayUntil( &xLastWakeTime, xFrequency );} } @@ -461,16 +464,17 @@ static void prvTask416( void * pvParameters ) { const TickType_t xFrequency = 10 / portTICK_PERIOD_MS; for( ;; ){ // Actions -------------------------------------- - // Exectime: f(x,y) = if y == 3 ? c-x : c+x + // Exectime: f(x,y) = if y ? c1+2*x : c2-x + // longmax - shortmax: 86955 uint32_t x = (uint32_t)fuzz_short_next(); int y = ulTaskNotifyTake(pdFALSE, 0); int torun = 0; - if (y==3) { - torun = 70000 + x; + if (y) { + torun = x*3; } else { - torun = 70000 - x; + torun = 40000 - CLAMP_CEILING(x, 40000); } - PRINT_TIME(126955, TASK_416_MESSAGE) + WCET_CLAMP(torun, 10000, 126955, TASK_416_MESSAGE) // --------------------------------------------- vTaskDelayUntil( &xLastWakeTime, xFrequency );} }