feat(clients): host/network split in every stats HUD (stats phase 2, client side)
Consumes the 0xCF host-timing plane (449a67c) on all four GUI clients: each
keeps a bounded pending ring of receipt samples keyed by pts, matches the
host's per-AU capture→sent reports against it, and the HUD equation becomes
= host 3.1 + network 6.7 + decode 2.1 + display 2.3
falling back to the combined `= host+network …` term whenever no timing
matched the window (old host / datagram loss) — same total, one split
fewer, never a misleading zero. Apple additionally gains the split as the
only equation line under the stage-1 fallback presenter (receipt is
presenter-independent), a `nextHostTiming` wrapper with its own plane lock,
and a unit-tested `HostNetworkSplitter`; Android extends the JNI stats
array 16→18 doubles (0–15 unchanged); Windows/Linux thread the split
through `Stats` into the HUD and the headless/debug logs.
Docs updated: design/stats-unification.md Phase 2 → implemented (wire
format, fallback semantics), and the docs-site matrix's Sunshine "Host
processing latency" row is now a direct match (ours includes the paced
send; avg vs p50).
Verified here: linux client clippy -D warnings green on the live tree,
windows stub check + hand-verified diff, android cargo-ndk arm64 check
green, apple loopback test extended (needs the rebuilt xcframework + swift
test on the mac). On-glass: pending on all platforms.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -68,10 +68,28 @@ impl StreamPage {
|
||||
if self.hdr.get() {
|
||||
line1.push_str(" · HDR");
|
||||
}
|
||||
// The equation line: split `host+network` into `host + network` when the host
|
||||
// reported per-AU timings (0xCF, stats Phase 2); the combined stage otherwise.
|
||||
let equation = if s.split {
|
||||
format!(
|
||||
"= host {:.1} + network {:.1} + decode {:.1} + display {:.1}",
|
||||
s.host_ms,
|
||||
s.net_ms,
|
||||
s.decode_ms,
|
||||
self.presented.display_ms.get(),
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"= host+network {:.1} + decode {:.1} + display {:.1}",
|
||||
s.host_net_ms,
|
||||
s.decode_ms,
|
||||
self.presented.display_ms.get(),
|
||||
)
|
||||
};
|
||||
let mut text = format!(
|
||||
"{line1}\n\
|
||||
end-to-end {:.1} ms p50 · {:.1} p95 · capture→displayed{}\n\
|
||||
= host+network {:.1} + decode {:.1} + display {:.1}",
|
||||
{equation}",
|
||||
self.presented.e2e_p50_ms.get(),
|
||||
self.presented.e2e_p95_ms.get(),
|
||||
if self.same_host {
|
||||
@@ -79,9 +97,6 @@ impl StreamPage {
|
||||
} else {
|
||||
""
|
||||
},
|
||||
s.host_net_ms,
|
||||
s.decode_ms,
|
||||
self.presented.display_ms.get(),
|
||||
);
|
||||
// Counters — only rendered when nonzero this window.
|
||||
if s.lost > 0 {
|
||||
|
||||
Reference in New Issue
Block a user