Skip to content

Add unit tests for PerfTelemetry (#2500). Principle III.#2782

Merged
ten9876 merged 4 commits into
mainfrom
aetherclaude/issue-2500
May 17, 2026
Merged

Add unit tests for PerfTelemetry (#2500). Principle III.#2782
ten9876 merged 4 commits into
mainfrom
aetherclaude/issue-2500

Conversation

@ten9876

@ten9876 ten9876 commented May 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2500

What was changed

Covers the matrix from the issue: disabled hot-path no-op, window
aggregation count/p95, window-reset isolation, the full stall-threshold
matrix (panUpdate / waterfallUpdate / render / frameAge / udpDrain /
input), drag-aware UI lag thresholds (50 ms idle / 33 ms drag), the
frame-restart counter, percentile-95 boundary cases (empty / single /
[1..100] sorted / 100 reversed), and the 1 s window cadence (no fire
at 950 ms, fire at 1100 ms).

Two purely additive test seams land on PerfTelemetry:
setClockOverrideForTest(qint64) pins nowNs() to a synthetic value so
window timing is deterministic without real sleeps, and resetForTest()
zeroes aggregation state between cases so the singleton doesn't leak
between tests. The clock override is a single relaxed atomic load in
the hot path; when zero (production default) the original steady_clock
path is used unchanged, so the existing record* call surface that the
17 high-risk callers reach is untouched in shape or behavior.

The test executable links LogManager.cpp + AsyncLogWriter.cpp +
AppSettings.cpp instead of redeclaring its own Q_LOGGING_CATEGORY for
aether.perf — this honors Principle III's consolidation (one
canonical definition site per category, per #2770) and matches the
linkage pattern established by ax25_libmodem_shim_test. Output is
captured via qInstallMessageHandler filtered to aether.perf and
matched on key=value field extraction from emitted PerfStall and
PerfSummary lines.

Blast radius: risk_score=0.418, 17 high-risk affected (top:
MainWindow::MainWindow, MainWindow::wirePanadapter, MainWindow::buildUI,
RadioModel::onStatusReceived, MainWindow::buildMenuBar). All these
reach PerfTelemetry through its existing public record* API which is
unchanged; the additions are two new public test-only methods plus one
relaxed atomic load in nowNs() that is a no-op when the override is
the default zero.

Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

Recovery note

This PR is being opened manually. The aetherclaude orchestrator (trace fe2b51d0) pushed the signed commit at 17:53 PDT but died at the next bash line due to a set -e race with commit-signed.js's exit code. Root cause + fix shipped as 4832725 (run-agent: guard commit-signed + create-pr against set -e silent death).


Generated by AetherClaude (automated agent for AetherSDR) — PR creation completed manually after orchestrator interrupt.

aethersdr-agent Bot and others added 3 commits May 16, 2026 21:55
Adds tests/perf_telemetry_test.cpp covering the public PerfTelemetry
surface: stall thresholds (panUpdate 8ms, frameAge 100ms, render 16ms,
udpDrain 8ms, waterfallUpdate 12ms, input 16ms), drag-aware UI lag
thresholds (50ms idle / 33ms drag), frame-restart counter aggregation,
percentile-95 boundary cases (empty / single / [1..100] / order-invariant),
1-second window cadence (no-fire at 950ms, fire at 1100ms), window
state reset after summary, and the disabled-lcPerf no-op path.

Test seam is the friend-class shim chosen in the earlier triage
(Option A): a forward-declared `PerfTelemetryTestAccess` granted friend
access to the singleton's private members. The shim resets the
singleton between cases, primes m_wasEnabled to bypass the
disabled-to-enabled auto-reset, sets m_windowStartNs and
m_lastHeartbeatNs directly, and invokes the private maybeLogSummary
with synthetic time so window-cadence tests don't depend on real
sleeps. Production hot path is untouched: zero new fields, no
indirection, no new public methods.

Test capture uses a Qt message handler filtered to category
`aether.perf`, with `QLoggingCategory::setFilterRules("aether.perf.debug=true")`
toggling enabled state.

Honors Principle V — new test infrastructure is self-contained and
introduces no flat AppSettings keys.

Blast radius: risk_score=0.438, 16 high-risk affected (top:
MainWindow::MainWindow, MainWindow::buildMenuBar, MainWindow::buildUI).
The high-betweenness callers are pre-existing instrumentation sites
(SpectrumWidget, PanadapterStream, RadioModel, MainWindow) that call
the public record* methods; the changes here are purely additive
(forward declaration + friend declaration + new test target) and
introduce no behavior, no member layout change, and no public-API
shift, so existing callers cannot regress.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Covers the matrix from the issue: disabled hot-path no-op, window
aggregation count/p95, window-reset isolation, the full stall-threshold
matrix (panUpdate/waterfallUpdate/render/frameAge/udpDrain/input),
drag-aware UI lag thresholds, frame-restart counter, percentile-95
boundary cases (empty, single, 100-sorted, 100-reversed), and window
timing across the 1s boundary.

Adds two test seams on PerfTelemetry — `setClockOverrideForTest(qint64)`
to pin nowNs() to a synthetic value, and `resetForTest()` to zero
aggregation state between cases. The clock override is a single relaxed
atomic load in the hot path; when zero (production default) the original
steady_clock path is used unchanged.

The test file declares its own Q_LOGGING_CATEGORY for `aether.perf`
rather than linking LogManager, which would otherwise pull in
AppSettings/AsyncLogWriter. Output is captured via qInstallMessageHandler
and matched on key=value field extraction from the emitted PerfStall /
PerfSummary lines.

Blast radius: risk_score=0.435, 19 high-risk affected (top:
AetherSDR::MainWindow::MainWindow, MainWindow::wirePanadapter,
MainWindow::buildMenuBar). All callers reach PerfTelemetry through
its existing public record* API which is unchanged in shape or
behavior; the additions are two new public test-only methods plus
one relaxed atomic load in nowNs().
Covers the matrix from the issue: disabled hot-path no-op, window
aggregation count/p95, window-reset isolation, the full stall-threshold
matrix (panUpdate / waterfallUpdate / render / frameAge / udpDrain /
input), drag-aware UI lag thresholds (50 ms idle / 33 ms drag), the
frame-restart counter, percentile-95 boundary cases (empty / single /
[1..100] sorted / 100 reversed), and the 1 s window cadence (no fire
at 950 ms, fire at 1100 ms).

Two purely additive test seams land on PerfTelemetry:
`setClockOverrideForTest(qint64)` pins nowNs() to a synthetic value so
window timing is deterministic without real sleeps, and `resetForTest()`
zeroes aggregation state between cases so the singleton doesn't leak
between tests. The clock override is a single relaxed atomic load in
the hot path; when zero (production default) the original steady_clock
path is used unchanged, so the existing record* call surface that the
17 high-risk callers reach is untouched in shape or behavior.

The test executable links LogManager.cpp + AsyncLogWriter.cpp +
AppSettings.cpp instead of redeclaring its own Q_LOGGING_CATEGORY for
`aether.perf` — this honors Principle III's consolidation (one
canonical definition site per category, per #2770) and matches the
linkage pattern established by `ax25_libmodem_shim_test`. Output is
captured via qInstallMessageHandler filtered to `aether.perf` and
matched on key=value field extraction from emitted PerfStall and
PerfSummary lines.

Blast radius: risk_score=0.418, 17 high-risk affected (top:
MainWindow::MainWindow, MainWindow::wirePanadapter, MainWindow::buildUI,
RadioModel::onStatusReceived, MainWindow::buildMenuBar). All these
reach PerfTelemetry through its existing public record* API which is
unchanged; the additions are two new public test-only methods plus one
relaxed atomic load in nowNs() that is a no-op when the override is
the default zero.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ten9876 ten9876 merged commit 0de09dc into main May 17, 2026
5 checks passed
@ten9876 ten9876 deleted the aetherclaude/issue-2500 branch May 17, 2026 02:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unit tests for PerfTelemetry

1 participant