mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
lazily compute SimStats
This commit is contained in:
parent
58c4cb5e1b
commit
3451b65823
@ -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
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user