lazily compute SimStats

This commit is contained in:
Dustin Carlino 2019-02-01 13:47:07 -08:00
parent 58c4cb5e1b
commit 3451b65823
7 changed files with 57 additions and 51 deletions

View File

@ -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

View File

@ -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<DiffAllState> {
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<Line> = 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,
}

View File

@ -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);
}

View File

@ -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<Trace> = 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<TripID> = 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)
}

View File

@ -23,7 +23,7 @@ pub fn short_roads(map: &mut InitialMap) {
merge(map, StableRoadID(22));
}
if true {
if false {
let mut look_at: HashSet<StableIntersectionID> = HashSet::new();
let orig_count = map.roads.len();

View File

@ -890,7 +890,8 @@ impl DrivingSimState {
pub fn get_all_draw_cars(&self, time: Tick, map: &Map) -> Vec<DrawCarInput> {
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()
}

View File

@ -38,7 +38,10 @@ pub struct Sim {
// TODO not quite the right type to represent durations
savestate_every: Option<Tick>,
stats: SimStats,
// Lazily computed.
#[derivative(PartialEq = "ignore")]
#[serde(skip_serializing, skip_deserializing)]
stats: Option<SimStats>,
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<Pt2D> {
@ -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<Pt2D> {
match id {
AgentID::Car(id) => self