22#include "cmsis_compiler.h"
24#define __IMPLEMENT_PERF_COUNTER
25#include "perf_counter.h"
27#if defined(__IS_COMPILER_GCC__)
28# pragma GCC diagnostic ignored "-Wattributes"
33#ifndef PERF_CNT_COMPENSATION_THRESHOLD
34# define PERF_CNT_COMPENSATION_THRESHOLD 16
37#ifndef PERF_CNT_DELAY_US_COMPENSATION
38# define PERF_CNT_DELAY_US_COMPENSATION 90
46 #define __I volatile const
52#define __IM volatile const
57#define SCS_BASE (0xE000E000UL)
58#define SysTick_BASE (SCS_BASE + 0x0010UL)
59#define SCB_BASE (SCS_BASE + 0x0D00UL)
61#define SysTick ((SysTick_Type *) SysTick_BASE )
62#define SCB ((SCB_Type *) SCB_BASE )
65#define SysTick_CTRL_COUNTFLAG_Pos 16U
66#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos)
68#define SysTick_CTRL_CLKSOURCE_Pos 2U
69#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos)
71#define SysTick_CTRL_TICKINT_Pos 1U
72#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos)
74#define SysTick_CTRL_ENABLE_Pos 0U
75#define SysTick_CTRL_ENABLE_Msk (1UL )
78#define SysTick_LOAD_RELOAD_Pos 0U
79#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL )
82#define SysTick_VAL_CURRENT_Pos 0U
83#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL )
86#define SysTick_CALIB_NOREF_Pos 31U
87#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos)
89#define SysTick_CALIB_SKEW_Pos 30U
90#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos)
92#define SysTick_CALIB_TENMS_Pos 0U
93#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL )
97#define SCB_ICSR_PENDSTCLR_Pos 25U
98#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos)
100#define SCB_ICSR_PENDSTSET_Pos 26U
101#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos)
104#define MAGIC_WORD_AGENT_LIST_VALID 0x8492A53C
105#define MAGIC_WORD_CANARY 0xDEADBEEF
129 __IOM uint32_t AIRCR;
132 __IOM uint8_t SHP[12U];
133 __IOM uint32_t SHCSR;
137 __IOM uint32_t MMFAR;
140 __IM uint32_t PFR[2U];
143 __IM uint32_t MMFR[4U];
144 __IM uint32_t ISAR[5U];
145 uint32_t RESERVED0[5U];
146 __IOM uint32_t CPACR;
149struct __task_cycle_info_t {
151 int64_t lLastTimeStamp;
158extern uint32_t SystemCoreClock;
161volatile int64_t g_lLastTimeStamp = 0;
162volatile int32_t g_nOffset = 0;
163volatile static int32_t s_nUSUnit = 1;
164volatile static int32_t s_nMSUnit = 1;
165volatile static int32_t s_nMSResidule = 0;
166volatile static int32_t s_nSystemMS = 0;
168volatile static int64_t s_lSystemClockCounts = 0;
175__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
177 if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
185 SysTick->LOAD = (uint32_t)(ticks - 1UL);
188 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
189 SysTick_CTRL_TICKINT_Msk |
190 SysTick_CTRL_ENABLE_Msk;
198 uint32_t wLoad = SysTick->LOAD + 1;
199 s_lSystemClockCounts += wLoad;
202 s_nMSResidule += wLoad;
203 int32_t nMS = s_nMSResidule / s_nMSUnit;
204 s_nMSResidule -= nMS * s_nMSUnit;
209void __perf_os_patch_init(
void)
216 s_nUSUnit = SystemCoreClock / 1000000ul;
217 s_nMSUnit = SystemCoreClock / 1000ul;
229 if (!bIsSysTickOccupied) {
230 SysTick_Config(0x01000000);
232 SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
236 s_lSystemClockCounts = 0;
239#if defined(__PERF_COUNTER_CFG_USE_SYSTICK_WRAPPER__)
240#if defined(__IS_COMPILER_ARM_COMPILER_5__) \
241 || defined(__IS_COMPILER_ARM_COMPILER_6__) \
242 || defined(__IS_COMPILER_GCC__) \
243 || defined(__IS_COMPILER_LLVM__)
244 extern void __ensure_systick_wrapper(
void);
245 __ensure_systick_wrapper();
249 __perf_os_patch_init();
256__STATIC_INLINE int32_t check_systick(
void)
258 int32_t nTemp = (int32_t)SysTick->LOAD - (int32_t)SysTick->VAL;
280 if (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk){
281 if (((int32_t)SysTick->LOAD - nTemp) >= PERF_CNT_COMPENSATION_THRESHOLD) {
282 nTemp += SysTick->LOAD + 1;
289#if defined(__IS_COMPILER_IAR__)
290__attribute__((constructor))
292__attribute__((constructor(255)))
294void __perf_counter_init(
void)
302 int64_t lUs = (int64_t)nUs * (int64_t)s_nUSUnit;
303 int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
305 : PERF_CNT_DELAY_US_COMPENSATION;
307 if (lUs <= iCompensate) {
320 int64_t lUs = (int64_t)nMs * (int64_t)s_nMSUnit;
321 int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
323 : PERF_CNT_DELAY_US_COMPENSATION;
325 if (lUs <= iCompensate) {
356#if !defined(__IS_COMPILER_IAR__)
357__attribute__((nothrow))
359__attribute__((noinline))
365 lTemp = check_systick() + s_lSystemClockCounts;
372__attribute__((noinline))
378 lTemp = check_systick() + s_lSystemClockCounts;
389 nTemp = s_nSystemMS + (check_systick() + s_nMSResidule) / s_nMSUnit;
404 struct __task_cycle_info_t * ptRootAgent =
406 if (NULL == ptRootAgent) {
410 memset(ptRootAgent, 0,
sizeof(
struct __task_cycle_info_t));
412 ptRootAgent->tList.ptInfo = &(ptRootAgent->tInfo);
414 ptRootAgent->wMagicWord = MAGIC_WORD_CANARY;
420 if (NULL == ptInfo) {
426 ptInfo->bEnabled =
true;
434 if (NULL == ptInfo) {
439 bOrig = ptInfo->bEnabled;
440 ptInfo->bEnabled =
true;
447 if (NULL == ptInfo) {
452 bOrig = ptInfo->bEnabled;
453 ptInfo->bEnabled =
false;
460 if (NULL == ptInfo) {
464 ptInfo->bEnabled = bEnabledStatus;
473 if (NULL == ptAgent || NULL == ptInfo) {
477 struct __task_cycle_info_t * ptRootAgent =
479 if (NULL == ptRootAgent) {
483 ptRootAgent->wMagicWord = MAGIC_WORD_AGENT_LIST_VALID;
485 ptAgent->ptInfo = ptInfo;
490 ptAgent->ptNext = ptRootAgent->tList.ptNext;
491 ptRootAgent->tList.ptNext = ptAgent;
494 ptAgent->ptPrev = &(ptRootAgent->tList);
495 if (NULL != ptAgent->ptNext) {
496 ptAgent->ptNext->ptPrev = ptAgent;
511 if (NULL == ptAgent) {
516 if (NULL == ptPrev) {
519 if (ptPrev->ptNext != ptAgent) {
525 ptPrev->ptNext = ptAgent->ptNext;
527 if (NULL != ptAgent->ptNext) {
529 ptAgent->ptNext->ptPrev = ptPrev;
532 ptAgent->ptNext = NULL;
533 ptAgent->ptPrev = NULL;
542void __on_context_switch_in(uint32_t *pwStack)
544 struct __task_cycle_info_t *ptRootAgent = (
struct __task_cycle_info_t *)pwStack;
547 ptRootAgent->lLastTimeStamp = dwTimeStamp;
548 ptRootAgent->tInfo.hwActiveCount++;
550 if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
553 while(NULL != ptAgent) {
554 if (NULL != ptAgent->ptInfo) {
555 if (ptAgent->ptInfo->bEnabled) {
556 ptAgent->ptInfo->hwActiveCount++;
559 ptAgent = ptAgent->ptNext;
564void __on_context_switch_out(uint32_t *pwStack)
566 struct __task_cycle_info_t *ptRootAgent = (
struct __task_cycle_info_t *)pwStack;
567 int64_t lCycleUsed =
get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
569 ptRootAgent->tInfo.nUsedRecent = lCycleUsed;
570 ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
572 if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
575 while(NULL != ptAgent) {
576 if (NULL != ptAgent->ptInfo) {
577 if (ptAgent->ptInfo->bEnabled) {
578 ptAgent->ptInfo->nUsedRecent = lCycleUsed;
579 ptAgent->ptInfo->lUsedTotal += lCycleUsed;
582 ptAgent = ptAgent->ptNext;
587__attribute__((noinline))
590 struct __task_cycle_info_t * ptRootAgent =
592 if (NULL == ptRootAgent) {
598 ptRootAgent->tInfo.lUsedTotal = 0;
600 if (NULL != ptInfo) {
601 ptInfo->lUsedTotal = 0;
602 ptInfo->bEnabled =
true;
607__attribute__((noinline))
610 struct __task_cycle_info_t * ptRootAgent =
612 if (NULL == ptRootAgent) {
619 int64_t lCycleUsed =
get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
620 ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
622 if (NULL != ptInfo) {
623 if (ptInfo->bEnabled) {
624 ptInfo->nUsedRecent = lCycleUsed;
625 ptInfo->lUsedTotal += lCycleUsed;
626 ptInfo->bEnabled =
false;
629 lCycles = ptInfo->lUsedTotal;
631 lCycles = ptRootAgent->tInfo.lUsedTotal;
void user_code_insert_to_systick_handler(void)
a system timer handler inserted to the SysTick_Handler
void update_perf_counter(void)
update perf_counter as SystemCoreClock has been updated.
void delay_ms(int32_t nMs)
delay specified time in millisecond
int64_t get_system_ticks(void)
get the elapsed cycles since perf_counter is initialised
void init_cycle_counter(bool bIsSysTickOccupied)
initialise cycle counter service
void delay_us(int32_t nUs)
delay specified time in microsecond
int32_t get_system_ms(void)
get the elapsed milliseconds since perf_counter is initialised
bool disable_task_cycle_info(task_cycle_info_t *ptInfo)
disable a given task_cycle_info_t object
task_cycle_info_agent_t * register_task_cycle_agent(task_cycle_info_t *ptInfo, task_cycle_info_agent_t *ptAgent)
register a global virtual cycle counter agent to the current task
void init_task_cycle_counter(void)
initialize the default virtual cycle counter for the current task
void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus)
resume the enabled status of a given task_cycle_info_t object
__WEAK task_cycle_info_t * get_rtos_task_cycle_info(void)
provide cycle information for target task
bool enable_task_cycle_info(task_cycle_info_t *ptInfo)
enable a given task_cycle_info_t object
task_cycle_info_agent_t * unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent)
remove a global virtual cycle counter agent from the current task
task_cycle_info_t * init_task_cycle_info(task_cycle_info_t *ptInfo)
intialize a given task_cycle_info_t object and enable it before registering it.