112 lines
3.4 KiB
C++
112 lines
3.4 KiB
C++
#include "utilization.hpp"
|
|
#include "log.hpp"
|
|
#include <cstdint>
|
|
#include <thread>
|
|
#include <zephyr/debug/thread_analyzer.h>
|
|
#include <zephyr/kernel.h>
|
|
|
|
namespace rims {
|
|
|
|
K_FIFO_DEFINE(utilizationIngress);
|
|
K_FIFO_DEFINE(utilizationEggress);
|
|
|
|
fifo_queue<utilization_IngressMessage, 2> utilizationIngressQueue{utilizationIngress};
|
|
fifo_queue<utilization_EgressMessage, 2> utilizationEgressQueue{utilizationEggress};
|
|
|
|
struct StatsAccumulator {
|
|
uint32_t total_cpu = 0;
|
|
uint32_t total_threads = 0;
|
|
uint32_t max_stack_percent = 0;
|
|
uint32_t threads_over_stack_threshold = 0;
|
|
uint32_t idle_thread_cpu = 0;
|
|
uint32_t heap_free_percent = 0; // Optional, left as placeholder
|
|
};
|
|
|
|
// Threshold for stack usage warning (e.g. 80%)
|
|
constexpr uint32_t STACK_WARN_THRESHOLD = 80;
|
|
|
|
// We'll store intermediate values here
|
|
static StatsAccumulator stats{};
|
|
|
|
// Simple utility to calculate percent with safety
|
|
static uint32_t percent(uint32_t used, uint32_t total) {
|
|
if (total == 0) return 0;
|
|
return (used * 100) / total;
|
|
}
|
|
|
|
// Called once per thread by thread_analyzer_run()
|
|
extern "C" void mythread_analyzer_cb(struct thread_analyzer_info *info) {
|
|
if (!info || info->stack_size == 0) return;
|
|
|
|
if (strcmp(info->name, "idle") == 0) {
|
|
stats.idle_thread_cpu = info->utilization;
|
|
return;
|
|
}
|
|
|
|
stats.total_threads++;
|
|
|
|
uint32_t stack_used = info->stack_size - info->stack_used;
|
|
uint32_t stack_used_percent = percent(stack_used, info->stack_size);
|
|
|
|
if (stack_used_percent > stats.max_stack_percent) {
|
|
stats.max_stack_percent = stack_used_percent;
|
|
}
|
|
|
|
if (stack_used_percent >= STACK_WARN_THRESHOLD) {
|
|
stats.threads_over_stack_threshold++;
|
|
}
|
|
stats.total_cpu += info->utilization;
|
|
}
|
|
|
|
// Call after `thread_analyzer_run(mythread_analyzer_cb)`
|
|
void finalize_utilization(utilization_UtilizationSummary &summary, utilization_SystemStats &sysstats) {
|
|
summary.avg_cpu_percent = percent(stats.total_cpu, stats.total_threads * 100);
|
|
summary.max_stack_percent = stats.max_stack_percent;
|
|
summary.thread_count = stats.total_threads;
|
|
summary.cpu_idle = stats.idle_thread_cpu;
|
|
|
|
sysstats.cpu_utilization_percent = stats.total_cpu;
|
|
sysstats.max_stack_utilization_percent = stats.max_stack_percent;
|
|
sysstats.heap_free_percent = stats.heap_free_percent; // Fill from heap stats if available
|
|
sysstats.num_threads_over_threshold = stats.threads_over_stack_threshold;
|
|
|
|
// Reset accumulator if reused
|
|
stats = StatsAccumulator{};
|
|
}
|
|
|
|
// void mythread_analyzer_cb(struct thread_analyzer_info *info) {
|
|
// ULOG_DEBUG(
|
|
// "thread name, memfree, cpu : %s, %d, %d",
|
|
// info->name,
|
|
// info->stack_size - info->stack_used,
|
|
// info->utilization // cpu usage in %
|
|
// );
|
|
// }
|
|
|
|
void run_stats_collection() {
|
|
thread_analyzer_run(mythread_analyzer_cb, 0);
|
|
|
|
utilization_UtilizationSummary summary{};
|
|
utilization_SystemStats sysstats{};
|
|
|
|
finalize_utilization(summary, sysstats);
|
|
|
|
// Now encode with nanopb and send
|
|
// pb_encode(..., &summary);
|
|
// pb_encode(..., &sysstats);
|
|
}
|
|
|
|
void ThreadAnalyzer::loop() {
|
|
while (true) {
|
|
std::this_thread::sleep_for(std::chrono::seconds{5});
|
|
thread_analyzer_run(mythread_analyzer_cb, 0);
|
|
}
|
|
}
|
|
|
|
void ThreadAnalyzerThread::threadMain() {
|
|
ThreadAnalyzer ta;
|
|
ta.loop();
|
|
}
|
|
|
|
} // namespace rims
|