@@ -12,6 +12,7 @@ void CCpuMonitorTenant::Startup() {
1212
1313 prevExecutionCycles = stats.execution_cycles ;
1414 prevTotalCycles = stats.total_cycles ;
15+ prevUptime = k_uptime_get_32 ();
1516}
1617
1718void CCpuMonitorTenant::PostStartup () {
@@ -55,17 +56,31 @@ uint32_t CCpuMonitorTenant::getUptime() {
5556uint8_t CCpuMonitorTenant::getUtilization () {
5657 k_thread_runtime_stats stats{0 };
5758 k_thread_runtime_stats_all_get (&stats);
59+ uint32_t currentUptime = k_uptime_get_32 ();
5860
59- uint64_t deltaExecution = stats.execution_cycles - prevExecutionCycles;
60- uint64_t deltaTotal = stats.total_cycles - prevTotalCycles;
61+ // Zephyr's naming is confusing! Based on kernel/thread.h comments:
62+ // execution_cycles = total # of cycles (cpu: non-idle + idle) = ALL cycles
63+ // total_cycles = total # of non-idle cycles = ACTIVE/BUSY cycles only
64+ uint64_t deltaAllCycles = stats.execution_cycles - prevExecutionCycles; // All cycles (active + idle)
65+ uint64_t deltaActiveCycles = stats.total_cycles - prevTotalCycles; // Active cycles only
66+ uint32_t deltaTime = currentUptime - prevUptime;
6167
6268 prevExecutionCycles = stats.execution_cycles ;
6369 prevTotalCycles = stats.total_cycles ;
70+ prevUptime = currentUptime;
6471
65- if (deltaExecution == 0 ) {
72+ if (deltaAllCycles == 0 || deltaTime == 0 ) {
6673 return 0 ; // Avoid division by zero
6774 }
6875
69- // Utilization is the percentage of non-idle cycles in the interval
70- return static_cast <uint8_t >((deltaTotal * 100 ) / deltaExecution);
76+ if (deltaTime < 10 ) {
77+ LOG_WRN_ONCE (" CPU utilization measurement interval too short for accuracy" );
78+ }
79+
80+ // CPU Utilization = (Active cycles / All cycles) × 100
81+ // gives the percentage of time the CPU is NOT idle
82+ uint64_t utilization = (deltaActiveCycles * 100 ) / deltaAllCycles;
83+
84+ // Clamp to 100% in case of any edge cases
85+ return static_cast <uint8_t >(utilization > 100 ? 100 : utilization);
7186}
0 commit comments