diff --git a/sim/src/bin/run_scenario.rs b/sim/src/bin/run_scenario.rs index 1314254fbc..e7b27c6c6d 100644 --- a/sim/src/bin/run_scenario.rs +++ b/sim/src/bin/run_scenario.rs @@ -41,8 +41,9 @@ fn main() { return; } } - println!("Interrupting at {}", sim.time()); + println!("\n\nInterrupting at {}", sim.time()); sim.save(); + println!("{}", sim.describe_scheduler_stats()); } else { sim.timed_step( &mut map, diff --git a/sim/src/scheduler.rs b/sim/src/scheduler.rs index 1cdb87f6d3..2cadd07626 100644 --- a/sim/src/scheduler.rs +++ b/sim/src/scheduler.rs @@ -4,6 +4,7 @@ use std::collections::{BinaryHeap, HashMap}; use serde::{Deserialize, Serialize}; +use abstutil::Counter; use geom::{Duration, Histogram, Time}; use map_model::{BusRouteID, IntersectionID, Path, PathRequest}; @@ -53,6 +54,22 @@ impl Command { Command::StartBus(r, t) => CommandType::StartBus(*r, *t), } } + + fn to_simple_type(&self) -> SimpleCommandType { + match self { + Command::SpawnCar(_, _) => SimpleCommandType::Car, + Command::SpawnPed(_) => SimpleCommandType::Ped, + Command::StartTrip(_, _, _, _) => SimpleCommandType::StartTrip, + Command::UpdateCar(_) => SimpleCommandType::Car, + Command::UpdateLaggyHead(_) => SimpleCommandType::CarLaggyHead, + Command::UpdatePed(_) => SimpleCommandType::Ped, + Command::UpdateIntersection(_) => SimpleCommandType::Intersection, + Command::Callback(_) => SimpleCommandType::Callback, + Command::Pandemic(_) => SimpleCommandType::Pandemic, + Command::FinishRemoteTrip(_) => SimpleCommandType::FinishRemoteTrip, + Command::StartBus(_, _) => SimpleCommandType::StartBus, + } + } } /// A smaller version of Command that satisfies many more properties. Only one Command per @@ -70,6 +87,20 @@ enum CommandType { StartBus(BusRouteID, Time), } +/// A more compressed form of CommandType, just used for keeping stats on event processing. +#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Debug)] +enum SimpleCommandType { + StartTrip, + Car, + CarLaggyHead, + Ped, + Intersection, + Callback, + Pandemic, + FinishRemoteTrip, + StartBus, +} + #[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] struct Item { time: Time, @@ -106,6 +137,8 @@ pub struct Scheduler { last_time: Time, #[serde(skip_serializing, skip_deserializing)] delta_times: Histogram, + #[serde(skip_serializing, skip_deserializing)] + cmd_type_counts: Counter, } impl Scheduler { @@ -116,6 +149,7 @@ impl Scheduler { latest_time: Time::START_OF_DAY, last_time: Time::START_OF_DAY, delta_times: Histogram::new(), + cmd_type_counts: Counter::new(), } } @@ -128,6 +162,7 @@ impl Scheduler { } self.last_time = self.last_time.max(time); self.delta_times.add(time - self.latest_time); + self.cmd_type_counts.inc(cmd.to_simple_type()); let cmd_type = cmd.to_type(); @@ -209,7 +244,14 @@ impl Scheduler { } pub fn describe_stats(&self) -> String { - format!("delta times for events: {}", self.delta_times.describe()) + let mut stats = vec![ + format!("delta times for events: {}", self.delta_times.describe()), + "count for each command type:".to_string(), + ]; + for (cmd, cnt) in self.cmd_type_counts.borrow() { + stats.push(format!("{:?}: {}", cmd, abstutil::prettyprint_usize(*cnt))); + } + stats.join("\n") } /// It's much more efficient to save without the paths, and to recalculate them when loading diff --git a/sim/src/sim/queries.rs b/sim/src/sim/queries.rs index 6442078e69..bf4b4efe00 100644 --- a/sim/src/sim/queries.rs +++ b/sim/src/sim/queries.rs @@ -389,6 +389,10 @@ impl Sim { self.driving.all_waiting_people(self.time, &mut delays); delays } + + pub fn describe_scheduler_stats(&self) -> String { + self.scheduler.describe_stats() + } } // Drawing