Files
DCU_APP/GD32E508_DCU_APP/sys/cpu_load.cpp
T

118 lines
3.5 KiB
C++
Raw Normal View History

/**
* @file cpu_load.cpp
* @brief CPU 负载率测量实现(1.5.61,度量定义与并发协议见 cpu_load.h)。
*
* 热路径(beginWork/endWork/isrEnter/isrExit/tick)放进 .ramfunc——它们会被包进
* EXTI0(Sync0, preempt=0) 等延迟敏感的 ISR 包装,与 EthercatSync::onSync0Exti
* 同款 section 属性,避免 flash 等待态给 Sync0 入口添抖动。1s 一次的窗口
* 结算(含 64 位除法)留在普通 flash 函数里。
*/
#include "sys/cpu_load.h"
#include "RTE_Components.h"
#include CMSIS_device_header
volatile uint32_t CpuLoad::s_depth = 0U;
volatile uint32_t CpuLoad::s_stamp = 0U;
volatile uint32_t CpuLoad::s_busy = 0U;
volatile uint32_t CpuLoad::s_winStart = 0U;
volatile uint16_t CpuLoad::s_loadPerm = 0U;
volatile uint32_t CpuLoad::s_seq = 0U;
/** @brief 区间并集的共享进入点。0→1 者负责盖时间戳;STREX 失败方重试时深度
* 已被抢占者修正,不会再重复盖戳。 */
__attribute__((always_inline)) static inline void cpuLoadEnter()
{
uint32_t d;
do {
d = __LDREXW(&CpuLoad::s_depth);
if (d == 0U) {
CpuLoad::s_stamp = DWT->CYCCNT;
__DMB();
}
} while (__STREXW(d + 1U, &CpuLoad::s_depth) != 0U);
__DMB();
}
/** @brief 区间并集的共享退出点。1→0 者把区间累进 s_busy(同样走独占访问,
* 防"ISR 恰好插在主循环退出的读-改-写之间"丢累加)。 */
__attribute__((always_inline)) static inline void cpuLoadLeave()
{
const uint32_t end = DWT->CYCCNT;
const uint32_t start = CpuLoad::s_stamp;
uint32_t d;
do {
d = __LDREXW(&CpuLoad::s_depth);
} while (__STREXW(d - 1U, &CpuLoad::s_depth) != 0U);
if (d == 1U) {
const uint32_t delta = end - start;
uint32_t b;
do {
b = __LDREXW(&CpuLoad::s_busy);
} while (__STREXW(b + delta, &CpuLoad::s_busy) != 0U);
}
}
void CpuLoad::init()
{
/* DWT 已由 EscLan9252::init 使能;这里幂等兜底(万一 EtherCAT 初始化被裁剪)。 */
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
s_depth = 0U;
s_busy = 0U;
s_winStart = DWT->CYCCNT;
s_loadPerm = 0U;
s_seq = 0U;
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::beginWork()
{
cpuLoadEnter();
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::isrEnter()
{
cpuLoadEnter();
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::isrExit()
{
cpuLoadLeave();
}
/**
* @brief 窗口结算(普通 flash 函数,1s 才进一次)。
* @note s_busy 用独占访问换出:窗口边界上 ISR 的在途累加要么算进本窗口、
* 要么算进下窗口,不丢。
*/
static void cpuLoadRollWindow(uint32_t now)
{
const uint32_t elapsed = now - CpuLoad::s_winStart; /* 调用方已保证 >= 1s */
uint32_t busy;
do {
busy = __LDREXW(&CpuLoad::s_busy);
} while (__STREXW(0U, &CpuLoad::s_busy) != 0U);
CpuLoad::s_winStart = now;
uint32_t perm = (uint32_t)(((uint64_t)busy * 1000ULL) / (uint64_t)elapsed);
if (perm > 1000U) {
perm = 1000U;
}
CpuLoad::s_loadPerm = (uint16_t)perm;
CpuLoad::s_seq++;
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::endWork()
{
cpuLoadLeave();
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::tick()
{
const uint32_t now = DWT->CYCCNT;
if ((uint32_t)(now - s_winStart) >= SystemCoreClock) {
cpuLoadRollWindow(now);
}
}