Files
MARTe-Integrated-Components/Client/streamhub/StatsPanel.cpp
T
2026-06-12 15:25:13 +02:00

94 lines
3.2 KiB
C++

/**
* @file StatsPanel.cpp
* @brief Statistics table implementation.
*/
#include "StatsPanel.h"
#include "App.h"
#include "imgui.h"
#include "implot.h"
#include <cstdio>
namespace StreamHubClient {
void RenderStatsPanel(App& app) {
const auto& sources = app.sources();
ImGuiTableFlags flags =
ImGuiTableFlags_Borders |
ImGuiTableFlags_RowBg |
ImGuiTableFlags_ScrollX |
ImGuiTableFlags_SizingFixedFit;
if (!ImGui::BeginTable("##statstbl", 9, flags)) { return; }
ImGui::TableSetupScrollFreeze(1, 1);
ImGui::TableSetupColumn("Source");
ImGui::TableSetupColumn("State");
ImGui::TableSetupColumn("Cycles Rx");
ImGui::TableSetupColumn("Lost");
ImGui::TableSetupColumn("Rate Hz");
ImGui::TableSetupColumn("Frags/cyc");
ImGui::TableSetupColumn("Bytes/cyc");
ImGui::TableSetupColumn("Cycle ms (avg±std)");
ImGui::TableSetupColumn("Cycle ms (min/max)");
ImGui::TableHeadersRow();
for (const auto& src : sources) {
const SourceStats& st = src.stats;
ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TextUnformatted(src.id.c_str());
/* State cell with color */
ImGui::TableNextColumn();
ImVec4 stColor = (st.state == "connected")
? ImVec4(0.2f,0.9f,0.3f,1.f)
: ImVec4(0.9f,0.3f,0.3f,1.f);
ImGui::TextColored(stColor, "%s", st.state.c_str());
ImGui::TableNextColumn(); ImGui::Text("%llu", (unsigned long long)st.totalReceived);
ImGui::TableNextColumn(); ImGui::Text("%llu", (unsigned long long)st.totalLost);
ImGui::TableNextColumn(); ImGui::Text("%.2f ± %.2f", st.rateHz, st.rateStdHz);
ImGui::TableNextColumn(); ImGui::Text("%.1f", st.fragsPerCycle);
ImGui::TableNextColumn(); ImGui::Text("%.0f", st.bytesPerCycle);
ImGui::TableNextColumn(); ImGui::Text("%.3f ± %.3f", st.cycleAvgMs, st.cycleStdMs);
ImGui::TableNextColumn(); ImGui::Text("%.3f / %.3f", st.cycleMinMs, st.cycleMaxMs);
}
ImGui::EndTable();
/* ── Cycle-time histograms (20 bins, mirrors web UI) ────────────── */
for (const auto& src : sources) {
const SourceStats& st = src.stats;
if (st.cycleHistMax <= st.cycleHistMin) { continue; }
char title[160];
snprintf(title, sizeof(title), "Cycle time %s##hist_%s",
src.id.c_str(), src.id.c_str());
if (ImPlot::BeginPlot(title, ImVec2(-1.f, 140.f),
ImPlotFlags_NoMouseText | ImPlotFlags_NoMenus)) {
const double binW =
(st.cycleHistMax - st.cycleHistMin) / 20.0;
double xs[20];
for (int b = 0; b < 20; b++) {
xs[b] = st.cycleHistMin + (b + 0.5) * binW;
}
ImPlot::SetupAxes("cycle ms", "count",
ImPlotAxisFlags_AutoFit,
ImPlotAxisFlags_AutoFit);
ImPlot::PlotBars("##bars", xs, st.cycleHist, 20, binW * 0.9);
ImPlot::EndPlot();
}
}
ImGui::Spacing();
if (ImGui::Button("Refresh")) {
app.ws().sendText(BuildGetStats());
}
}
} /* namespace StreamHubClient */