632 lines
18 KiB
C++
632 lines
18 KiB
C++
|
#include <stdint.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#define __IMPLEMENT_PERF_COUNTER
|
||
|
|
||
|
#include "ticks.h"
|
||
|
|
||
|
#if defined(__IS_COMPILER_GCC__)
|
||
|
# pragma GCC diagnostic ignored "-Wattributes"
|
||
|
#endif
|
||
|
|
||
|
#if defined(__clang__)
|
||
|
# pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||
|
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||
|
# pragma clang diagnostic ignored "-Wconditional-uninitialized"
|
||
|
# pragma clang diagnostic ignored "-Wcast-align"
|
||
|
# pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/*============================ MACROS ========================================*/
|
||
|
#ifndef PERF_CNT_COMPENSATION_THRESHOLD
|
||
|
# define PERF_CNT_COMPENSATION_THRESHOLD 16
|
||
|
#endif
|
||
|
|
||
|
#ifndef PERF_CNT_DELAY_US_COMPENSATION
|
||
|
# define PERF_CNT_DELAY_US_COMPENSATION 90
|
||
|
#endif
|
||
|
|
||
|
#define MAGIC_WORD_AGENT_LIST_VALID 0x8492A53C
|
||
|
#define MAGIC_WORD_CANARY 0xDEADBEEF
|
||
|
|
||
|
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||
|
/*============================ TYPES =========================================*/
|
||
|
|
||
|
struct __task_cycle_info_t {
|
||
|
task_cycle_info_t tInfo; //!< cycle information
|
||
|
int64_t lLastTimeStamp; //!< previous timestamp
|
||
|
task_cycle_info_agent_t tList; //!< the root of the agent list
|
||
|
uint32_t wMagicWord; //!< an magic word for validation
|
||
|
};
|
||
|
|
||
|
|
||
|
/*============================ GLOBAL VARIABLES ==============================*/
|
||
|
/*============================ LOCAL VARIABLES ===============================*/
|
||
|
volatile int64_t g_lLastTimeStamp = 0;
|
||
|
volatile static int64_t s_lOldTimestamp;
|
||
|
volatile int32_t g_nOffset = 0;
|
||
|
volatile static uint32_t s_wUSUnit = 1;
|
||
|
volatile static uint32_t s_wMSUnit = 1;
|
||
|
volatile static uint32_t s_wMSResidule = 0;
|
||
|
volatile static uint32_t s_wUSResidule = 0;
|
||
|
volatile static int64_t s_lSystemMS = 0;
|
||
|
volatile static int64_t s_lSystemUS = 0;
|
||
|
|
||
|
volatile static int64_t s_lSystemClockCounts = 0;
|
||
|
|
||
|
/*============================ PROTOTYPES ====================================*/
|
||
|
|
||
|
/* low level interface for porting */
|
||
|
extern
|
||
|
uint32_t ticks_port_get_system_timer_freq(void);
|
||
|
|
||
|
extern
|
||
|
int64_t ticks_port_get_system_timer_top(void);
|
||
|
|
||
|
extern
|
||
|
bool ticks_port_is_system_timer_ovf_pending(void);
|
||
|
|
||
|
extern
|
||
|
bool ticks_port_init_system_timer(bool bTimerOccupied);
|
||
|
|
||
|
extern
|
||
|
int64_t ticks_port_get_system_timer_elapsed(void);
|
||
|
|
||
|
extern
|
||
|
void ticks_port_clear_system_timer_ovf_pending(void);
|
||
|
|
||
|
extern
|
||
|
void ticks_port_stop_system_timer_counting(void);
|
||
|
|
||
|
extern
|
||
|
void ticks_port_clear_system_timer_counter(void);
|
||
|
|
||
|
/*============================ INCLUDES ======================================*/
|
||
|
|
||
|
void ticks_port_insert_to_system_timer_insert_ovf_handler(void) {
|
||
|
int64_t lLoad = ticks_port_get_system_timer_top() + 1;
|
||
|
s_lSystemClockCounts += lLoad;
|
||
|
|
||
|
// update system ms counter
|
||
|
do {
|
||
|
int64_t lTemp = s_wMSResidule + lLoad;
|
||
|
|
||
|
int64_t lMS = lTemp / s_wMSUnit;
|
||
|
s_lSystemMS += lMS;
|
||
|
s_wMSResidule = (uint32_t) ((int64_t) lTemp - (int64_t) lMS * s_wMSUnit);
|
||
|
|
||
|
} while (0);
|
||
|
|
||
|
// update system us counter
|
||
|
do {
|
||
|
int64_t lTemp = s_wUSResidule + lLoad;
|
||
|
|
||
|
int64_t lUS = lTemp / s_wUSUnit;
|
||
|
s_lSystemUS += lUS;
|
||
|
|
||
|
s_wUSResidule = (uint32_t) ((int64_t) lTemp - (int64_t) lUS * s_wUSUnit);
|
||
|
|
||
|
} while (0);
|
||
|
|
||
|
}
|
||
|
|
||
|
uint32_t ticks_get_systimer_frequency(void) {
|
||
|
return ticks_port_get_system_timer_freq();
|
||
|
}
|
||
|
|
||
|
__WEAK
|
||
|
void __perf_os_patch_init(void) {
|
||
|
}
|
||
|
|
||
|
|
||
|
void update_perf_counter(void) {
|
||
|
uint32_t wSystemFrequency = ticks_port_get_system_timer_freq();
|
||
|
s_wUSUnit = wSystemFrequency / 1000000ul;
|
||
|
s_wMSUnit = wSystemFrequency / 1000ul;
|
||
|
|
||
|
__IRQ_SAFE {
|
||
|
g_lLastTimeStamp = get_system_ticks();
|
||
|
__ticks_sync_barrier__();
|
||
|
g_nOffset = get_system_ticks() - g_lLastTimeStamp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool init_cycle_counter(bool bIsSysTickOccupied) {
|
||
|
bool bResult = false;
|
||
|
__IRQ_SAFE {
|
||
|
bResult = ticks_port_init_system_timer(bIsSysTickOccupied); // use the longest period
|
||
|
ticks_port_clear_system_timer_ovf_pending();
|
||
|
}
|
||
|
|
||
|
update_perf_counter();
|
||
|
s_lSystemClockCounts = 0; // reset system cycle counter
|
||
|
s_lSystemMS = 0; // reset system millisecond counter
|
||
|
s_lSystemUS = 0; // reset system microsecond counter
|
||
|
s_lOldTimestamp = 0;
|
||
|
|
||
|
__perf_os_patch_init();
|
||
|
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
/*! \note this function should only be called when irq is disabled
|
||
|
* hence SysTick-LOAD and (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)
|
||
|
* won't change.
|
||
|
*/
|
||
|
__STATIC_INLINE int64_t check_systick(void) {
|
||
|
int64_t lLoad = ticks_port_get_system_timer_top() + 1;
|
||
|
int64_t lTemp = ticks_port_get_system_timer_elapsed();
|
||
|
|
||
|
/* Since we cannot stop counting temporarily, there are several
|
||
|
* conditions which we should take into consideration:
|
||
|
* - Condition 1: when assigning nTemp with the register value (LOAD-VAL),
|
||
|
* the underflow didn't happen but when we check the PENDSTSET bit,
|
||
|
* the underflow happens, for this condition, we should not
|
||
|
* do any compensation. When this happens, the (LOAD-nTemp) is
|
||
|
* smaller than PERF_CNT_COMPENSATION_THRESHOLD (a small value) as
|
||
|
* long as LOAD is bigger than (or equals to) the
|
||
|
* PERF_CNT_COMPENSATION_THRESHOLD;
|
||
|
* - Condition 2: when assigning nTemp with the register value (LOAD-VAL),
|
||
|
* the VAL is zero and underflow happened and the PENDSTSET bit
|
||
|
* is set, for this condition, we should not do any compensation.
|
||
|
* When this happens, the (LOAD-nTemp) is equals to zero.
|
||
|
* - Condition 3: when assigning nTemp with the register value (LOAD-VAL),
|
||
|
* the underflow has already happened, hence the PENDSTSET
|
||
|
* is set, for this condition, we should compensate the return
|
||
|
* value. When this happens, the (LOAD-nTemp) is bigger than (or
|
||
|
* equals to) PERF_CNT_COMPENSATION_THRESHOLD.
|
||
|
* The following code implements an equivalent logic.
|
||
|
*/
|
||
|
if (ticks_port_is_system_timer_ovf_pending()) {
|
||
|
if ((lLoad - lTemp) >= PERF_CNT_COMPENSATION_THRESHOLD) {
|
||
|
lTemp += lLoad;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return lTemp;
|
||
|
}
|
||
|
|
||
|
void before_cycle_counter_reconfiguration(void) {
|
||
|
__IRQ_SAFE {
|
||
|
ticks_port_stop_system_timer_counting();
|
||
|
|
||
|
if (ticks_port_is_system_timer_ovf_pending()) {
|
||
|
ticks_port_clear_system_timer_ovf_pending(); /* clear pending bit */
|
||
|
|
||
|
ticks_port_insert_to_system_timer_insert_ovf_handler(); /* manually handle exception */
|
||
|
|
||
|
}
|
||
|
s_lSystemClockCounts = get_system_ticks(); /* get the final cycle counter value */
|
||
|
|
||
|
ticks_port_clear_system_timer_counter();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
__attribute__((constructor))
|
||
|
void __perf_counter_init(void) {
|
||
|
init_cycle_counter(true);
|
||
|
}
|
||
|
|
||
|
|
||
|
void delay_us(uint32_t wUs) {
|
||
|
int64_t lUs = (int64_t) wUs * (int64_t) s_wUSUnit;
|
||
|
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
|
||
|
? g_nOffset
|
||
|
: PERF_CNT_DELAY_US_COMPENSATION;
|
||
|
|
||
|
if (lUs <= iCompensate) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
lUs -= iCompensate;
|
||
|
|
||
|
lUs += get_system_ticks();
|
||
|
while (get_system_ticks() < lUs);
|
||
|
}
|
||
|
|
||
|
void delay_ms(uint32_t wMs) {
|
||
|
int64_t lMs = (int64_t) wMs * (int64_t) s_wMSUnit;
|
||
|
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
|
||
|
? g_nOffset
|
||
|
: PERF_CNT_DELAY_US_COMPENSATION;
|
||
|
|
||
|
if (lMs <= iCompensate) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
lMs -= iCompensate;
|
||
|
|
||
|
lMs += get_system_ticks();
|
||
|
while (get_system_ticks() < lMs);
|
||
|
}
|
||
|
|
||
|
__attribute__((noinline))
|
||
|
int64_t get_system_ticks(void) {
|
||
|
int64_t lTemp = 0;
|
||
|
|
||
|
__IRQ_SAFE {
|
||
|
lTemp = check_systick() + s_lSystemClockCounts;
|
||
|
|
||
|
/* When calling get_system_ticks() in an exception handler that has a
|
||
|
* higher priority than the SysTick_Handler, in some rare cases, the
|
||
|
* lTemp might be temporarily smaller than the previous value (i.e.
|
||
|
* s_lOldTimestamp), to mitigate the adverse effects of this problem,
|
||
|
* we use the following code to avoid time-rolling-back issue.
|
||
|
*
|
||
|
* NOTE: the issue mentioned above doesn't accumulate or have long-lasting
|
||
|
* effects.
|
||
|
*/
|
||
|
if (lTemp < s_lOldTimestamp) {
|
||
|
lTemp = s_lOldTimestamp;
|
||
|
} else {
|
||
|
s_lOldTimestamp = lTemp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return lTemp;
|
||
|
}
|
||
|
|
||
|
/*! \note the prototype of this clock() is different from the one defined in
|
||
|
*! time.h. As clock_t is usually defined as unsigned int, it is
|
||
|
*! not big enough in Cortex-M system to hold a time-stamp. clock()
|
||
|
*! defined here returns the timestamp since the begining of main()
|
||
|
*! and its unit is clock cycle (rather than 1ms). Hence, for a system
|
||
|
*! running under several hundreds MHz or even 1GHz, e.g. RT10xx from
|
||
|
*! NXP, it is very easy to see a counter overflow as clock_t is
|
||
|
*! defined as uint32_t in timer.h.
|
||
|
*! Since we are not allowed to change the defintion of clock_t in
|
||
|
*! official header file, i.e. time.h, I use a compatible prototype
|
||
|
*! after I checked the AAPCS spec. So, the return of the clock() is
|
||
|
*! int64_t, which will use the R0 to store the lower 32bits and R1
|
||
|
*! to store the higher 32bits. When you are using the prototype from
|
||
|
*! timer.h, caller will only take the lower 32bits stored in R0 and
|
||
|
*! the higher 32bits stored in R1 will be ignored.
|
||
|
*!
|
||
|
*! If you want to use the non-overflow version of this clock(), please
|
||
|
*! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
|
||
|
*! and 2) do not include system header file <time.h>
|
||
|
*!
|
||
|
*/
|
||
|
#if !defined(__IS_COMPILER_IAR__)
|
||
|
|
||
|
__attribute__((nothrow))
|
||
|
#endif
|
||
|
__attribute__((noinline))
|
||
|
int64_t clock(void) {
|
||
|
return get_system_ticks();
|
||
|
}
|
||
|
|
||
|
int64_t get_system_ms(void) {
|
||
|
int64_t lTemp = 0;
|
||
|
|
||
|
__IRQ_SAFE {
|
||
|
lTemp = s_lSystemMS + ((check_systick() + (int64_t) s_wMSResidule) / s_wMSUnit);
|
||
|
}
|
||
|
|
||
|
return lTemp;
|
||
|
}
|
||
|
|
||
|
int64_t get_system_us(void) {
|
||
|
int64_t lTemp = 0;
|
||
|
|
||
|
__IRQ_SAFE {
|
||
|
lTemp = s_lSystemUS + ((check_systick() + (int64_t) s_wUSResidule) / s_wUSUnit);
|
||
|
}
|
||
|
|
||
|
return lTemp;
|
||
|
}
|
||
|
|
||
|
int64_t ticks_convert_ticks_to_ms(int64_t lTick) {
|
||
|
return lTick / (int64_t) s_wMSUnit;
|
||
|
}
|
||
|
|
||
|
int64_t ticks_convert_ms_to_ticks(uint32_t wMS) {
|
||
|
int64_t lResult = (int64_t) s_wMSUnit * (int64_t) wMS;
|
||
|
return lResult ? lResult : 1;
|
||
|
}
|
||
|
|
||
|
int64_t ticks_convert_ticks_to_us(int64_t lTick) {
|
||
|
return lTick / (int64_t) s_wUSUnit;
|
||
|
}
|
||
|
|
||
|
int64_t ticks_convert_us_to_ticks(uint32_t wMS) {
|
||
|
int64_t lResult = (int64_t) s_wUSUnit * (int64_t) wMS;
|
||
|
return lResult ? lResult : 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool __ticks_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload) {
|
||
|
if (NULL == plTimestamp) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int64_t lTimestamp = get_system_ticks();
|
||
|
|
||
|
|
||
|
if (0 == *plTimestamp) {
|
||
|
*plTimestamp = lPeriod;
|
||
|
*plTimestamp += lTimestamp;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (lTimestamp >= *plTimestamp) {
|
||
|
if (bAutoReload) {
|
||
|
*plTimestamp = lPeriod + lTimestamp;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/// Setup timer hardware.
|
||
|
/// \return status (1=Success, 0=Failure)
|
||
|
uint32_t EventRecorderTimerSetup(void) {
|
||
|
/* doing nothing at all */
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/// Get timer frequency.
|
||
|
/// \return timer frequency in Hz
|
||
|
uint32_t EventRecorderTimerGetFreq(void) {
|
||
|
return ticks_port_get_system_timer_freq();
|
||
|
}
|
||
|
|
||
|
/// Get timer count.
|
||
|
/// \return timer count (32-bit)
|
||
|
uint32_t EventRecorderTimerGetCount(void) {
|
||
|
return get_system_ticks();
|
||
|
}
|
||
|
|
||
|
|
||
|
__WEAK
|
||
|
task_cycle_info_t *get_rtos_task_cycle_info(void) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void init_task_cycle_counter(void) {
|
||
|
struct __task_cycle_info_t *ptRootAgent =
|
||
|
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||
|
if (NULL == ptRootAgent) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
memset(ptRootAgent, 0, sizeof(struct __task_cycle_info_t));
|
||
|
|
||
|
ptRootAgent->tList.ptInfo = &(ptRootAgent->tInfo);
|
||
|
ptRootAgent->tInfo.lStart = get_system_ticks();
|
||
|
ptRootAgent->wMagicWord = MAGIC_WORD_CANARY;
|
||
|
}
|
||
|
|
||
|
bool ticks_check_task_stack_canary_safe(void) {
|
||
|
struct __task_cycle_info_t *ptRootAgent =
|
||
|
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||
|
do {
|
||
|
if (NULL == ptRootAgent) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((MAGIC_WORD_CANARY == ptRootAgent->wMagicWord)
|
||
|
|| (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord)) {
|
||
|
return true;
|
||
|
}
|
||
|
} while (0);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
task_cycle_info_t *init_task_cycle_info(task_cycle_info_t *ptInfo) {
|
||
|
do {
|
||
|
if (NULL == ptInfo) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
memset(ptInfo, 0, sizeof(task_cycle_info_t));
|
||
|
|
||
|
ptInfo->bEnabled = true;
|
||
|
} while (0);
|
||
|
|
||
|
return ptInfo;
|
||
|
}
|
||
|
|
||
|
bool enable_task_cycle_info(task_cycle_info_t *ptInfo) {
|
||
|
if (NULL == ptInfo) {
|
||
|
return false;
|
||
|
}
|
||
|
bool bOrig;
|
||
|
__IRQ_SAFE {
|
||
|
bOrig = ptInfo->bEnabled;
|
||
|
ptInfo->bEnabled = true;
|
||
|
}
|
||
|
return bOrig;
|
||
|
}
|
||
|
|
||
|
bool disable_task_cycle_info(task_cycle_info_t *ptInfo) {
|
||
|
if (NULL == ptInfo) {
|
||
|
return false;
|
||
|
}
|
||
|
bool bOrig;
|
||
|
__IRQ_SAFE {
|
||
|
bOrig = ptInfo->bEnabled;
|
||
|
ptInfo->bEnabled = false;
|
||
|
}
|
||
|
return bOrig;
|
||
|
}
|
||
|
|
||
|
void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus) {
|
||
|
if (NULL == ptInfo) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ptInfo->bEnabled = bEnabledStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
task_cycle_info_agent_t *register_task_cycle_agent(task_cycle_info_t *ptInfo,
|
||
|
task_cycle_info_agent_t *ptAgent) {
|
||
|
__IRQ_SAFE {
|
||
|
do {
|
||
|
if (NULL == ptAgent || NULL == ptInfo) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
struct __task_cycle_info_t *ptRootAgent =
|
||
|
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||
|
if (NULL == ptRootAgent) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ptRootAgent->wMagicWord = MAGIC_WORD_AGENT_LIST_VALID;
|
||
|
|
||
|
ptAgent->ptInfo = ptInfo;
|
||
|
|
||
|
// push to the stack
|
||
|
do {
|
||
|
// set next-list
|
||
|
ptAgent->ptNext = ptRootAgent->tList.ptNext;
|
||
|
ptRootAgent->tList.ptNext = ptAgent;
|
||
|
|
||
|
// set prev-list
|
||
|
ptAgent->ptPrev = &(ptRootAgent->tList);
|
||
|
if (NULL != ptAgent->ptNext) {
|
||
|
ptAgent->ptNext->ptPrev = ptAgent;
|
||
|
}
|
||
|
} while (0);
|
||
|
|
||
|
} while (0);
|
||
|
}
|
||
|
|
||
|
return ptAgent;
|
||
|
}
|
||
|
|
||
|
task_cycle_info_agent_t *
|
||
|
unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent) {
|
||
|
__IRQ_SAFE {
|
||
|
do {
|
||
|
if (NULL == ptAgent) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
task_cycle_info_agent_t *ptPrev = ptAgent->ptPrev;
|
||
|
if (NULL == ptPrev) {
|
||
|
break; /* this should not happen */
|
||
|
}
|
||
|
if (ptPrev->ptNext != ptAgent) {
|
||
|
// already removed
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//! remove agent from the next-list
|
||
|
ptPrev->ptNext = ptAgent->ptNext;
|
||
|
|
||
|
if (NULL != ptAgent->ptNext) {
|
||
|
// remove agent from the prev-list
|
||
|
ptAgent->ptNext->ptPrev = ptPrev;
|
||
|
}
|
||
|
|
||
|
ptAgent->ptNext = NULL;
|
||
|
ptAgent->ptPrev = NULL;
|
||
|
|
||
|
} while (0);
|
||
|
}
|
||
|
|
||
|
return ptAgent;
|
||
|
}
|
||
|
|
||
|
|
||
|
void __on_context_switch_in(uint32_t *pwStack) {
|
||
|
struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *) pwStack;
|
||
|
int64_t lTimeStamp = get_system_ticks();
|
||
|
|
||
|
ptRootAgent->lLastTimeStamp = lTimeStamp;
|
||
|
ptRootAgent->tInfo.hwActiveCount++;
|
||
|
|
||
|
if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
|
||
|
// update all agents
|
||
|
task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
|
||
|
while (NULL != ptAgent) {
|
||
|
if (NULL != ptAgent->ptInfo) {
|
||
|
if (ptAgent->ptInfo->bEnabled) {
|
||
|
ptAgent->ptInfo->hwActiveCount++;
|
||
|
}
|
||
|
}
|
||
|
ptAgent = ptAgent->ptNext;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void __on_context_switch_out(uint32_t *pwStack) {
|
||
|
struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *) pwStack;
|
||
|
int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
|
||
|
|
||
|
ptRootAgent->tInfo.nUsedRecent = lCycleUsed;
|
||
|
ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
|
||
|
|
||
|
if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
|
||
|
// update all agents
|
||
|
task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
|
||
|
while (NULL != ptAgent) {
|
||
|
if (NULL != ptAgent->ptInfo) {
|
||
|
if (ptAgent->ptInfo->bEnabled) {
|
||
|
ptAgent->ptInfo->nUsedRecent = lCycleUsed;
|
||
|
ptAgent->ptInfo->lUsedTotal += lCycleUsed;
|
||
|
}
|
||
|
}
|
||
|
ptAgent = ptAgent->ptNext;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
__attribute__((noinline))
|
||
|
void __start_task_cycle_counter(task_cycle_info_t *ptInfo) {
|
||
|
struct __task_cycle_info_t *ptRootAgent =
|
||
|
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||
|
if (NULL == ptRootAgent) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
__IRQ_SAFE {
|
||
|
ptRootAgent->lLastTimeStamp = get_system_ticks();
|
||
|
ptRootAgent->tInfo.lUsedTotal = 0;
|
||
|
|
||
|
if (NULL != ptInfo) {
|
||
|
ptInfo->lUsedTotal = 0;
|
||
|
ptInfo->bEnabled = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
__attribute__((noinline))
|
||
|
int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo) {
|
||
|
struct __task_cycle_info_t *ptRootAgent =
|
||
|
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||
|
if (NULL == ptRootAgent) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int64_t lCycles = 0;
|
||
|
|
||
|
__IRQ_SAFE {
|
||
|
int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
|
||
|
ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
|
||
|
|
||
|
if (NULL != ptInfo) {
|
||
|
if (ptInfo->bEnabled) {
|
||
|
ptInfo->nUsedRecent = lCycleUsed;
|
||
|
ptInfo->lUsedTotal += lCycleUsed;
|
||
|
ptInfo->bEnabled = false;
|
||
|
}
|
||
|
|
||
|
lCycles = ptInfo->lUsedTotal;
|
||
|
} else {
|
||
|
lCycles = ptRootAgent->tInfo.lUsedTotal;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return lCycles;
|
||
|
}
|