feat: display system swap usage in the TUI memory section#226
Conversation
Surface swap usage in the interactive view so users can spot swap pressure at a glance. This is most important on Apple Silicon, where an over-sized model or mismatched inference-engine parameters spill unified memory into swap and silently degrade throughput. The data plumbing was already in place — `MemoryInfo` carries `swap_{total,used,free}_bytes` across every platform and the Prometheus exporter already publishes `all_smi_swap_*` series — but the TUI never rendered them.
UI changes:
- `print_memory_info` now draws a second `Swap` bar directly below the existing `Mem` bar whenever `swap_total_bytes > 0`. The bar is hidden on hosts with no swap so non-swap deployments stay visually uncluttered, mirroring the API exporter guard at `src/api/metrics/memory.rs:76`.
- The swap segment switches color from magenta (idle: swap exists but is unused) to red (active: `swap_used_bytes > 0`) so active swap pressure is immediately distinguishable — the core signal requested in the issue.
- `BarSegment` gains `swap_used` (Magenta) and `swap_used_active` (Red) helpers alongside the existing `memory_used`/`memory_buffers`/`memory_cache` constructors.
- The help overlay's resource-gauge legend documents the new Swap row with the same colored-keyword styling as the Memory row.
Cluster/remote mode plumbing:
The Prometheus metrics parser previously routed only `memory_*` lines into the per-host memory accumulator. `swap_*` lines were silently dropped, which would have left every cluster-mode `MemoryInfo` row with `swap_total_bytes == 0` and the new UI inert against real remote hosts. Routing now accepts both prefixes, the field map gains `swap_{total,used,free}_bytes`, and a new `test_parse_swap_metrics` test covers the round-trip.
Mock server:
The Apple Silicon and NVIDIA mock templates previously hardcoded swap to zero and did not emit `all_smi_swap_*` series at all, so the new UI could not be demoed via `all-smi-mock-server`. Both templates now seed realistic non-zero swap (4 GB on Apple Silicon with non-zero usage, 32 GB on NVIDIA with variable usage), and the template builders emit `all_smi_swap_{total,used,free}_bytes` series guarded by the same `swap_total_bytes > 0` condition as the real exporter. Three new mock-template tests cover emission-when-present, omission-when-zero, and placeholder resolution.
Tests:
- `memory_renderer`: five new tests covering swap-row visible when total > 0, hidden when total == 0, visible-with-idle-bar when total > 0 but used == 0, red ANSI SGR present when actively swapping, and no panic at narrow terminal widths.
- `metrics_parser`: extended `test_parse_memory_metrics` to assert that absent swap series leave the swap fields at zero, plus a new `test_parse_swap_metrics` that asserts the swap series populate the same `MemoryInfo` row as the matching memory series.
- `nvidia` mock template: three new tests for swap emission/omission and placeholder resolution.
Verification: `cargo check --lib --tests`, `cargo clippy --lib --tests -- -D warnings`, `cargo fmt --check`, and targeted `cargo test --lib ui::renderers::memory_renderer` / `cargo test --lib network::metrics_parser` / `cargo test --features mock --bin all-smi-mock-server mock::templates::nvidia` all pass.
Implementation Review SummaryIntentSurface system swap usage in the TUI memory section so users can spot swap pressure at a glance — primarily for Apple Silicon AI inference workloads where over-sized models silently spill unified memory into swap. Verification
NotesThe optional secondary indicator described in the issue (compact The metrics-parser extension was not listed in the issue's "Affected files" but turned out to be required: without it, cluster/remote mode would silently drop every |
Security & Performance ReviewSecurity
Performance
FindingsNone. |
Refs #221, #222, #224, #225, #226, #227. Align config path active discovery with the implicit loader's first-existing-candidate semantics, correct record output help and resolver docs against the binary default, and make the swap-color regression test derive crossterm's current Red SGR sequence instead of hard-coding older encodings.
Refs #221, #222, #224, #225, #226, #227. Align config path active discovery with the implicit loader's first-existing-candidate semantics, correct record output help and resolver docs against the binary default, and make the swap-color regression test derive crossterm's current Red SGR sequence instead of hard-coding older encodings.
Summary
Surface system swap usage in the TUI memory section so users can spot swap pressure at a glance. Most important on Apple Silicon, where over-sized models spill unified memory into swap and silently degrade AI inference throughput. The data was already collected and exported on every platform; this PR is the long-missing rendering and end-to-end demoability work.
What changed
src/ui/renderers/memory_renderer.rs: addedprint_swap_barand conditional rendering. The swap row is drawn directly below the Mem bar only whenswap_total_bytes > 0(mirrorssrc/api/metrics/memory.rs:76); the bar segment color flips from magenta (idle) to red (active swap pressure) whenswap_used_bytes > 0.src/ui/widgets.rs: newBarSegment::swap_usedandBarSegment::swap_used_activehelpers alongsidememory_used/memory_buffers/memory_cache.src/ui/help.rs: documented the new swap row in the resource-gauge legend using the same colored-keyword styling as the memory row.src/network/metrics_parser.rs: extended the per-host memory accumulator to routeswap_*lines into the sameMemoryInforow asmemory_*lines, populatingswap_{total,used,free}_bytes. Without this, cluster/remote mode would silently drop every swap series and the new UI would render inert against real remote hosts.src/mock/templates/apple_silicon.rsandsrc/mock/templates/nvidia.rs: replaced hardcoded zero swap with realistic non-zero values (4 GB on Apple Silicon, 32 GB on NVIDIA) and now emitall_smi_swap_{total,used,free}_bytesseries guarded by the sameswap_total_bytes > 0condition as the real exporter. Lets reviewers exercise the new UI end-to-end againstall-smi-mock-server.README.md: documented the new swap row, the hide-when-zero behaviour, and the active-swap red emphasis under the Memory Monitoring section.Test plan
cargo check --lib --tests(clean)cargo clippy --lib --tests -- -D warnings(clean)cargo fmt --check(clean)cargo test --lib ui::renderers::memory_renderer(9 tests pass — includes 5 new tests for swap-row visible/hidden/idle/active/narrow-width)cargo test --lib network::metrics_parser(48 tests pass — includes newtest_parse_swap_metrics)cargo test --features mock --bin all-smi-mock-server mock::templates::nvidia(12 tests pass — includes 3 new tests for swap emission/omission/render)Closes #220