perf_counter/perf_counter.c

697 lines
20 KiB
C
Raw Normal View History

2021-01-09 13:18:39 +00:00
/****************************************************************************
2024-01-17 06:50:33 +00:00
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
2021-01-09 13:18:39 +00:00
* *
* 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 ======================================*/
2022-11-01 01:41:22 +00:00
#undef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
2021-01-09 13:10:37 +00:00
#include <stdint.h>
2021-02-08 18:41:49 +00:00
#include <stdbool.h>
#include <string.h>
2021-01-09 13:10:37 +00:00
#include "cmsis_compiler.h"
2021-12-22 23:11:09 +00:00
#define __IMPLEMENT_PERF_COUNTER
2021-01-09 13:10:37 +00:00
#include "perf_counter.h"
2021-07-19 23:55:51 +01:00
#if defined(__IS_COMPILER_GCC__)
# pragma GCC diagnostic ignored "-Wattributes"
#endif
2023-03-03 00:18:41 +00:00
#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"
2023-03-03 00:47:15 +00:00
# pragma clang diagnostic ignored "-Wmissing-prototypes"
2023-03-03 00:18:41 +00:00
#endif
2021-07-19 23:55:51 +01:00
/*============================ 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
2021-01-09 13:18:39 +00:00
/*============================ MACROFIED FUNCTIONS ===========================*/
/*============================ TYPES =========================================*/
2021-12-22 23:11:09 +00:00
struct __task_cycle_info_t {
2022-05-30 16:10:39 +01:00
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
2021-12-22 23:11:09 +00:00
} ;
2021-01-09 13:18:39 +00:00
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
2024-12-08 18:52:01 +00:00
2023-08-30 00:51:00 +08:00
volatile static int64_t s_lOldTimestamp;
2024-12-08 18:52:01 +00:00
volatile static int64_t s_lOldTimestampUS;
volatile static int64_t s_lOldTimestampMS;
2024-01-20 18:49:43 +00:00
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;
2024-01-22 13:48:48 +00:00
volatile static int64_t s_lSystemMS = 0;
volatile static int64_t s_lSystemUS = 0;
2022-02-14 16:36:03 +00:00
2022-06-13 20:29:20 -04:00
volatile static int64_t s_lSystemClockCounts = 0;
2021-01-09 13:18:39 +00:00
2024-12-08 18:52:01 +00:00
volatile int32_t g_nOffset = 0;
volatile int64_t g_lLastTimeStamp = 0;
2021-01-09 13:18:39 +00:00
/*============================ PROTOTYPES ====================================*/
2021-01-09 13:10:37 +00:00
2024-01-20 18:49:43 +00:00
/* low level interface for porting */
extern
uint32_t perfc_port_get_system_timer_freq(void);
2024-01-20 18:49:43 +00:00
extern
2024-01-22 13:48:48 +00:00
int64_t perfc_port_get_system_timer_top(void);
2024-01-20 18:49:43 +00:00
extern
bool perfc_port_is_system_timer_ovf_pending(void);
extern
2024-01-27 14:04:03 +00:00
bool perfc_port_init_system_timer(bool bTimerOccupied);
2024-01-20 18:49:43 +00:00
extern
2024-01-22 13:48:48 +00:00
int64_t perfc_port_get_system_timer_elapsed(void);
2024-01-20 18:49:43 +00:00
extern
void perfc_port_clear_system_timer_ovf_pending(void);
extern
void perfc_port_stop_system_timer_counting(void);
extern
void perfc_port_clear_system_timer_counter(void);
2022-06-13 20:29:20 -04:00
2024-01-20 18:49:43 +00:00
/*============================ IMPLEMENTATION ================================*/
/*============================ INCLUDES ======================================*/
2021-01-09 13:10:37 +00:00
void perfc_port_insert_to_system_timer_insert_ovf_handler(void)
2021-01-09 13:10:37 +00:00
{
2024-01-22 13:48:48 +00:00
int64_t lLoad = perfc_port_get_system_timer_top() + 1;
2022-06-13 20:29:20 -04:00
2024-12-06 11:10:33 +00:00
/* prevent high priority exceptions from preempting the system timer OVF
* exception handling
*/
__IRQ_SAFE {
s_lSystemClockCounts += lLoad;
// update system ms counter
do {
int64_t lTemp = s_wMSResidule + lLoad;
2024-12-08 18:52:01 +00:00
2024-12-06 11:10:33 +00:00
int64_t lMS = lTemp / s_wMSUnit;
s_lSystemMS += lMS;
s_wMSResidule = (uint32_t)((int64_t)lTemp - (int64_t)lMS * s_wMSUnit);
2024-01-22 13:48:48 +00:00
2024-12-06 11:10:33 +00:00
} while(0);
2024-12-08 18:52:01 +00:00
}
2022-09-24 20:07:10 +01:00
2024-12-08 18:52:01 +00:00
__IRQ_SAFE {
2024-12-06 11:10:33 +00:00
// update system us counter
do {
int64_t lTemp = s_wUSResidule + lLoad;
2024-12-08 18:52:01 +00:00
2024-12-06 11:10:33 +00:00
int64_t lUS = lTemp / s_wUSUnit;
s_lSystemUS += lUS;
2024-01-22 13:48:48 +00:00
2024-12-06 11:10:33 +00:00
s_wUSResidule = (uint32_t)((int64_t)lTemp - (int64_t)lUS * s_wUSUnit);
} while(0);
}
2021-01-09 13:10:37 +00:00
}
2024-04-09 20:48:59 +01:00
uint32_t perfc_get_systimer_frequency(void)
{
return perfc_port_get_system_timer_freq();
}
2022-06-13 20:29:20 -04:00
__WEAK
2021-12-27 12:16:20 +00:00
void __perf_os_patch_init(void)
{
}
2022-06-20 17:00:16 +01:00
2022-06-14 00:39:54 +01:00
void update_perf_counter(void)
{
uint32_t wSystemFrequency = perfc_port_get_system_timer_freq();
2024-01-20 18:49:43 +00:00
s_wUSUnit = wSystemFrequency / 1000000ul;
s_wMSUnit = wSystemFrequency / 1000ul;
2022-07-08 11:17:13 +01:00
__IRQ_SAFE {
g_lLastTimeStamp = get_system_ticks();
2024-07-06 07:19:50 +01:00
__perfc_sync_barrier__();
2022-07-08 11:17:13 +01:00
g_nOffset = get_system_ticks() - g_lLastTimeStamp;
}
2022-06-14 00:39:54 +01:00
}
2021-12-27 12:16:20 +00:00
2024-01-27 14:04:03 +00:00
bool init_cycle_counter(bool bIsSysTickOccupied)
2021-01-09 13:10:37 +00:00
{
2024-01-27 14:04:03 +00:00
bool bResult = false;
2021-06-07 16:30:39 +01:00
__IRQ_SAFE {
2024-01-27 14:04:03 +00:00
bResult = perfc_port_init_system_timer(bIsSysTickOccupied); // use the longest period
2024-01-20 18:49:43 +00:00
perfc_port_clear_system_timer_ovf_pending();
2021-01-09 13:10:37 +00:00
}
2022-07-06 22:43:39 +01:00
2022-06-14 00:39:54 +01:00
update_perf_counter();
2022-05-30 16:38:58 +01:00
s_lSystemClockCounts = 0; // reset system cycle counter
2024-01-22 13:48:48 +00:00
s_lSystemMS = 0; // reset system millisecond counter
s_lSystemUS = 0; // reset system microsecond counter
2024-04-09 20:48:59 +01:00
s_lOldTimestamp = 0;
2024-12-08 18:52:01 +00:00
s_lOldTimestampUS = 0;
s_lOldTimestampMS = 0;
2024-04-09 20:48:59 +01:00
2021-12-27 12:16:20 +00:00
__perf_os_patch_init();
2024-01-27 14:04:03 +00:00
return bResult;
2021-01-09 13:10:37 +00:00
}
/*! \note this function should only be called when irq is disabled
2022-05-30 16:38:58 +01:00
* hence SysTick-LOAD and (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)
2022-06-13 20:29:20 -04:00
* won't change.
*/
2024-01-22 13:48:48 +00:00
__STATIC_INLINE int64_t check_systick(void)
2021-01-09 13:10:37 +00:00
{
2024-01-22 13:48:48 +00:00
int64_t lTemp = perfc_port_get_system_timer_elapsed();
2022-06-20 17:00:16 +01:00
/* Since we cannot stop counting temporarily, there are several
2022-05-30 16:38:58 +01:00
* conditions which we should take into consideration:
2022-06-13 20:29:20 -04:00
* - Condition 1: when assigning nTemp with the register value (LOAD-VAL),
2022-05-30 16:38:58 +01:00
* the underflow didn't happen but when we check the PENDSTSET bit,
2024-12-06 11:45:14 +00:00
* the underflow happens, for this condition, we should recall the
* perfc_port_get_system_timer_elapsed().
2022-05-30 16:38:58 +01:00
* The following code implements an equivalent logic.
2021-01-09 13:10:37 +00:00
*/
2024-01-20 18:49:43 +00:00
if (perfc_port_is_system_timer_ovf_pending()){
2024-12-06 11:45:14 +00:00
/* refresh the elapsed just in case the counter has just overflowed/underflowed
* after we called the perfc_port_get_system_timer_elapsed()
*/
lTemp = perfc_port_get_system_timer_elapsed();
lTemp += perfc_port_get_system_timer_top() + 1;
2021-01-09 13:10:37 +00:00
}
2022-06-13 20:29:20 -04:00
2024-01-22 13:48:48 +00:00
return lTemp;
2021-01-09 13:10:37 +00:00
}
2023-06-12 08:37:19 +01:00
void before_cycle_counter_reconfiguration(void)
{
__IRQ_SAFE {
2024-01-20 18:49:43 +00:00
perfc_port_stop_system_timer_counting();
2023-06-12 08:37:19 +01:00
2024-01-20 18:49:43 +00:00
if (perfc_port_is_system_timer_ovf_pending()) {
perfc_port_clear_system_timer_ovf_pending(); /* clear pending bit */
2023-06-12 08:37:19 +01:00
2024-03-14 15:49:50 +00:00
perfc_port_insert_to_system_timer_insert_ovf_handler(); /* manually handle exception */
2023-06-12 08:37:19 +01:00
}
s_lSystemClockCounts = get_system_ticks(); /* get the final cycle counter value */
2024-01-17 09:04:20 +00:00
2024-01-20 18:49:43 +00:00
perfc_port_clear_system_timer_counter();
2023-06-12 08:37:19 +01:00
}
}
2021-11-13 14:07:11 +00:00
__attribute__((constructor))
2021-01-09 13:10:37 +00:00
void __perf_counter_init(void)
{
init_cycle_counter(true);
}
2022-06-20 17:00:16 +01:00
2024-01-20 18:49:43 +00:00
void delay_us(uint32_t wUs)
2021-01-09 13:10:37 +00:00
{
2024-01-20 18:49:43 +00:00
int64_t lUs = (int64_t)wUs * (int64_t)s_wUSUnit;
2022-07-08 10:26:33 +01:00
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
? g_nOffset
: PERF_CNT_DELAY_US_COMPENSATION;
2022-06-13 20:29:20 -04:00
2022-07-08 10:26:33 +01:00
if (lUs <= iCompensate) {
2022-02-14 16:36:03 +00:00
return ;
2022-06-13 20:29:20 -04:00
}
2022-07-08 10:26:33 +01:00
lUs -= iCompensate;
2022-06-13 20:29:20 -04:00
2022-02-14 16:36:03 +00:00
lUs += get_system_ticks();
while(get_system_ticks() < lUs);
}
2024-01-20 18:49:43 +00:00
void delay_ms(uint32_t wMs)
2022-02-14 16:36:03 +00:00
{
2024-01-22 17:19:57 +00:00
int64_t lMs = (int64_t)wMs * (int64_t)s_wMSUnit;
2022-07-08 10:26:33 +01:00
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
? g_nOffset
: PERF_CNT_DELAY_US_COMPENSATION;
2022-06-13 20:29:20 -04:00
2024-01-22 17:19:57 +00:00
if (lMs <= iCompensate) {
return ;
2022-06-13 20:29:20 -04:00
}
2024-01-22 17:19:57 +00:00
lMs -= iCompensate;
2022-06-13 20:29:20 -04:00
2024-01-22 17:19:57 +00:00
lMs += get_system_ticks();
2024-01-22 17:58:21 +00:00
while(get_system_ticks() < lMs);
2021-01-09 13:10:37 +00:00
}
2022-09-05 23:38:32 +01:00
__attribute__((noinline))
int64_t get_system_ticks(void)
{
int64_t lTemp = 0;
__IRQ_SAFE {
lTemp = check_systick() + s_lSystemClockCounts;
2023-08-30 00:51:00 +08:00
/* 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;
}
2022-09-05 23:38:32 +01:00
}
return lTemp;
}
2021-01-09 13:51:30 +00:00
/*! \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
2022-06-13 20:29:20 -04:00
*! 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
2021-01-09 13:51:30 +00:00
*! defined as uint32_t in timer.h.
*! Since we are not allowed to change the defintion of clock_t in
2022-06-13 20:29:20 -04:00
*! 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
2021-01-09 13:51:30 +00:00
*! to store the higher 32bits. When you are using the prototype from
2022-06-13 20:29:20 -04:00
*! timer.h, caller will only take the lower 32bits stored in R0 and
2021-01-09 13:51:30 +00:00
*! the higher 32bits stored in R1 will be ignored.
2022-06-13 20:29:20 -04:00
*!
2021-01-09 13:51:30 +00:00
*! If you want to use the non-overflow version of this clock(), please
2022-06-13 20:29:20 -04:00
*! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
2021-01-09 13:51:30 +00:00
*! and 2) do not include system header file <time.h>
*!
*/
2021-11-13 14:07:11 +00:00
#if !defined(__IS_COMPILER_IAR__)
2022-06-13 20:29:20 -04:00
__attribute__((nothrow))
2021-11-13 14:07:11 +00:00
#endif
__attribute__((noinline))
2021-01-09 13:10:37 +00:00
int64_t clock(void)
{
2022-09-05 23:38:32 +01:00
return get_system_ticks();
}
2021-12-22 23:11:09 +00:00
2024-01-22 13:48:48 +00:00
int64_t get_system_ms(void)
2022-02-14 16:36:03 +00:00
{
2024-01-22 13:48:48 +00:00
int64_t lTemp = 0;
2022-06-13 20:29:20 -04:00
2022-02-14 16:36:03 +00:00
__IRQ_SAFE {
2024-12-08 18:52:01 +00:00
lTemp = s_lSystemMS
+ ( (check_systick()
+ (int64_t)s_wMSResidule) / s_wMSUnit);
if (lTemp < s_lOldTimestampMS) {
lTemp = s_lOldTimestampMS;
} else {
s_lOldTimestampMS = lTemp;
}
2022-02-14 16:36:03 +00:00
}
2022-06-13 20:29:20 -04:00
2024-01-22 13:48:48 +00:00
return lTemp;
2022-02-14 16:36:03 +00:00
}
2024-01-22 13:48:48 +00:00
int64_t get_system_us(void)
2022-09-24 20:07:10 +01:00
{
2024-01-22 13:48:48 +00:00
int64_t lTemp = 0;
2022-09-24 20:07:10 +01:00
__IRQ_SAFE {
2024-12-08 18:52:01 +00:00
lTemp = s_lSystemUS
+ ( (check_systick()
+ (int64_t)s_wUSResidule) / s_wUSUnit);
if (lTemp < s_lOldTimestampUS) {
lTemp = s_lOldTimestampUS;
} else {
s_lOldTimestampUS = lTemp;
}
2022-09-24 20:07:10 +01:00
}
2024-01-22 13:48:48 +00:00
return lTemp;
2022-09-24 20:07:10 +01:00
}
2023-05-18 13:03:47 +01:00
int64_t perfc_convert_ticks_to_ms(int64_t lTick)
{
2024-01-20 18:49:43 +00:00
return lTick / (int64_t)s_wMSUnit;
2023-05-18 13:03:47 +01:00
}
int64_t perfc_convert_ms_to_ticks(uint32_t wMS)
{
2024-01-20 18:49:43 +00:00
int64_t lResult = (int64_t)s_wMSUnit * (int64_t)wMS;
2023-05-18 13:03:47 +01:00
return lResult ? lResult : 1;
}
int64_t perfc_convert_ticks_to_us(int64_t lTick)
{
2024-01-20 18:49:43 +00:00
return lTick / (int64_t)s_wUSUnit;
2023-05-18 13:03:47 +01:00
}
int64_t perfc_convert_us_to_ticks(uint32_t wMS)
{
2024-01-20 18:49:43 +00:00
int64_t lResult = (int64_t)s_wUSUnit * (int64_t)wMS;
2023-05-18 13:03:47 +01:00
return lResult ? lResult : 1;
}
bool __perfc_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload)
2023-05-18 13:03:47 +01:00
{
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;
}
2023-05-18 13:03:47 +01:00
return true;
}
return false;
}
2023-03-19 23:08:08 +00:00
/// 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 perfc_port_get_system_timer_freq();
2023-03-19 23:08:08 +00:00
}
/// Get timer count.
/// \return timer count (32-bit)
uint32_t EventRecorderTimerGetCount (void)
{
return get_system_ticks();
2023-03-19 23:08:08 +00:00
}
2022-06-13 20:29:20 -04:00
__WEAK
task_cycle_info_t * get_rtos_task_cycle_info(void)
2021-12-22 23:11:09 +00:00
{
return NULL;
}
void init_task_cycle_counter(void)
2021-12-22 23:11:09 +00:00
{
2022-06-13 20:29:20 -04:00
struct __task_cycle_info_t * ptRootAgent =
(struct __task_cycle_info_t *)get_rtos_task_cycle_info();
if (NULL == ptRootAgent) {
return ;
}
2022-06-13 20:29:20 -04:00
memset(ptRootAgent, 0, sizeof(struct __task_cycle_info_t));
2022-06-13 20:29:20 -04:00
ptRootAgent->tList.ptInfo = &(ptRootAgent->tInfo);
ptRootAgent->tInfo.lStart = get_system_ticks();
ptRootAgent->wMagicWord = MAGIC_WORD_CANARY;
}
2021-12-22 23:11:09 +00:00
2023-10-19 22:53:52 +01:00
bool perfc_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;
}
2023-10-20 00:43:01 +01:00
if ( (MAGIC_WORD_CANARY == ptRootAgent->wMagicWord)
|| (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord)) {
2023-10-19 22:53:52 +01:00
return true;
}
} while(0);
return false;
}
2022-02-12 23:04:46 +00:00
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);
2022-06-13 20:29:20 -04:00
2022-02-12 23:04:46 +00:00
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;
}
2022-06-13 20:29:20 -04:00
struct __task_cycle_info_t * ptRootAgent =
(struct __task_cycle_info_t *)get_rtos_task_cycle_info();
if (NULL == ptRootAgent) {
break;
}
2022-06-13 20:29:20 -04:00
ptRootAgent->wMagicWord = MAGIC_WORD_AGENT_LIST_VALID;
2022-06-13 20:29:20 -04:00
ptAgent->ptInfo = ptInfo;
2022-06-13 20:29:20 -04:00
2022-06-20 17:00:16 +01:00
// push to the stack
do {
2022-06-20 17:00:16 +01:00
// set next-list
ptAgent->ptNext = ptRootAgent->tList.ptNext;
ptRootAgent->tList.ptNext = ptAgent;
2022-06-13 20:29:20 -04:00
2022-06-20 17:00:16 +01:00
// set prev-list
ptAgent->ptPrev = &(ptRootAgent->tList);
if (NULL != ptAgent->ptNext) {
ptAgent->ptNext->ptPrev = ptAgent;
}
} while(0);
2022-06-13 20:29:20 -04:00
} while(0);
}
2022-06-13 20:29:20 -04:00
return ptAgent;
}
task_cycle_info_agent_t *
unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent)
{
__IRQ_SAFE {
do {
if (NULL == ptAgent) {
break;
}
2022-06-13 20:29:20 -04:00
task_cycle_info_agent_t *ptPrev = ptAgent->ptPrev;
if (NULL == ptPrev) {
break; /* this should not happen */
}
if (ptPrev->ptNext != ptAgent) {
2022-06-20 17:00:16 +01:00
// already removed
break;
}
2022-06-13 20:29:20 -04:00
//! remove agent from the next-list
ptPrev->ptNext = ptAgent->ptNext;
2022-06-13 20:29:20 -04:00
if (NULL != ptAgent->ptNext) {
2022-06-20 17:00:16 +01:00
// remove agent from the prev-list
ptAgent->ptNext->ptPrev = ptPrev;
}
2022-06-13 20:29:20 -04:00
ptAgent->ptNext = NULL;
ptAgent->ptPrev = NULL;
2022-06-13 20:29:20 -04:00
} while(0);
2021-12-22 23:11:09 +00:00
}
2022-06-13 20:29:20 -04:00
return ptAgent;
}
2021-12-22 23:11:09 +00:00
void __on_context_switch_in(uint32_t *pwStack)
{
struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *)pwStack;
2023-03-03 00:47:15 +00:00
int64_t lTimeStamp = get_system_ticks();
2022-06-13 20:29:20 -04:00
2023-03-03 00:47:15 +00:00
ptRootAgent->lLastTimeStamp = lTimeStamp;
2022-02-12 23:04:46 +00:00
ptRootAgent->tInfo.hwActiveCount++;
if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
2022-06-20 17:00:16 +01:00
// update all agents
task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
while(NULL != ptAgent) {
if (NULL != ptAgent->ptInfo) {
2022-02-12 23:04:46 +00:00
if (ptAgent->ptInfo->bEnabled) {
ptAgent->ptInfo->hwActiveCount++;
}
}
ptAgent = ptAgent->ptNext;
}
}
2021-12-22 23:11:09 +00:00
}
void __on_context_switch_out(uint32_t *pwStack)
{
struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *)pwStack;
2022-07-06 22:43:39 +01:00
int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
2022-06-13 20:29:20 -04:00
ptRootAgent->tInfo.nUsedRecent = lCycleUsed;
ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
2022-06-13 20:29:20 -04:00
if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
2022-06-20 17:00:16 +01:00
// update all agents
task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
while(NULL != ptAgent) {
if (NULL != ptAgent->ptInfo) {
2022-02-12 23:04:46 +00:00
if (ptAgent->ptInfo->bEnabled) {
ptAgent->ptInfo->nUsedRecent = lCycleUsed;
ptAgent->ptInfo->lUsedTotal += lCycleUsed;
}
}
ptAgent = ptAgent->ptNext;
}
}
2021-12-22 23:11:09 +00:00
}
__attribute__((noinline))
2022-02-13 20:04:40 +00:00
void __start_task_cycle_counter(task_cycle_info_t *ptInfo)
2021-12-22 23:11:09 +00:00
{
2022-06-13 20:29:20 -04:00
struct __task_cycle_info_t * ptRootAgent =
2021-12-28 22:30:42 +00:00
(struct __task_cycle_info_t *)get_rtos_task_cycle_info();
if (NULL == ptRootAgent) {
2021-12-28 22:30:42 +00:00
return ;
}
2022-06-13 20:29:20 -04:00
2021-12-28 22:30:42 +00:00
__IRQ_SAFE {
ptRootAgent->lLastTimeStamp = get_system_ticks();
ptRootAgent->tInfo.lUsedTotal = 0;
2022-06-13 20:29:20 -04:00
2022-02-13 20:04:40 +00:00
if (NULL != ptInfo) {
ptInfo->lUsedTotal = 0;
ptInfo->bEnabled = true;
}
2021-12-22 23:11:09 +00:00
}
}
__attribute__((noinline))
2022-02-13 20:04:40 +00:00
int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo)
2021-12-22 23:11:09 +00:00
{
2022-06-13 20:29:20 -04:00
struct __task_cycle_info_t * ptRootAgent =
2021-12-28 22:30:42 +00:00
(struct __task_cycle_info_t *)get_rtos_task_cycle_info();
if (NULL == ptRootAgent) {
2021-12-28 22:30:42 +00:00
return 0;
}
2022-06-13 20:29:20 -04:00
2021-12-29 14:18:41 +00:00
int64_t lCycles = 0;
2022-06-13 20:29:20 -04:00
2022-04-13 19:40:35 +01:00
__IRQ_SAFE {
2022-07-06 22:43:39 +01:00
int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
2022-04-13 19:40:35 +01:00
ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
if (NULL != ptInfo) {
if (ptInfo->bEnabled) {
ptInfo->nUsedRecent = lCycleUsed;
ptInfo->lUsedTotal += lCycleUsed;
ptInfo->bEnabled = false;
}
2022-06-13 20:29:20 -04:00
2022-04-13 19:40:35 +01:00
lCycles = ptInfo->lUsedTotal;
} else {
lCycles = ptRootAgent->tInfo.lUsedTotal;
2022-02-13 20:04:40 +00:00
}
2021-12-22 23:11:09 +00:00
}
2022-06-13 20:29:20 -04:00
2021-12-29 14:18:41 +00:00
return lCycles;
2021-12-22 23:11:09 +00:00
}