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:
@@ -36,6 +36,11 @@ struct LiveSession {
|
||||
/// One-shot force-keyframe flag ([`force_idr_all`] → mgmt `POST /session/idr`); the encode loop
|
||||
/// drains it alongside a client's decode-recovery keyframe request.
|
||||
force_idr: Arc<AtomicBool>,
|
||||
/// Completed bring-up total (hello → first packet), ms; 0 until the first packet left. Written
|
||||
/// once by the session's [`crate::bringup::Trace`] (latency plan P0.1).
|
||||
ttff_ms: Arc<AtomicU32>,
|
||||
/// Most recent completed mid-stream resize (reconfigure → pipeline rebuilt), ms; 0 = none yet.
|
||||
last_resize_ms: Arc<AtomicU32>,
|
||||
}
|
||||
|
||||
/// A resolved read of one live session, for the `/status` view.
|
||||
@@ -46,6 +51,10 @@ pub struct SessionSnapshot {
|
||||
pub fps: u32,
|
||||
pub bitrate_kbps: u32,
|
||||
pub codec: Codec,
|
||||
/// Bring-up total (hello → first packet), ms; 0 while still bringing up (latency plan P0.1).
|
||||
pub time_to_first_frame_ms: u32,
|
||||
/// Most recent mid-stream resize total, ms; 0 = no resize this session.
|
||||
pub last_resize_ms: u32,
|
||||
}
|
||||
|
||||
fn registry() -> &'static Mutex<Vec<LiveSession>> {
|
||||
@@ -65,6 +74,8 @@ pub fn register(
|
||||
codec: Codec,
|
||||
stop: Arc<AtomicBool>,
|
||||
force_idr: Arc<AtomicBool>,
|
||||
ttff_ms: Arc<AtomicU32>,
|
||||
last_resize_ms: Arc<AtomicU32>,
|
||||
) -> LiveSessionGuard {
|
||||
let id = next_id();
|
||||
registry().lock().unwrap().push(LiveSession {
|
||||
@@ -74,6 +85,8 @@ pub fn register(
|
||||
codec,
|
||||
stop,
|
||||
force_idr,
|
||||
ttff_ms,
|
||||
last_resize_ms,
|
||||
});
|
||||
LiveSessionGuard { id }
|
||||
}
|
||||
@@ -109,6 +122,8 @@ pub fn snapshot() -> Vec<SessionSnapshot> {
|
||||
fps,
|
||||
bitrate_kbps: s.bitrate_kbps.load(Ordering::Relaxed),
|
||||
codec: s.codec,
|
||||
time_to_first_frame_ms: s.ttff_ms.load(Ordering::Relaxed),
|
||||
last_resize_ms: s.last_resize_ms.load(Ordering::Relaxed),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
||||
Reference in New Issue
Block a user