perf(host): session-transition trace + Welcome-time display prep (native path)
Latency plan P0.1 + P1.1/P1.2 (design/first-frame-and-resize-latency.md): P0.1 — every native session runs a bringup::Trace (hello -> welcome -> start -> punch_done -> display_acquired -> capture_attached -> first_frame -> encoder_open -> first_au -> first_packet), one summary info! line when the first video packet leaves; each accepted resize runs its own trace (reconfigure -> pipeline_rebuilt). Totals surface per session as time_to_first_frame_ms / last_resize_ms in session_status -> mgmt /status, so every subsequent latency change is measured, not vibed. (The Windows manager logs its own activation/settle deltas — correlate by wall clock.) P1.1/P1.2 — on the Windows native path the display bring-up no longer serializes behind the Start round-trip and the up-to-2.5 s hole-punch wait: a prep thread kicks off at Welcome (mode is final there) and runs monitor create -> activation -> verified settle -> capture attach -> first frame -> encoder open while the network waits are in flight; the data plane hands it the post-punch SessionContext and it becomes the stream thread on a warm pipeline. Abort between Welcome and Start drops the hand-off channel and the prep result releases into the keep-alive machinery (stop/quit + watcher are created pre-handshake so a vanished client also aborts the build retries). Same slot-scoped begin_idd_setup serialization as the inline path. Linux keeps the inline bring-up (launch semantics bind before create); GameStream untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -391,6 +391,12 @@ struct StreamInfo {
|
||||
/// Client's parity floor per FEC block (`minRequiredFecPackets`).
|
||||
min_fec: u8,
|
||||
codec: ApiCodec,
|
||||
/// Session bring-up total, hello → first video packet, in ms (native sessions; `null` on the
|
||||
/// GameStream plane or while the session is still bringing up).
|
||||
time_to_first_frame_ms: Option<u32>,
|
||||
/// Most recent mid-stream resize total, reconfigure → pipeline rebuilt, in ms (native sessions;
|
||||
/// `null` when no resize happened / GameStream).
|
||||
last_resize_ms: Option<u32>,
|
||||
}
|
||||
|
||||
/// Non-sensitive host status for the local tray icon: counts and booleans only — no PIN values,
|
||||
@@ -1480,6 +1486,9 @@ async fn get_status(State(st): State<Arc<MgmtState>>) -> Json<RuntimeStatus> {
|
||||
packet_size: c.packet_size as u32,
|
||||
min_fec: c.min_fec,
|
||||
codec: c.codec.into(),
|
||||
// Transition latencies are traced on the native plane only (latency plan P0.1).
|
||||
time_to_first_frame_ms: None,
|
||||
last_resize_ms: None,
|
||||
})
|
||||
.or_else(|| {
|
||||
native.first().map(|s| StreamInfo {
|
||||
@@ -1492,6 +1501,9 @@ async fn get_status(State(st): State<Arc<MgmtState>>) -> Json<RuntimeStatus> {
|
||||
packet_size: 0,
|
||||
min_fec: 0,
|
||||
codec: s.codec.into(),
|
||||
time_to_first_frame_ms: (s.time_to_first_frame_ms > 0)
|
||||
.then_some(s.time_to_first_frame_ms),
|
||||
last_resize_ms: (s.last_resize_ms > 0).then_some(s.last_resize_ms),
|
||||
})
|
||||
});
|
||||
Json(RuntimeStatus {
|
||||
|
||||
Reference in New Issue
Block a user