perf(latency): tier-0 attribution + tier-1 send-path levers from the latency plan
ci / web (push) Successful in 49s
ci / docs-site (push) Successful in 54s
decky / build-publish (push) Successful in 18s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 8s
apple / swift (push) Successful in 1m23s
ci / rust (push) Failing after 4m15s
arch / build-publish (push) Failing after 4m35s
deb / build-publish (push) Failing after 4m4s
docker / deploy-docs (push) Successful in 24s
ci / bench (push) Successful in 5m35s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Failing after 3m45s
windows-host / package (push) Failing after 9m8s
release / apple (push) Successful in 5m49s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Failing after 5m25s
flatpak / build-publish (push) Failing after 8m3s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m58s
android / android (push) Successful in 14m9s
apple / screenshots (push) Successful in 6m28s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 7m0s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 9m28s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 12m26s
ci / web (push) Successful in 49s
ci / docs-site (push) Successful in 54s
decky / build-publish (push) Successful in 18s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 8s
apple / swift (push) Successful in 1m23s
ci / rust (push) Failing after 4m15s
arch / build-publish (push) Failing after 4m35s
deb / build-publish (push) Failing after 4m4s
docker / deploy-docs (push) Successful in 24s
ci / bench (push) Successful in 5m35s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Failing after 3m45s
windows-host / package (push) Failing after 9m8s
release / apple (push) Successful in 5m49s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Failing after 5m25s
flatpak / build-publish (push) Failing after 8m3s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m58s
android / android (push) Successful in 14m9s
apple / screenshots (push) Successful in 6m28s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 7m0s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 9m28s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 12m26s
design/latency-reduction-2026-07.md T0.1/T0.2/T1.2/T1.3:
- T1.2 rate-capped front-loaded pacing: the paced overflow's budget is now
min(0.9x slack, overflow wire time at ~3x the live encoder bitrate)
(PUNKTFUNK_PACE_FACTOR, 0 = legacy deadline-only spread). A 300 KB-1 MB
frame's tail leaves in ~2-5 ms instead of smearing across ~15 ms at 60 fps;
GameStream schedule byte-identical (pins unchanged).
- T1.3 data-first wire order: packetize emits every block's data shards before
any parity (per-block parity pools keep all blocks' parity alive for the
second pass), so lossless completion stops waiting behind the parity tail.
EOF = last emitted packet; receiver already order-agnostic.
- T0.1 staged 0xCF: HostTiming gains an append-extensible per-stage tail
(queue/encode/pace us; seal+channel-wait derived as residual) - no cap bit
needed, old peers read the 13-byte prefix. Joined client-side into
Stats::host_{queue,encode,xfer,pace}_ms, the OSD detailed tier, and the
probe's report.
- T0.2 true on-glass present timing: VK_KHR_present_id/present_wait enabled
when supported; a PresentTimer waiter thread resolves each present id to
real visibility, replacing the submit-time display stamp (which undercounts
by up to a refresh and hides a silent-FIFO standing queue).
Validated on .21: core 185 + host 185 tests, pf-presenter 19, clippy
-D warnings across all five touched crates; loss-harness recovery curve
unchanged; C ABI harness round-trips.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -545,28 +545,63 @@ pub struct HostTiming {
|
||||
/// Host capture→sent duration, µs (saturated at `u32::MAX` ≈ 71 min — far past the 10 s
|
||||
/// client-side sanity clamp anyway).
|
||||
pub host_us: u32,
|
||||
/// Per-stage split of `host_us` (latency plan T0.1). `None` from a host that predates the
|
||||
/// extended datagram — the 0xCF wire is APPEND-extensible (decode reads the 13-byte prefix
|
||||
/// and takes the stage tail only when present), so no capability bit is needed in either
|
||||
/// direction: old client + new host reads the prefix, new client + old host gets `None`.
|
||||
pub stages: Option<HostStages>,
|
||||
}
|
||||
|
||||
/// Wire length of a [`HOST_TIMING_MAGIC`] datagram: tag + u64 pts + u32 µs = 13 bytes.
|
||||
const HOST_TIMING_LEN: usize = 1 + 8 + 4;
|
||||
/// The extended 0xCF's per-stage split of [`HostTiming::host_us`], all µs against the same
|
||||
/// capture anchor. The stages tile the host pipeline as
|
||||
/// `host_us = queue + encode + (seal/FEC + channel-wait = the residual) + pace`, so the client
|
||||
/// derives the residual as `host_us − queue_us − encode_us − pace_us` — no fifth field needed.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct HostStages {
|
||||
/// Capture delivery → encoder submit (the capture ring / channel-queue age; 0 for
|
||||
/// re-encoded hold frames, which never waited).
|
||||
pub queue_us: u32,
|
||||
/// Encoder submit → bitstream ready (scheduling wait + ASIC time).
|
||||
pub encode_us: u32,
|
||||
/// Paced send: first byte handed to the socket → last packet sent (the microburst spread).
|
||||
pub pace_us: u32,
|
||||
}
|
||||
|
||||
/// Encode a [`HostTiming`] into a [`HOST_TIMING_MAGIC`] datagram.
|
||||
/// Wire length of a legacy [`HOST_TIMING_MAGIC`] datagram: tag + u64 pts + u32 µs = 13 bytes.
|
||||
const HOST_TIMING_LEN: usize = 1 + 8 + 4;
|
||||
/// Wire length with the [`HostStages`] tail appended: + 3 × u32 = 25 bytes.
|
||||
const HOST_TIMING_STAGES_LEN: usize = HOST_TIMING_LEN + 12;
|
||||
|
||||
/// Encode a [`HostTiming`] into a [`HOST_TIMING_MAGIC`] datagram (extended form when `stages`
|
||||
/// is set — an older client parses the prefix and ignores the tail).
|
||||
pub fn encode_host_timing_datagram(t: &HostTiming) -> Vec<u8> {
|
||||
let mut b = Vec::with_capacity(HOST_TIMING_LEN);
|
||||
let mut b = Vec::with_capacity(HOST_TIMING_STAGES_LEN);
|
||||
b.push(HOST_TIMING_MAGIC);
|
||||
b.extend_from_slice(&t.pts_ns.to_le_bytes());
|
||||
b.extend_from_slice(&t.host_us.to_le_bytes());
|
||||
if let Some(s) = &t.stages {
|
||||
b.extend_from_slice(&s.queue_us.to_le_bytes());
|
||||
b.extend_from_slice(&s.encode_us.to_le_bytes());
|
||||
b.extend_from_slice(&s.pace_us.to_le_bytes());
|
||||
}
|
||||
b
|
||||
}
|
||||
|
||||
/// Parse a [`HOST_TIMING_MAGIC`] datagram → [`HostTiming`]. `None` on bad tag or a short buffer
|
||||
/// (the fixed length bounds every read before it happens).
|
||||
/// (the fixed lengths bound every read before it happens). A datagram carrying only the 13-byte
|
||||
/// prefix (an older host) yields `stages: None`.
|
||||
pub fn decode_host_timing_datagram(b: &[u8]) -> Option<HostTiming> {
|
||||
if b.len() < HOST_TIMING_LEN || b[0] != HOST_TIMING_MAGIC {
|
||||
return None;
|
||||
}
|
||||
let stages = (b.len() >= HOST_TIMING_STAGES_LEN).then(|| HostStages {
|
||||
queue_us: u32::from_le_bytes(b[13..17].try_into().unwrap()),
|
||||
encode_us: u32::from_le_bytes(b[17..21].try_into().unwrap()),
|
||||
pace_us: u32::from_le_bytes(b[21..25].try_into().unwrap()),
|
||||
});
|
||||
Some(HostTiming {
|
||||
pts_ns: u64::from_le_bytes(b[1..9].try_into().unwrap()),
|
||||
host_us: u32::from_le_bytes(b[9..13].try_into().unwrap()),
|
||||
stages,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -266,6 +266,7 @@ fn host_timing_datagram_roundtrip_and_truncation() {
|
||||
let t = HostTiming {
|
||||
pts_ns: 1_751_500_000_123_456_789, // a realistic 2026 CLOCK_REALTIME capture stamp
|
||||
host_us: 4_321,
|
||||
stages: None,
|
||||
};
|
||||
let d = encode_host_timing_datagram(&t);
|
||||
assert_eq!(d[0], HOST_TIMING_MAGIC);
|
||||
@@ -278,6 +279,33 @@ fn host_timing_datagram_roundtrip_and_truncation() {
|
||||
let mut bad = d.clone();
|
||||
bad[0] = HDR_META_MAGIC;
|
||||
assert_eq!(decode_host_timing_datagram(&bad), None);
|
||||
|
||||
// Extended form (T0.1): the stage tail roundtrips; a truncated tail (an old host's 13-byte
|
||||
// datagram, or anything short of the full 25) degrades to `stages: None`, never a partial
|
||||
// read; the prefix fields stay identical in both forms (the append-extensibility contract).
|
||||
let ts = HostTiming {
|
||||
stages: Some(HostStages {
|
||||
queue_us: 900,
|
||||
encode_us: 3_100,
|
||||
pace_us: 2_500,
|
||||
}),
|
||||
..t
|
||||
};
|
||||
let ds = encode_host_timing_datagram(&ts);
|
||||
assert_eq!(ds.len(), 25);
|
||||
assert_eq!(
|
||||
&ds[..13],
|
||||
&d[..13],
|
||||
"prefix is byte-identical to the legacy form"
|
||||
);
|
||||
assert_eq!(decode_host_timing_datagram(&ds), Some(ts));
|
||||
for n in 13..ds.len() {
|
||||
assert_eq!(
|
||||
decode_host_timing_datagram(&ds[..n]),
|
||||
Some(t),
|
||||
"partial stage tail ({n} B) must degrade to the legacy decode"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user