Entering edit mode is slow on large maps, because clearing the simulation recreates parking state for every building. Parallelize it to speed it up at least a bit.

This commit is contained in:
Dustin Carlino 2021-07-02 11:47:05 -07:00
parent 866ecd5f88
commit 4fd86c8a41
3 changed files with 47 additions and 22 deletions

View File

@ -100,7 +100,10 @@ impl EditMode {
app.primary
.sim
.handle_live_edited_traffic_signals(&app.primary.map);
let (trips, parked_cars) = app.primary.sim.handle_live_edits(&app.primary.map);
let (trips, parked_cars) = app
.primary
.sim
.handle_live_edits(&app.primary.map, &mut timer);
if trips == 0 && parked_cars == 0 {
Transition::Pop
} else {

View File

@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
use abstutil::{
deserialize_btreemap, deserialize_multimap, serialize_btreemap, serialize_multimap, MultiMap,
Timer,
};
use geom::{Distance, PolyLine, Pt2D};
use map_model::{
@ -24,7 +25,7 @@ use crate::{CarID, CarStatus, DrawCarInput, Event, ParkedCar, ParkingSpot, Perso
pub trait ParkingSim {
/// Returns any cars that got very abruptly evicted from existence, and also cars actively
/// moving into a deleted spot.
fn handle_live_edits(&mut self, map: &Map) -> (Vec<ParkedCar>, Vec<CarID>);
fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> (Vec<ParkedCar>, Vec<CarID>);
fn get_free_onstreet_spots(&self, l: LaneID) -> Vec<ParkingSpot>;
fn get_free_offstreet_spots(&self, b: BuildingID) -> Vec<ParkingSpot>;
fn get_free_lot_spots(&self, pl: ParkingLotID) -> Vec<ParkingSpot>;
@ -86,11 +87,11 @@ pub enum ParkingSimState {
impl ParkingSimState {
/// Counterintuitive: any spots located in blackholes are just not represented here. If somebody
/// tries to drive from a blackholed spot, they couldn't reach most places.
pub fn new(map: &Map, infinite: bool) -> ParkingSimState {
pub fn new(map: &Map, infinite: bool, timer: &mut Timer) -> ParkingSimState {
if infinite {
ParkingSimState::Infinite(InfiniteParkingSimState::new(map))
} else {
ParkingSimState::Normal(NormalParkingSimState::new(map))
ParkingSimState::Normal(NormalParkingSimState::new(map, timer))
}
}
@ -150,7 +151,7 @@ pub struct NormalParkingSimState {
}
impl NormalParkingSimState {
fn new(map: &Map) -> NormalParkingSimState {
fn new(map: &Map, timer: &mut Timer) -> NormalParkingSimState {
let mut sim = NormalParkingSimState {
parked_cars: BTreeMap::new(),
occupants: BTreeMap::new(),
@ -171,18 +172,36 @@ impl NormalParkingSimState {
sim.onstreet_lanes.insert(lane.parking_lane, lane);
}
}
for b in map.all_buildings() {
if let Some((pos, _)) = b.driving_connection(map) {
if !map.get_l(pos.lane()).driving_blackhole {
let num_spots = b.num_parking_spots();
if num_spots > 0 {
sim.num_spots_per_offstreet.insert(b.id, num_spots);
sim.driving_to_offstreet
.insert(pos.lane(), (b.id, pos.dist_along()));
// This is slow on huge maps
for (b, pos, num_spots) in timer
.parallelize(
"setup offstreet parking",
map.all_buildings().iter().collect(),
|b| {
if let Some((pos, _)) = b.driving_connection(map) {
if !map.get_l(pos.lane()).driving_blackhole {
let num_spots = b.num_parking_spots();
if num_spots > 0 {
Some((b.id, pos, num_spots))
} else {
None
}
} else {
None
}
} else {
None
}
}
}
},
)
.into_iter()
.flatten()
{
sim.num_spots_per_offstreet.insert(b, num_spots);
sim.driving_to_offstreet
.insert(pos.lane(), (b, pos.dist_along()));
}
for pl in map.all_parking_lots() {
if !map.get_l(pl.driving_pos.lane()).driving_blackhole {
sim.num_spots_per_lot.insert(pl.id, pl.capacity());
@ -195,9 +214,9 @@ impl NormalParkingSimState {
}
impl ParkingSim for NormalParkingSimState {
fn handle_live_edits(&mut self, map: &Map) -> (Vec<ParkedCar>, Vec<CarID>) {
fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> (Vec<ParkedCar>, Vec<CarID>) {
let (filled_before, _) = self.get_all_parking_spots();
let new = NormalParkingSimState::new(map);
let new = NormalParkingSimState::new(map, timer);
let (_, avail_after) = new.get_all_parking_spots();
let avail_after: BTreeSet<ParkingSpot> = avail_after.into_iter().collect();
@ -814,7 +833,7 @@ impl InfiniteParkingSimState {
}
impl ParkingSim for InfiniteParkingSimState {
fn handle_live_edits(&mut self, map: &Map) -> (Vec<ParkedCar>, Vec<CarID>) {
fn handle_live_edits(&mut self, map: &Map, _: &mut Timer) -> (Vec<ParkedCar>, Vec<CarID>) {
// Can live edits possibly affect anything?
let new = InfiniteParkingSimState::new(map);
self.driving_to_offstreet = new.driving_to_offstreet;

View File

@ -202,10 +202,11 @@ impl SimOptions {
// Setup
impl Sim {
pub fn new(map: &Map, opts: SimOptions) -> Sim {
let mut timer = Timer::new("create blank sim");
let mut scheduler = Scheduler::new();
Sim {
driving: DrivingSimState::new(map, &opts),
parking: ParkingSimState::new(map, opts.infinite_parking),
parking: ParkingSimState::new(map, opts.infinite_parking, &mut timer),
walking: WalkingSimState::new(),
intersections: IntersectionSimState::new(map, &mut scheduler, &opts),
transit: TransitSimState::new(map),
@ -841,10 +842,10 @@ impl Sim {
/// Respond to arbitrary map edits without resetting the simulation. Returns the number of
/// (trips cancelled, parked cars displaced).
pub fn handle_live_edits(&mut self, map: &Map) -> (usize, usize) {
pub fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> (usize, usize) {
self.edits_name = map.get_edits().edits_name.clone();
let (affected, num_parked_cars) = self.find_trips_affected_by_live_edits(map);
let (affected, num_parked_cars) = self.find_trips_affected_by_live_edits(map, timer);
let num_trips_cancelled = affected.len();
let affected_agents: BTreeSet<AgentID> = affected.iter().map(|(a, _)| *a).collect();
@ -899,6 +900,7 @@ impl Sim {
fn find_trips_affected_by_live_edits(
&mut self,
map: &Map,
timer: &mut Timer,
) -> (BTreeSet<(AgentID, TripID)>, usize) {
let mut affected: BTreeSet<(AgentID, TripID)> = BTreeSet::new();
@ -939,7 +941,8 @@ impl Sim {
}
let num_evicted = {
let (evicted_cars, cars_parking_in_the_void) = self.parking.handle_live_edits(map);
let (evicted_cars, cars_parking_in_the_void) =
self.parking.handle_live_edits(map, timer);
let num_evicted = evicted_cars.len();
affected.extend(self.walking.find_trips_to_parking(evicted_cars));
for car in cars_parking_in_the_void {