Gate readiness on stable viewport frames
This commit is contained in:
@@ -343,6 +343,7 @@ async fn run_live(
|
|||||||
{
|
{
|
||||||
live.vision.set_generation(status.generation);
|
live.vision.set_generation(status.generation);
|
||||||
record_session_observation(&live.observability, &event);
|
record_session_observation(&live.observability, &event);
|
||||||
|
print_ready(&live, status.generation);
|
||||||
return Ok::<(), CliError>(());
|
return Ok::<(), CliError>(());
|
||||||
}
|
}
|
||||||
Some(
|
Some(
|
||||||
@@ -529,32 +530,7 @@ async fn run_live(
|
|||||||
status.agent_ready,
|
status.agent_ready,
|
||||||
);
|
);
|
||||||
if status.agent_ready {
|
if status.agent_ready {
|
||||||
let world = live
|
print_ready(&live, status.generation);
|
||||||
.world_loop
|
|
||||||
.as_ref()
|
|
||||||
.and_then(metacrate_game_loop::LoopHandle::latest_world);
|
|
||||||
let world_sequence = world.as_ref().map_or(0, |world| world.sequence);
|
|
||||||
let primitives = world
|
|
||||||
.as_ref()
|
|
||||||
.map_or(0, |world| world.value.primitives.len());
|
|
||||||
let avatars = world.as_ref().map_or(0, |world| world.value.avatars.len());
|
|
||||||
let dropped_world_events = live
|
|
||||||
.world_loop
|
|
||||||
.as_ref()
|
|
||||||
.map_or(0, metacrate_game_loop::LoopHandle::dropped_world_events);
|
|
||||||
let frames = live
|
|
||||||
.vision
|
|
||||||
.viewport_stats()
|
|
||||||
.map_or(0, |stats| stats.completed_frames);
|
|
||||||
println!(
|
|
||||||
"READY generation={} world_sequence={} world_primitives={} world_avatars={} dropped_world_events={} viewport_frames={} viewport_target_fps=10",
|
|
||||||
status.generation,
|
|
||||||
world_sequence,
|
|
||||||
primitives,
|
|
||||||
avatars,
|
|
||||||
dropped_world_events,
|
|
||||||
frames
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -689,13 +665,20 @@ async fn prepare_live_framework(
|
|||||||
generation,
|
generation,
|
||||||
libremetaverse_types::compat::CancellationToken::default(),
|
libremetaverse_types::compat::CancellationToken::default(),
|
||||||
);
|
);
|
||||||
|
let mut stable_after_frame = 0;
|
||||||
|
let mut observed_missed_deadlines = 0;
|
||||||
loop {
|
loop {
|
||||||
if live
|
if let Some(stats) = live.vision.viewport_stats() {
|
||||||
.vision
|
if stats.missed_frame_deadlines != observed_missed_deadlines {
|
||||||
.viewport_stats()
|
observed_missed_deadlines = stats.missed_frame_deadlines;
|
||||||
.is_some_and(|stats| stats.completed_frames >= 2 && stats.render_errors == 0)
|
stable_after_frame = stats.completed_frames;
|
||||||
{
|
}
|
||||||
return;
|
if stats.completed_frames.saturating_sub(stable_after_frame) >= 2
|
||||||
|
&& stats.render_errors == 0
|
||||||
|
&& stats.last_render <= metacrate_game_loop::DEFAULT_VIEWPORT_FRAME_INTERVAL
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tokio::time::sleep(Duration::from_millis(20)).await;
|
tokio::time::sleep(Duration::from_millis(20)).await;
|
||||||
}
|
}
|
||||||
@@ -705,7 +688,7 @@ async fn prepare_live_framework(
|
|||||||
readiness.mark_ready(generation);
|
readiness.mark_ready(generation);
|
||||||
let stats = live.vision.viewport_stats().unwrap_or_default();
|
let stats = live.vision.viewport_stats().unwrap_or_default();
|
||||||
println!(
|
println!(
|
||||||
"INITIALIZED generation={} viewport_frames={} last_render_ms={} missed_deadlines={} world_state=stable",
|
"INITIALIZED generation={} viewport_frames={} last_render_ms={} warmup_missed_deadlines={} world_state=stable viewport_state=stable",
|
||||||
generation,
|
generation,
|
||||||
stats.completed_frames,
|
stats.completed_frames,
|
||||||
stats.last_render.as_millis(),
|
stats.last_render.as_millis(),
|
||||||
@@ -714,6 +697,30 @@ async fn prepare_live_framework(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "live-grid")]
|
||||||
|
fn print_ready(live: &LiveInteractions, generation: u64) {
|
||||||
|
let world = live
|
||||||
|
.world_loop
|
||||||
|
.as_ref()
|
||||||
|
.and_then(metacrate_game_loop::LoopHandle::latest_world);
|
||||||
|
let world_sequence = world.as_ref().map_or(0, |world| world.sequence);
|
||||||
|
let primitives = world
|
||||||
|
.as_ref()
|
||||||
|
.map_or(0, |world| world.value.primitives.len());
|
||||||
|
let avatars = world.as_ref().map_or(0, |world| world.value.avatars.len());
|
||||||
|
let dropped_world_events = live
|
||||||
|
.world_loop
|
||||||
|
.as_ref()
|
||||||
|
.map_or(0, metacrate_game_loop::LoopHandle::dropped_world_events);
|
||||||
|
let frames = live
|
||||||
|
.vision
|
||||||
|
.viewport_stats()
|
||||||
|
.map_or(0, |stats| stats.completed_frames);
|
||||||
|
println!(
|
||||||
|
"READY generation={generation} world_sequence={world_sequence} world_primitives={primitives} world_avatars={avatars} dropped_world_events={dropped_world_events} viewport_frames={frames} viewport_target_fps=10"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "live-grid")]
|
#[cfg(feature = "live-grid")]
|
||||||
struct LiveInteractions {
|
struct LiveInteractions {
|
||||||
interaction: metacrate_grid_agent::InteractionHandle,
|
interaction: metacrate_grid_agent::InteractionHandle,
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ INITIALIZING generation=N waiting_for=world_state,viewport target_fps=10
|
|||||||
|
|
||||||
The framework gate opens only after the region-scoped world state exists, the
|
The framework gate opens only after the region-scoped world state exists, the
|
||||||
first scene/assets have converged, and at least two complete viewport frames
|
first scene/assets have converged, and at least two complete viewport frames
|
||||||
have been published without render errors. The terminal then emits
|
have been published after the last missed deadline, within the frame budget,
|
||||||
|
and without render errors. One-time warm-up misses are reported separately and
|
||||||
|
do not contaminate the post-`READY` stability window. The terminal then emits
|
||||||
`INITIALIZED ...` followed by one unambiguous `READY ...` line when the session
|
`INITIALIZED ...` followed by one unambiguous `READY ...` line when the session
|
||||||
and agent services are released. The default readiness allowance is two
|
and agent services are released. The default readiness allowance is two
|
||||||
minutes; the measured scene convergence window was about 30.05 seconds.
|
minutes; the measured scene convergence window was about 30.05 seconds.
|
||||||
|
|||||||
Reference in New Issue
Block a user