From 11f13aaf88454de69aed793dc382f0606ac13dff Mon Sep 17 00:00:00 2001 From: Gabriel Wang Date: Wed, 22 Dec 2021 23:11:09 +0000 Subject: [PATCH] Add support for FreeRTOS --- GorgonMeducer.perf_counter.pdsc | 99 +++++--- README.md | 2 +- .../GorgonMeducer.perf_counter.1.7.1.pack | Bin 0 -> 40472 bytes cmsis-pack/GorgonMeducer.perf_counter.pdsc | 99 +++++--- gen_pack.sh | 2 + lib/perf_counter.h | 2 +- lib/perf_counter.lib | Bin 7702 -> 9638 bytes lib/perf_os_patch_freertos.c | 231 ++++++++++++++++++ lib/perf_os_patch_rtx5.c | 56 +---- perf_counter.c | 58 +++++ perf_counter.h | 2 +- perf_os_patch_freertos.c | 231 ++++++++++++++++++ perf_os_patch_rtx5.c | 56 +---- 13 files changed, 681 insertions(+), 157 deletions(-) create mode 100644 cmsis-pack/GorgonMeducer.perf_counter.1.7.1.pack create mode 100644 lib/perf_os_patch_freertos.c create mode 100644 perf_os_patch_freertos.c diff --git a/GorgonMeducer.perf_counter.pdsc b/GorgonMeducer.perf_counter.pdsc index 6fb1351..a4a1313 100644 --- a/GorgonMeducer.perf_counter.pdsc +++ b/GorgonMeducer.perf_counter.pdsc @@ -3,7 +3,7 @@ GorgonMeducer perf_counter - A dedicated performance counter for Cortex-M systick. It shares the SysTick with users' original SysTick function without interfere it. This library will bring new functionalities, such as performance counter, delay_us and clock() service defined in time.h + A dedicated performance counter for the Cortex-M Systick. It shares the SysTick with users' original SysTick function without interfering with it. This library will bring new functionalities, such as performance counter, delay_us and clock() service defined in time.h https://raw.githubusercontent.com/GorgonMeducer/perf_counter/CMSIS-Pack/cmsis-pack/ https://github.com/GorgonMeducer/perf_counter/issues lib/LICENSE @@ -16,6 +16,10 @@ https://github.com/GorgonMeducer/perf_counter.git + + - Add support for FreeRTOS + - Other minor update + - Add new feature for RTOS. Now you can get cycle information for the current thread. - Other minor update @@ -81,9 +85,16 @@ - + Require RTX5 Support + + + + + Require FreeRTOS Support + + @@ -143,35 +154,67 @@ --> - - A dedicated performance counter for Cortex-M systick. - - - - - - + + A dedicated performance counter for Cortex-M systick. + + + A dedicated performance counter for Cortex-M systick. + + + + + + - - A dedicated performance counter for Cortex-M systick. - - - - - - - - - - A Patch for RTX5 - - - - + + A dedicated performance counter for Cortex-M systick. + + + + + + + + + + A Patch for RTX5 + + + + //! \brief Enable RTOS Patch for perf_counter #define __PERF_CNT_USE_RTOS__ - - + + + + + A Patch for FreeRTOS + + + + +//! \brief Enable RTOS Patch for perf_counter +#define __PERF_CNT_USE_RTOS__ + + +#define traceTASK_SWITCHED_OUT_DISABLE +#define traceTASK_SWITCHED_IN_DISABLE + +#if defined(MPU_WRAPPERS_INCLUDED_FROM_API_FILE) + + +extern void __freertos_evr_on_task_switched_out (void *ptTCB); +extern void __freertos_evr_on_task_switched_in(void *ptTCB, uint32_t uxTopPriority) ; + +# define traceTASK_SWITCHED_OUT() \ + __freertos_evr_on_task_switched_out(pxCurrentTCB) +# define traceTASK_SWITCHED_IN() \ + __freertos_evr_on_task_switched_in(pxCurrentTCB, uxTopReadyPriority) + +#endif + + + diff --git a/README.md b/README.md index 41294b0..29ba98d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # perf_counter -A dedicated performance counter for Cortex-M systick. It shares the SysTick with users' original SysTick function without interfere it. This library will bring new functionalities, such as performance counter, delay_us and clock() service defined in time.h +A dedicated performance counter for Cortex-M systick. It shares the SysTick with users' original SysTick function without interfering with it. This library will bring new functionalities, such as performance counter, delay_us and clock() service defined in time.h. diff --git a/cmsis-pack/GorgonMeducer.perf_counter.1.7.1.pack b/cmsis-pack/GorgonMeducer.perf_counter.1.7.1.pack new file mode 100644 index 0000000000000000000000000000000000000000..5ecf0266e4adf6bc6c6050bbe9cde5e3a50f9552 GIT binary patch literal 40472 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 GorgonMeducer perf_counter - A dedicated performance counter for Cortex-M systick. It shares the SysTick with users' original SysTick function without interfere it. This library will bring new functionalities, such as performance counter, delay_us and clock() service defined in time.h + A dedicated performance counter for the Cortex-M Systick. It shares the SysTick with users' original SysTick function without interfering with it. This library will bring new functionalities, such as performance counter, delay_us and clock() service defined in time.h https://raw.githubusercontent.com/GorgonMeducer/perf_counter/CMSIS-Pack/cmsis-pack/ https://github.com/GorgonMeducer/perf_counter/issues lib/LICENSE @@ -16,6 +16,10 @@ https://github.com/GorgonMeducer/perf_counter.git + + - Add support for FreeRTOS + - Other minor update + - Add new feature for RTOS. Now you can get cycle information for the current thread. - Other minor update @@ -81,9 +85,16 @@ - + Require RTX5 Support + + + + + Require FreeRTOS Support + + @@ -143,35 +154,67 @@ --> - - A dedicated performance counter for Cortex-M systick. - - - - - - + + A dedicated performance counter for Cortex-M systick. + + + A dedicated performance counter for Cortex-M systick. + + + + + + - - A dedicated performance counter for Cortex-M systick. - - - - - - - - - - A Patch for RTX5 - - - - + + A dedicated performance counter for Cortex-M systick. + + + + + + + + + + A Patch for RTX5 + + + + //! \brief Enable RTOS Patch for perf_counter #define __PERF_CNT_USE_RTOS__ - - + + + + + A Patch for FreeRTOS + + + + +//! \brief Enable RTOS Patch for perf_counter +#define __PERF_CNT_USE_RTOS__ + + +#define traceTASK_SWITCHED_OUT_DISABLE +#define traceTASK_SWITCHED_IN_DISABLE + +#if defined(MPU_WRAPPERS_INCLUDED_FROM_API_FILE) + + +extern void __freertos_evr_on_task_switched_out (void *ptTCB); +extern void __freertos_evr_on_task_switched_in(void *ptTCB, uint32_t uxTopPriority) ; + +# define traceTASK_SWITCHED_OUT() \ + __freertos_evr_on_task_switched_out(pxCurrentTCB) +# define traceTASK_SWITCHED_IN() \ + __freertos_evr_on_task_switched_in(pxCurrentTCB, uxTopReadyPriority) + +#endif + + + diff --git a/gen_pack.sh b/gen_pack.sh index 4af51f5..d501674 100644 --- a/gen_pack.sh +++ b/gen_pack.sh @@ -54,6 +54,7 @@ PACK_BASE_FILES=" systick_wrapper_gcc.s systick_wrapper_ual.s perf_os_patch_rtx5.c + perf_os_patch_freertos.c LICENSE README.md " @@ -139,6 +140,7 @@ fi cp -f ./$PACK_VENDOR.$PACK_NAME.pdsc ${PACK_BUILD} cp -f ./perf_os_patch_rtx5.c ./lib +cp -f ./perf_os_patch_freertos.c ./lib cp -f ./perf_counter.h ./lib # directories diff --git a/lib/perf_counter.h b/lib/perf_counter.h index 2a7980e..0a53a3c 100644 --- a/lib/perf_counter.h +++ b/lib/perf_counter.h @@ -341,7 +341,7 @@ extern void start_task_cycle_counter(void); */ extern int32_t stop_task_cycle_counter(void); -#else +#elif !defined(__IMPLEMENT_PERF_COUNTER) # define start_task_cycle_counter start_cycle_counter # define stop_task_cycle_counter stop_cycle_counter diff --git a/lib/perf_counter.lib b/lib/perf_counter.lib index 850ada279aecf07beac2e278697bbea741cc5760..47b002afe7c28592878cf68c6dacda52a87bd76b 100644 GIT binary patch literal 9638 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 delta 2624 zcmaJ@UuauZ82|3M?b0UwvnFeA+q6m6bx9LSle9KXx~iSdQl?0mLJLls*3Px+w2p07 zDWr;8AC#$Qj3L8SA4(tGP&%d}iVq?|K?NW7HVcXjL4A|q6#RYn+$1OW!H?X0=l7l8 z_q*Rc-#Itgy#M^zo7wE(&`3mC-b+Ndj935vvThJrH)NN;_pPm`9KKR9=?68i^9|ZZ*Bo32Z`jIC0L~;& zfxd%a#XNKZf_Vf~0Uq*Tu%O{9;4fD9H!@a<#H0%dnDdU2N%b?YAz(X$q z=Yf@Z=s9P^1sSxTo~Xi62PtQgj~+#S#e9@UVr2z=^f%_qD_Dz!`%GD^3mpkprG+&Y6 zF7@gVc)ts~ThUK5cxVGG&h!hDHUSvtZS0}n47uV975?RzW4qxuwY6eA=cI8L{lZ66 z@SMVj+AjjMPOU~j4VnSYcqZnWsk^BESXWzE4avqy_BI(P#)NLws^5t~I9p9FQqVdLdg7Jpu@gMHe?{!-Isl~O5>$m?KFyVymrxnEqkPh$_s zm=#MTUF;oAyHR8Rf>UEf6FV;YP0+ddEZ(fqKR0C2ipD>6(c4ijGHiN_Mn5dA_E>xZ z5q(u68XJe8{G2`VIM^WcET#h6=R%1fP=ywY8l`=}IwXUjv086_)?Paa6KX4b<4R{vvBZJr)5P{QczTf^0<0m 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) + StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */ + #endif + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ + UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ + #endif + + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ + UBaseType_t uxMutexesHeld; + #endif + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + TaskHookFunction_t pxTaskTag; + #endif + + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + + #if( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + /* Allocate a Newlib reent structure that is specific to this task. + Note Newlib support has been included by popular demand, but is not + used by the FreeRTOS maintainers themselves. FreeRTOS is not + responsible for resulting newlib operation. User must be familiar with + newlib and must provide system-wide implementations of the necessary + stubs. Be warned that (at the time of writing) the current newlib design + implements a system-wide malloc() that must be provided with locks. + + See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html + for additional information. */ + struct _reent xNewLib_reent; + #endif + + #if( configUSE_TASK_NOTIFICATIONS == 1 ) + volatile uint32_t ulNotifiedValue; + volatile uint8_t ucNotifyState; + #endif + + /* See the comments in FreeRTOS.h with the definition of + tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + uint8_t ucDelayAborted; + #endif + + #if( configUSE_POSIX_ERRNO == 1 ) + int iTaskErrno; + #endif + +} tskTCB; + +/* The old tskTCB name is maintained above then typedefed to the new TCB_t name +below to enable the use of older kernel aware debuggers. */ +typedef tskTCB TCB_t; + +/*lint -save -e956 A manual analysis and inspection has been used to determine +which static variables must be declared volatile. */ +PRIVILEGED_DATA +extern TCB_t * volatile pxCurrentTCB; + +/* +#define traceTASK_SWITCHED_OUT_DISABLE +#define traceTASK_SWITCHED_IN_DISABLE + +#if defined(MPU_WRAPPERS_INCLUDED_FROM_API_FILE) + + +extern void __freertos_evr_on_task_switched_out (void *ptTCB); +extern void __freertos_evr_on_task_switched_in(void *ptTCB, uint32_t uxTopPriority) ; + +# define traceTASK_SWITCHED_OUT() \ + __freertos_evr_on_task_switched_out(pxCurrentTCB) +# define traceTASK_SWITCHED_IN() \ + __freertos_evr_on_task_switched_in(pxCurrentTCB, uxTopReadyPriority) + +#endif + + */ + + +/*============================ GLOBAL VARIABLES ==============================*/ +/*============================ LOCAL VARIABLES ===============================*/ +/*============================ PROTOTYPES ====================================*/ +extern void __on_context_switch_in(uint32_t *pwStack); +extern void __on_context_switch_out(uint32_t *pwStack); + +/*============================ IMPLEMENTATION ================================*/ + + +#if defined(RTE_Compiler_EventRecorder) + +# include "EventRecorder.h" + +#endif + + +#define EvtFreeRTOSTasksNo (0xF0U) + +#define EvtFreeRTOSTasks_TaskSwitchedOut \ + EventID(EventLevelOp, EvtFreeRTOSTasksNo, 0x0BU) +#define EvtFreeRTOSTasks_TaskSwitchedIn \ + EventID(EventLevelOp, EvtFreeRTOSTasksNo, 0x0CU) + +void __freertos_evr_on_task_switched_out (void *ptTCB) { +#if defined(RTE_Compiler_EventRecorder) + EventRecord2(EvtFreeRTOSTasks_TaskSwitchedOut, (uint32_t)ptTCB, 0U); +#else + (void)pxCurrentTCB; +#endif + + __on_context_switch_out(((TCB_t *)ptTCB)->pxStack); + +} + + +void __freertos_evr_on_task_switched_in(void *ptTCB, uint32_t uxTopPriority) { +#if defined(RTE_Compiler_EventRecorder) + EventRecord2(EvtFreeRTOSTasks_TaskSwitchedIn, (uint32_t)ptTCB, uxTopPriority); +#else + (void)pxCurrentTCB; + (void)uxTopPriority; +#endif + + __on_context_switch_in(((TCB_t *)ptTCB)->pxStack); +} + + +task_cycle_info_t * get_rtos_task_cycle_info(void) +{ + return &(((struct __task_cycle_info_t *)pxCurrentTCB->pxStack)->tInfo); +} diff --git a/lib/perf_os_patch_rtx5.c b/lib/perf_os_patch_rtx5.c index 2f96f2e..d0b817b 100644 --- a/lib/perf_os_patch_rtx5.c +++ b/lib/perf_os_patch_rtx5.c @@ -52,43 +52,20 @@ struct __task_cycle_info_t { /*============================ GLOBAL VARIABLES ==============================*/ /*============================ LOCAL VARIABLES ===============================*/ /*============================ PROTOTYPES ====================================*/ +extern void __on_context_switch_in(uint32_t *pwStack); +extern void __on_context_switch_out(uint32_t *pwStack); + /*============================ IMPLEMENTATION ================================*/ /*! \brief wrapper function for rtos context switching */ void __on_context_switch (osRtxThread_t *thread) { + if (NULL != osRtxInfo.thread.run.curr) { + __on_context_switch_out(osRtxInfo.thread.run.curr->stack_mem); + } - //assert(NULL != ptThread); - - do { - struct __task_cycle_info_t *ptFrame = NULL; - uint64_t dwTimeStamp; - osRtxThread_t *curr = osRtxInfo.thread.run.curr; - if (curr == thread) { - break; - } - - //! get current system ticks - dwTimeStamp = get_system_ticks(); - - if (NULL != curr) { - ptFrame = (struct __task_cycle_info_t *)curr->stack_mem; - - ptFrame->tInfo.dwUsedRecent = dwTimeStamp - ptFrame->dwLastTimeStamp; - ptFrame->tInfo.dwUsedTotal += ptFrame->tInfo.dwUsedRecent; - } - - //! inital target thread - - ptFrame = (struct __task_cycle_info_t *)thread->stack_mem; - - if (0 == ptFrame->tInfo.dwStart) { - ptFrame->tInfo.dwStart = dwTimeStamp; - } - ptFrame->dwLastTimeStamp = dwTimeStamp; - ptFrame->tInfo.wActiveCount++; - } while(0); + __on_context_switch_in(thread->stack_mem); } __attribute__((used)) @@ -117,22 +94,3 @@ task_cycle_info_t * get_rtos_task_cycle_info(void) return &(((struct __task_cycle_info_t *)curr->stack_mem)->tInfo); } -void start_task_cycle_counter(void) -{ - task_cycle_info_t * ptInfo = get_rtos_task_cycle_info(); - if (NULL != ptInfo) { - ptInfo->dwUsedTotal = 0; - } -} - -int32_t stop_task_cycle_counter(void) -{ - task_cycle_info_t * ptInfo = get_rtos_task_cycle_info(); - if (NULL != ptInfo) { - return (int32_t)ptInfo->dwUsedTotal; - } - - return 0; -} - - diff --git a/perf_counter.c b/perf_counter.c index bc4529d..b14bb02 100644 --- a/perf_counter.c +++ b/perf_counter.c @@ -20,6 +20,8 @@ #include #include #include "cmsis_compiler.h" + +#define __IMPLEMENT_PERF_COUNTER #include "perf_counter.h" #if defined(__IS_COMPILER_GCC__) @@ -153,6 +155,11 @@ typedef struct __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ } SCB_Type; +struct __task_cycle_info_t { + uint64_t dwLastTimeStamp; + task_cycle_info_t tInfo; +} ; + /*============================ GLOBAL VARIABLES ==============================*/ extern uint32_t SystemCoreClock; @@ -379,3 +386,54 @@ int64_t get_system_ticks(void) return lTemp; } + + +__WEAK +task_cycle_info_t * get_rtos_task_cycle_info(void) +{ + return NULL; +} + +void __on_context_switch_in(uint32_t *pwStack) +{ + + struct __task_cycle_info_t *ptFrame = (struct __task_cycle_info_t *)pwStack; + uint64_t dwTimeStamp = get_system_ticks(); + + if (0 == ptFrame->tInfo.dwStart) { + ptFrame->tInfo.dwStart = dwTimeStamp; + } + ptFrame->dwLastTimeStamp = dwTimeStamp; + ptFrame->tInfo.wActiveCount++; + +} + +void __on_context_switch_out(uint32_t *pwStack) +{ + + uint64_t dwTimeStamp = get_system_ticks(); + struct __task_cycle_info_t *ptFrame = (struct __task_cycle_info_t *)pwStack; + + ptFrame->tInfo.dwUsedRecent = dwTimeStamp - ptFrame->dwLastTimeStamp; + ptFrame->tInfo.dwUsedTotal += ptFrame->tInfo.dwUsedRecent; + +} + +void start_task_cycle_counter(void) +{ + task_cycle_info_t * ptInfo = get_rtos_task_cycle_info(); + if (NULL != ptInfo) { + ptInfo->dwUsedTotal = 0; + } +} + +int32_t stop_task_cycle_counter(void) +{ + task_cycle_info_t * ptInfo = get_rtos_task_cycle_info(); + if (NULL != ptInfo) { + return (int32_t)ptInfo->dwUsedTotal; + } + + return 0; +} + diff --git a/perf_counter.h b/perf_counter.h index 2a7980e..0a53a3c 100644 --- a/perf_counter.h +++ b/perf_counter.h @@ -341,7 +341,7 @@ extern void start_task_cycle_counter(void); */ extern int32_t stop_task_cycle_counter(void); -#else +#elif !defined(__IMPLEMENT_PERF_COUNTER) # define start_task_cycle_counter start_cycle_counter # define stop_task_cycle_counter stop_cycle_counter diff --git a/perf_os_patch_freertos.c b/perf_os_patch_freertos.c new file mode 100644 index 0000000..f377f57 --- /dev/null +++ b/perf_os_patch_freertos.c @@ -0,0 +1,231 @@ +/**************************************************************************** +* Copyright 2021 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) * +* * +* Licensed under the Apache License, Version 2.0 (the "License"); * +* you may not use this file except in compliance with the License. * +* You may obtain a copy of the License at * +* * +* http://www.apache.org/licenses/LICENSE-2.0 * +* * +* Unless required by applicable law or agreed to in writing, software * +* distributed under the License is distributed on an "AS IS" BASIS, * +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * +* See the License for the specific language governing permissions and * +* limitations under the License. * +* * +****************************************************************************/ + + +/*============================ INCLUDES ======================================*/ + + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "stack_macros.h" + +/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified +because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined +for the header files above, but not in this file, in order to generate the +correct privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ + +#include "perf_counter.h" +#include "cmsis_compiler.h" + +/*============================ MACROS ========================================*/ + +#undef __WRAP_FUNC +#undef WRAP_FUNC +#if defined(__IS_COMPILER_ARM_COMPILER__) && __IS_COMPILER_ARM_COMPILER__ + +# define __WRAP_FUNC(__NAME) $Sub$$##__NAME +# define __ORIG_FUNC(__NAME) $Super$$##__NAME + +#elif (defined(__IS_COMPILER_LLVM__) && __IS_COMPILER_LLVM__) \ + || (defined(__IS_COMPILER_GCC__) && __IS_COMPILER_GCC__) + +# define __WRAP_FUNC(__NAME) __wrap_##__NAME +# define __ORIG_FUNC(__NAME) __real_##__NAME + +#endif +#define WRAP_FUNC(__NAME) __WRAP_FUNC(__NAME) +#define ORIG_FUNC(__NAME) __ORIG_FUNC(__NAME) + +struct __task_cycle_info_t { + uint64_t dwLastTimeStamp; + task_cycle_info_t tInfo; +} ; + +/*============================ TYPES =========================================*/ + +/* + * Task control block. A task control block (TCB) is allocated for each task, + * and stores task state information, including a pointer to the task's context + * (the task's run time environment, including register values) + */ +typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */ +{ + volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ + #endif + + ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ + ListItem_t xEventListItem; /*< Used to reference a task from an event list. */ + UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */ + StackType_t *pxStack; /*< Points to the start of the stack. */ + char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + + #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) + StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */ + #endif + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ + UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ + #endif + + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ + UBaseType_t uxMutexesHeld; + #endif + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + TaskHookFunction_t pxTaskTag; + #endif + + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + + #if( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + /* Allocate a Newlib reent structure that is specific to this task. + Note Newlib support has been included by popular demand, but is not + used by the FreeRTOS maintainers themselves. FreeRTOS is not + responsible for resulting newlib operation. User must be familiar with + newlib and must provide system-wide implementations of the necessary + stubs. Be warned that (at the time of writing) the current newlib design + implements a system-wide malloc() that must be provided with locks. + + See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html + for additional information. */ + struct _reent xNewLib_reent; + #endif + + #if( configUSE_TASK_NOTIFICATIONS == 1 ) + volatile uint32_t ulNotifiedValue; + volatile uint8_t ucNotifyState; + #endif + + /* See the comments in FreeRTOS.h with the definition of + tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + uint8_t ucDelayAborted; + #endif + + #if( configUSE_POSIX_ERRNO == 1 ) + int iTaskErrno; + #endif + +} tskTCB; + +/* The old tskTCB name is maintained above then typedefed to the new TCB_t name +below to enable the use of older kernel aware debuggers. */ +typedef tskTCB TCB_t; + +/*lint -save -e956 A manual analysis and inspection has been used to determine +which static variables must be declared volatile. */ +PRIVILEGED_DATA +extern TCB_t * volatile pxCurrentTCB; + +/* +#define traceTASK_SWITCHED_OUT_DISABLE +#define traceTASK_SWITCHED_IN_DISABLE + +#if defined(MPU_WRAPPERS_INCLUDED_FROM_API_FILE) + + +extern void __freertos_evr_on_task_switched_out (void *ptTCB); +extern void __freertos_evr_on_task_switched_in(void *ptTCB, uint32_t uxTopPriority) ; + +# define traceTASK_SWITCHED_OUT() \ + __freertos_evr_on_task_switched_out(pxCurrentTCB) +# define traceTASK_SWITCHED_IN() \ + __freertos_evr_on_task_switched_in(pxCurrentTCB, uxTopReadyPriority) + +#endif + + */ + + +/*============================ GLOBAL VARIABLES ==============================*/ +/*============================ LOCAL VARIABLES ===============================*/ +/*============================ PROTOTYPES ====================================*/ +extern void __on_context_switch_in(uint32_t *pwStack); +extern void __on_context_switch_out(uint32_t *pwStack); + +/*============================ IMPLEMENTATION ================================*/ + + +#if defined(RTE_Compiler_EventRecorder) + +# include "EventRecorder.h" + +#endif + + +#define EvtFreeRTOSTasksNo (0xF0U) + +#define EvtFreeRTOSTasks_TaskSwitchedOut \ + EventID(EventLevelOp, EvtFreeRTOSTasksNo, 0x0BU) +#define EvtFreeRTOSTasks_TaskSwitchedIn \ + EventID(EventLevelOp, EvtFreeRTOSTasksNo, 0x0CU) + +void __freertos_evr_on_task_switched_out (void *ptTCB) { +#if defined(RTE_Compiler_EventRecorder) + EventRecord2(EvtFreeRTOSTasks_TaskSwitchedOut, (uint32_t)ptTCB, 0U); +#else + (void)pxCurrentTCB; +#endif + + __on_context_switch_out(((TCB_t *)ptTCB)->pxStack); + +} + + +void __freertos_evr_on_task_switched_in(void *ptTCB, uint32_t uxTopPriority) { +#if defined(RTE_Compiler_EventRecorder) + EventRecord2(EvtFreeRTOSTasks_TaskSwitchedIn, (uint32_t)ptTCB, uxTopPriority); +#else + (void)pxCurrentTCB; + (void)uxTopPriority; +#endif + + __on_context_switch_in(((TCB_t *)ptTCB)->pxStack); +} + + +task_cycle_info_t * get_rtos_task_cycle_info(void) +{ + return &(((struct __task_cycle_info_t *)pxCurrentTCB->pxStack)->tInfo); +} diff --git a/perf_os_patch_rtx5.c b/perf_os_patch_rtx5.c index 2f96f2e..d0b817b 100644 --- a/perf_os_patch_rtx5.c +++ b/perf_os_patch_rtx5.c @@ -52,43 +52,20 @@ struct __task_cycle_info_t { /*============================ GLOBAL VARIABLES ==============================*/ /*============================ LOCAL VARIABLES ===============================*/ /*============================ PROTOTYPES ====================================*/ +extern void __on_context_switch_in(uint32_t *pwStack); +extern void __on_context_switch_out(uint32_t *pwStack); + /*============================ IMPLEMENTATION ================================*/ /*! \brief wrapper function for rtos context switching */ void __on_context_switch (osRtxThread_t *thread) { + if (NULL != osRtxInfo.thread.run.curr) { + __on_context_switch_out(osRtxInfo.thread.run.curr->stack_mem); + } - //assert(NULL != ptThread); - - do { - struct __task_cycle_info_t *ptFrame = NULL; - uint64_t dwTimeStamp; - osRtxThread_t *curr = osRtxInfo.thread.run.curr; - if (curr == thread) { - break; - } - - //! get current system ticks - dwTimeStamp = get_system_ticks(); - - if (NULL != curr) { - ptFrame = (struct __task_cycle_info_t *)curr->stack_mem; - - ptFrame->tInfo.dwUsedRecent = dwTimeStamp - ptFrame->dwLastTimeStamp; - ptFrame->tInfo.dwUsedTotal += ptFrame->tInfo.dwUsedRecent; - } - - //! inital target thread - - ptFrame = (struct __task_cycle_info_t *)thread->stack_mem; - - if (0 == ptFrame->tInfo.dwStart) { - ptFrame->tInfo.dwStart = dwTimeStamp; - } - ptFrame->dwLastTimeStamp = dwTimeStamp; - ptFrame->tInfo.wActiveCount++; - } while(0); + __on_context_switch_in(thread->stack_mem); } __attribute__((used)) @@ -117,22 +94,3 @@ task_cycle_info_t * get_rtos_task_cycle_info(void) return &(((struct __task_cycle_info_t *)curr->stack_mem)->tInfo); } -void start_task_cycle_counter(void) -{ - task_cycle_info_t * ptInfo = get_rtos_task_cycle_info(); - if (NULL != ptInfo) { - ptInfo->dwUsedTotal = 0; - } -} - -int32_t stop_task_cycle_counter(void) -{ - task_cycle_info_t * ptInfo = get_rtos_task_cycle_info(); - if (NULL != ptInfo) { - return (int32_t)ptInfo->dwUsedTotal; - } - - return 0; -} - -