diff --git a/docs/TODO_ux.md b/docs/TODO_ux.md index dbdb7cc041..4d7536d9af 100644 --- a/docs/TODO_ux.md +++ b/docs/TODO_ux.md @@ -2,9 +2,8 @@ ## Performance +- disable time travel recording by default - cache draw stuff -- lazy SimStats - - dont consider it when comparing or serializing ## Quick n easy diff --git a/editor/src/plugins/sim/diff_all.rs b/editor/src/plugins/sim/diff_all.rs index 1a2814de16..f72505461f 100644 --- a/editor/src/plugins/sim/diff_all.rs +++ b/editor/src/plugins/sim/diff_all.rs @@ -3,7 +3,7 @@ use crate::plugins::{Plugin, PluginCtx}; use ezgui::GfxCtx; use geom::Line; use map_model::LANE_THICKNESS; -use sim::{Sim, Tick}; +use sim::Tick; pub struct DiffAllState { time: Tick, @@ -16,10 +16,7 @@ impl DiffAllState { pub fn new(ctx: &mut PluginCtx) -> Option { if ctx.primary.current_selection.is_none() && ctx.input.action_chosen("diff all A/B trips") { - return Some(diff_all( - &ctx.primary.sim, - ctx.secondary.as_ref().map(|(s, _)| &s.sim).unwrap(), - )); + return Some(diff_all(ctx)); } None } @@ -28,10 +25,7 @@ impl DiffAllState { impl Plugin for DiffAllState { fn blocking_event(&mut self, ctx: &mut PluginCtx) -> bool { if self.time != ctx.primary.sim.time { - *self = diff_all( - &ctx.primary.sim, - ctx.secondary.as_ref().map(|(s, _)| &s.sim).unwrap(), - ); + *self = diff_all(ctx); } ctx.input.set_mode_with_prompt( @@ -56,9 +50,13 @@ impl Plugin for DiffAllState { } } -fn diff_all(primary_sim: &Sim, secondary_sim: &Sim) -> DiffAllState { - let stats1 = primary_sim.get_stats(); - let stats2 = secondary_sim.get_stats(); +fn diff_all(ctx: &mut PluginCtx) -> DiffAllState { + let stats1 = ctx.primary.sim.get_stats(&ctx.primary.map); + let stats2 = ctx + .secondary + .as_mut() + .map(|(s, _)| s.sim.get_stats(&s.map)) + .unwrap(); let mut same_trips = 0; let mut lines: Vec = Vec::new(); for (trip, pt1) in &stats1.canonical_pt_per_trip { @@ -71,7 +69,7 @@ fn diff_all(primary_sim: &Sim, secondary_sim: &Sim) -> DiffAllState { } } DiffAllState { - time: primary_sim.time, + time: ctx.primary.sim.time, same_trips, lines, } diff --git a/editor/src/plugins/view/show_activity.rs b/editor/src/plugins/view/show_activity.rs index 35bccb9ef0..0665c718f1 100644 --- a/editor/src/plugins/view/show_activity.rs +++ b/editor/src/plugins/view/show_activity.rs @@ -2,7 +2,7 @@ use crate::objects::Ctx; use crate::plugins::{Plugin, PluginCtx}; use ezgui::{Color, GfxCtx}; use geom::{Bounds, Polygon, Pt2D}; -use sim::{Sim, Tick}; +use sim::Tick; pub enum ShowActivityState { Inactive, @@ -20,10 +20,8 @@ impl Plugin for ShowActivityState { match self { ShowActivityState::Inactive => { if ctx.input.action_chosen("show lanes with active traffic") { - *self = ShowActivityState::Active( - ctx.primary.sim.time, - active_agent_heatmap(ctx.canvas.get_screen_bounds(), &ctx.primary.sim), - ); + *self = + ShowActivityState::Active(ctx.primary.sim.time, active_agent_heatmap(ctx)); } } ShowActivityState::Active(time, ref old_heatmap) => { @@ -34,10 +32,8 @@ impl Plugin for ShowActivityState { } let bounds = ctx.canvas.get_screen_bounds(); if *time != ctx.primary.sim.time || bounds != old_heatmap.bounds { - *self = ShowActivityState::Active( - ctx.primary.sim.time, - active_agent_heatmap(bounds, &ctx.primary.sim), - ); + *self = + ShowActivityState::Active(ctx.primary.sim.time, active_agent_heatmap(ctx)); } } } @@ -114,9 +110,9 @@ impl Heatmap { } } -fn active_agent_heatmap(bounds: Bounds, sim: &Sim) -> Heatmap { - let mut h = Heatmap::new(bounds); - let stats = sim.get_stats(); +fn active_agent_heatmap(ctx: &mut PluginCtx) -> Heatmap { + let mut h = Heatmap::new(ctx.canvas.get_screen_bounds()); + let stats = ctx.primary.sim.get_stats(&ctx.primary.map); for pt in stats.canonical_pt_per_trip.values() { h.add(*pt); } diff --git a/editor/src/plugins/view/show_route.rs b/editor/src/plugins/view/show_route.rs index 3481b6d06b..0b483ebd63 100644 --- a/editor/src/plugins/view/show_route.rs +++ b/editor/src/plugins/view/show_route.rs @@ -98,14 +98,21 @@ fn show_route(trip: TripID, ctx: &mut PluginCtx) -> ShowRouteState { } fn debug_all_routes(ctx: &mut PluginCtx) -> ShowRouteState { - let sim = &ctx.primary.sim; let mut traces: Vec = Vec::new(); - for trip in sim.get_stats().canonical_pt_per_trip.keys() { - if let Some(agent) = sim.trip_to_agent(*trip) { - if let Some(trace) = sim.trace_route(agent, &ctx.primary.map, None) { + let trips: Vec = ctx + .primary + .sim + .get_stats(&ctx.primary.map) + .canonical_pt_per_trip + .keys() + .cloned() + .collect(); + for trip in trips { + if let Some(agent) = ctx.primary.sim.trip_to_agent(trip) { + if let Some(trace) = ctx.primary.sim.trace_route(agent, &ctx.primary.map, None) { traces.push(trace); } } } - ShowRouteState::DebugAllRoutes(sim.time, traces) + ShowRouteState::DebugAllRoutes(ctx.primary.sim.time, traces) } diff --git a/map_model/src/make/initial/merge.rs b/map_model/src/make/initial/merge.rs index be898d80fd..3455519caa 100644 --- a/map_model/src/make/initial/merge.rs +++ b/map_model/src/make/initial/merge.rs @@ -23,7 +23,7 @@ pub fn short_roads(map: &mut InitialMap) { merge(map, StableRoadID(22)); } - if true { + if false { let mut look_at: HashSet = HashSet::new(); let orig_count = map.roads.len(); diff --git a/sim/src/driving.rs b/sim/src/driving.rs index 77a62bc857..84bc78669a 100644 --- a/sim/src/driving.rs +++ b/sim/src/driving.rs @@ -890,7 +890,8 @@ impl DrivingSimState { pub fn get_all_draw_cars(&self, time: Tick, map: &Map) -> Vec { self.cars .keys() - .map(|id| self.get_draw_car(*id, time, map).unwrap()) + // Might not succeed, since we can have "invisible" cars at borders + .filter_map(|id| self.get_draw_car(*id, time, map)) .collect() } diff --git a/sim/src/sim.rs b/sim/src/sim.rs index 6bf5b96c7c..8b9f6c331e 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -38,7 +38,10 @@ pub struct Sim { // TODO not quite the right type to represent durations savestate_every: Option, - stats: SimStats, + // Lazily computed. + #[derivative(PartialEq = "ignore")] + #[serde(skip_serializing, skip_deserializing)] + stats: Option, pub(crate) spawner: Spawner, scheduler: Scheduler, @@ -83,7 +86,7 @@ impl Sim { run_name, savestate_every, current_agent_for_debugging: None, - stats: SimStats::new(Tick::zero()), + stats: None, } } @@ -244,8 +247,7 @@ impl Sim { // then. self.time = self.time.next(); - // Collect stats for consumers to quickly... well, consume - self.collect_stats(map); + self.stats = None; // Savestate? Do this AFTER incrementing the timestep. Otherwise we could repeatedly load a // savestate, run a step, and invalidly save over it. @@ -393,8 +395,22 @@ impl Sim { self.intersection_state.is_in_overtime(id) } - pub fn get_stats(&self) -> &SimStats { - &self.stats + pub fn get_stats(&mut self, map: &Map) -> &SimStats { + if self.stats.is_some() { + return self.stats.as_ref().unwrap(); + } + + let mut stats = SimStats::new(self.time); + for trip in self.trips_state.get_active_trips().into_iter() { + if let Some(agent) = self.trips_state.trip_to_agent(trip) { + if let Some(pt) = self.canonical_pt_for_agent(agent, map) { + stats.canonical_pt_per_trip.insert(trip, pt); + } + } + } + + self.stats = Some(stats); + self.stats.as_ref().unwrap() } pub fn get_canonical_pt_per_trip(&self, trip: TripID, map: &Map) -> Option { @@ -403,17 +419,6 @@ impl Sim { .and_then(|id| self.canonical_pt_for_agent(id, map)) } - fn collect_stats(&mut self, map: &Map) { - self.stats = SimStats::new(self.time); - for trip in self.trips_state.get_active_trips().into_iter() { - if let Some(agent) = self.trips_state.trip_to_agent(trip) { - if let Some(pt) = self.canonical_pt_for_agent(agent, map) { - self.stats.canonical_pt_per_trip.insert(trip, pt); - } - } - } - } - fn canonical_pt_for_agent(&self, id: AgentID, map: &Map) -> Option { match id { AgentID::Car(id) => self