118 lines
3.5 KiB
C++
118 lines
3.5 KiB
C++
/**
|
|||
|
|
* @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);
|
||
|
|
}
|
||
|
|
}
|