From 0b6bd68a24ae6a98fceb40d539f1d620a129b7f3 Mon Sep 17 00:00:00 2001 From: JalleliAchraf Date: Tue, 16 Dec 2025 17:43:33 +0100 Subject: [PATCH] frontend UI improvements + compile metrics script fixes --- compile_metrics.sh | 19 ++-- electron/src/control/units.tsx | 42 ++++++++ electron/src/metrics/MetricsControlPage.tsx | 107 +++++++++++++++----- electron/src/metrics/MetricsGraphsPage.tsx | 37 ++++--- 4 files changed, 152 insertions(+), 53 deletions(-) diff --git a/compile_metrics.sh b/compile_metrics.sh index 4439a83b..dc02fd0a 100755 --- a/compile_metrics.sh +++ b/compile_metrics.sh @@ -3,18 +3,15 @@ set -euo pipefail BUILD_DIR="${BUILD_DIR:-target}" CSV_FILE="${CSV_FILE:-compile_metrics.csv}" +DEFAULT_PKG="server" -if [ "$#" -lt 1 ]; then - echo "Usage: $0 cargo build [--release]" - exit 1 +if [ "$#" -eq 0 ]; then + set -- cargo build fi -if [ -d "$BUILD_DIR" ]; then - find "$BUILD_DIR" -type f -name '*.ll' -delete -fi - -if [ "$1" = "cargo" ] && [ "$2" = "build" ]; then - BUILD_CMD=(cargo rustc) +if [ "${1:-}" = "cargo" ] && [ "${2:-}" = "build" ]; then + cargo clean + BUILD_CMD=(cargo rustc -p "$DEFAULT_PKG") shift 2 BUILD_CMD+=("$@") BUILD_CMD+=(-- --emit=llvm-ir -C debuginfo=0) @@ -57,7 +54,6 @@ else binary_size_bytes=0 fi - finished_timestamp_ms=$(($(date +%s%N) / 1000000)) finished_datetime=$(date -Iseconds) @@ -67,4 +63,5 @@ fi echo "${finished_datetime},${finished_timestamp_ms},${compile_ms},${llvm_ir_lines},${binary_size_bytes}" \ >> "$CSV_FILE" -echo "Metrics recorded in $CSV_FILE" \ No newline at end of file + +echo "Metrics recorded in $CSV_FILE" diff --git a/electron/src/control/units.tsx b/electron/src/control/units.tsx index b53959de..fe2ba4d1 100644 --- a/electron/src/control/units.tsx +++ b/electron/src/control/units.tsx @@ -25,6 +25,8 @@ export function getUnitIcon(unit: Unit): IconName { return "lu:Gauge"; case "mHz": return "lu:AudioWaveform"; + case "Hz": + return "lu:AudioWaveform"; case "W": return "lu:Zap"; case "V": @@ -37,6 +39,16 @@ export function getUnitIcon(unit: Unit): IconName { return "lu:Waves"; case "%": return "lu:ChartNoAxesColumn"; + case "µs": + return "lu:RefreshCcw"; + case "s": + return "lu:Clock"; + case "MiB": + return "lu:MemoryStick"; + case "Mbit/s": + return "lu:Network"; + case "/s": + return "lu:Gauge"; default: return "lu:ChartNoAxesColumn"; } @@ -64,6 +76,8 @@ export function renderUnitSymbol(unit: Unit | undefined): string { return "m/min"; case "mHz": return "mHz"; + case "Hz": + return "Hz"; case "W": return "W"; case "V": @@ -76,6 +90,16 @@ export function renderUnitSymbol(unit: Unit | undefined): string { return "l/min"; case "%": return "%"; + case "µs": + return "µs"; + case "s": + return "s"; + case "MiB": + return "MiB"; + case "Mbit/s": + return "Mbit/s"; + case "/s": + return "/s"; default: return ""; } @@ -125,6 +149,8 @@ export function renderUnitSymbolLong(unit: Unit): string { return "meters/minute"; case "mHz": return "millihertz"; + case "Hz": + return "hertz"; case "W": return "watts"; case "V": @@ -137,6 +163,16 @@ export function renderUnitSymbolLong(unit: Unit): string { return "liters/minute"; case "%": return "percent"; + case "µs": + return "microseconds"; + case "s": + return "seconds"; + case "MiB": + return "mebibytes"; + case "Mbit/s": + return "megabits/second"; + case "/s": + return "per second"; default: return ""; } @@ -153,12 +189,18 @@ export const units = [ "bar", "m/min", "mHz", + "Hz", "W", "V", "A", "kWh", "l/min", "%", + "µs", + "s", + "MiB", + "Mbit/s", + "/s", ] as const; export type Unit = (typeof units)[number]; diff --git a/electron/src/metrics/MetricsControlPage.tsx b/electron/src/metrics/MetricsControlPage.tsx index 44a923ce..c18a5665 100644 --- a/electron/src/metrics/MetricsControlPage.tsx +++ b/electron/src/metrics/MetricsControlPage.tsx @@ -1,17 +1,54 @@ import React from "react"; import { Page } from "@/components/Page"; import { useRuntimeMetrics } from "./useRuntimeMetrics"; +import { SectionTitle } from "@/components/SectionTitle"; +import { + renderValueToReactNode, + renderUnitSymbol, + getUnitIcon, + type Unit, +} from "@/control/units"; +import { Icon } from "@/components/Icon"; type MetricCardProps = { title: string; - value: string; + value: React.ReactNode; + unit?: Unit; }; -function MetricCard({ title, value }: MetricCardProps) { +function renderMetricWithUnit( + value: number | null | undefined, + unit: Unit, + digits = 1, +) { + if (value == null) { + return "—"; + } + + return ( + <> + {renderValueToReactNode(value, unit, (v) => v.toFixed(digits))} + + {renderUnitSymbol(unit)} + + + ); +} + +function MetricCard({ title, value, unit }: MetricCardProps) { + const iconName = unit ? getUnitIcon(unit) : "lu:StickyNote"; + return (
-

{title}

+
+ {iconName && ( + + + + )} +

{title}

+
{value}
@@ -39,55 +76,71 @@ export function MetricsControlPage() { return (
-

- Runtime metrics are refreshed immediately once and then every 5 - seconds. -

- +
+ {/* Loop jitter: max, in µs */} + {/* CPU usage */} + {/* CPU time */} + {/* Memory usage */} + + {/* Total page faults (composite, no single unit) */} + + {/* EtherCAT throughput (RX | TX) */} + {renderMetricWithUnit(rxMbit, "Mbit/s")} + | + {renderMetricWithUnit(txMbit, "Mbit/s")} + + ) : ( + "—" + ) } /> + {/* Preemptions per second */}
diff --git a/electron/src/metrics/MetricsGraphsPage.tsx b/electron/src/metrics/MetricsGraphsPage.tsx index a7addeff..b010f576 100644 --- a/electron/src/metrics/MetricsGraphsPage.tsx +++ b/electron/src/metrics/MetricsGraphsPage.tsx @@ -8,6 +8,7 @@ import { } from "@/components/graph"; import { useRuntimeMetrics } from "./useRuntimeMetrics"; import { useRuntimeMetricSeries } from "./runtimeSeries"; +import { getUnitIcon, type Unit } from "@/control/units"; export function MetricsGraphsPage() { // Start / keep the global poller alive @@ -18,9 +19,15 @@ export function MetricsGraphsPage() { const syncHook = useGraphSync("runtime-metrics"); + const jitterUnit: Unit = "µs"; + const cpuUnit: Unit = "%"; + const memUnit: Unit = "MiB"; + const ioUnit: Unit = "Mbit/s"; + const preemptUnit: Unit = "/s"; + const jitterConfig: GraphConfig = { - title: "Loop jitter (avg, µs)", - icon: "lu:Activity", + title: "Average Loop Jitter", + icon: getUnitIcon(jitterUnit), colors: { primary: "#f97316", grid: "#e2e8f0", @@ -30,8 +37,8 @@ export function MetricsGraphsPage() { }; const cpuConfig: GraphConfig = { - title: "CPU usage (%)", - icon: "lu:Cpu", + title: "CPU Usage", + icon: getUnitIcon(cpuUnit), colors: { primary: "#3b82f6", grid: "#e2e8f0", @@ -41,8 +48,8 @@ export function MetricsGraphsPage() { }; const memConfig: GraphConfig = { - title: "Memory usage (MiB)", - icon: "lu:MemoryStick", + title: "Memory Usage", + icon: getUnitIcon(memUnit), colors: { primary: "#10b981", grid: "#e2e8f0", @@ -52,8 +59,8 @@ export function MetricsGraphsPage() { }; const ioConfig: GraphConfig = { - title: "EtherCAT throughput (Mbit/s)", - icon: "lu:Network", + title: "EtherCAT Throughput", + icon: getUnitIcon(ioUnit), colors: { primary: "#10b981", grid: "#e2e8f0", @@ -64,8 +71,8 @@ export function MetricsGraphsPage() { }; const preemptConfig: GraphConfig = { - title: "Preemptions per second (1/s)", - icon: "lu:Timer", + title: "Preemptions Per Second", + icon: getUnitIcon(preemptUnit), colors: { primary: "#6366f1", grid: "#e2e8f0", @@ -84,7 +91,7 @@ export function MetricsGraphsPage() { newData: series.jitter, color: "#f97316", }} - unit={undefined} + unit={jitterUnit} renderValue={(v) => v.toFixed(1)} config={jitterConfig} graphId="runtime_jitter" @@ -98,7 +105,7 @@ export function MetricsGraphsPage() { newData: series.cpu, color: "#3b82f6", }} - unit="%" + unit={cpuUnit} renderValue={(v) => v.toFixed(1)} config={cpuConfig} graphId="runtime_cpu" @@ -112,7 +119,7 @@ export function MetricsGraphsPage() { newData: series.mem, color: "#10b981", }} - unit={undefined} + unit={memUnit} renderValue={(v) => v.toFixed(1)} config={memConfig} graphId="runtime_memory" @@ -134,7 +141,7 @@ export function MetricsGraphsPage() { color: "#ef4444", }, ]} - unit={undefined} + unit={ioUnit} renderValue={(v) => v.toFixed(2)} config={ioConfig} graphId="runtime_io" @@ -148,7 +155,7 @@ export function MetricsGraphsPage() { newData: series.preempt, color: "#6366f1", }} - unit={undefined} + unit={preemptUnit} renderValue={(v) => v.toFixed(1)} config={preemptConfig} graphId="runtime_preemptions"