Parallelize part of scenario spawning. One of the code paths calls

biking_connection, which does a slow graph floodfill.

Prolet robot in Krakow: from 22.6s to 10.1s

Because Krakow now uses separate sidewalks and they're not properly
connected to the road graph yet, biking_connection has to search very
far. The speedup isn't noticeable in other cases.
This commit is contained in:
Dustin Carlino 2020-11-16 09:36:48 -08:00
parent b9ff94f275
commit 754749a578
3 changed files with 63 additions and 24 deletions

View File

@ -485,7 +485,7 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
vec![vehicle_spec.clone()],
);
spawner.schedule_trip(
person,
person.id,
now,
TripSpec::VehicleAppearing {
start_pos: Position::new(
@ -509,7 +509,8 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
} else if lane.is_walkable() {
for _ in 0..5 {
spawner.schedule_trip(
sim.random_person(Scenario::rand_ped_speed(&mut rng), Vec::new()),
sim.random_person(Scenario::rand_ped_speed(&mut rng), Vec::new())
.id,
now,
TripSpec::JustWalking {
start: SidewalkSpot::suddenly_appear(

View File

@ -6,7 +6,7 @@ use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use serde::{Deserialize, Serialize};
use abstutil::{prettyprint_usize, Counter, MapName, Timer};
use abstutil::{prettyprint_usize, Counter, MapName, Parallelism, Timer};
use geom::{Distance, Duration, LonLat, Speed, Time};
use map_model::{
BuildingID, BusRouteID, BusStopID, DirectedRoadID, Map, OffstreetParking, PathConstraints,
@ -161,8 +161,8 @@ impl Scenario {
}
timer.start_iter("trips for People", self.people.len());
let mut spawner = sim.make_spawner();
let mut parked_cars: Vec<(Vehicle, BuildingID)> = Vec::new();
let mut schedule_trips = Vec::new();
for p in &self.people {
timer.next();
@ -191,8 +191,8 @@ impl Scenario {
&mut tmp_rng,
map,
);
spawner.schedule_trip(
person,
schedule_trips.push((
person.id,
t.depart,
spec,
t.trip.start(map),
@ -200,9 +200,22 @@ impl Scenario {
t.cancelled,
t.modified,
map,
));
}
}
let mut spawner = sim.make_spawner();
let results = timer.parallelize(
"schedule trips",
Parallelism::Fastest,
schedule_trips,
|tuple| {
spawner.schedule_trip_fast(
tuple.0, tuple.1, tuple.2, tuple.3, tuple.4, tuple.5, tuple.6, tuple.7,
)
},
);
}
}
spawner.schedule_trips(results);
// parked_cars is stable over map edits, so don't fork.
parked_cars.shuffle(rng);

View File

@ -8,8 +8,8 @@ use geom::{Duration, Time};
use map_model::{BuildingID, BusRouteID, BusStopID, Map, PathConstraints, PathRequest, Position};
use crate::{
CarID, Command, DrivingGoal, OffMapLocation, Person, PersonID, Scheduler, SidewalkSpot,
TripEndpoint, TripLeg, TripManager, TripMode, TripPurpose, VehicleType,
CarID, Command, DrivingGoal, OffMapLocation, PersonID, Scheduler, SidewalkSpot, TripEndpoint,
TripLeg, TripManager, TripMode, TripPurpose, VehicleType,
};
// TODO Some of these fields are unused now that we separately pass TripEndpoint
@ -61,9 +61,7 @@ pub enum TripSpec {
},
}
/// This structure is created temporarily by a Scenario or to interactively spawn agents.
pub struct TripSpawner {
trips: Vec<(
type TripSpawnPlan = (
PersonID,
Time,
TripSpec,
@ -71,7 +69,11 @@ pub struct TripSpawner {
TripPurpose,
bool,
bool,
)>,
);
/// This structure is created temporarily by a Scenario or to interactively spawn agents.
pub struct TripSpawner {
trips: Vec<TripSpawnPlan>,
}
impl TripSpawner {
@ -79,9 +81,11 @@ impl TripSpawner {
TripSpawner { trips: Vec::new() }
}
pub fn schedule_trip(
&mut self,
person: &Person,
/// Doesn't actually schedule anything yet; you can call this from multiple threads, then feed
/// all the results to schedule_trips.
pub fn schedule_trip_fast(
&self,
person: PersonID,
start_time: Time,
mut spec: TripSpec,
trip_start: TripEndpoint,
@ -89,7 +93,7 @@ impl TripSpawner {
cancelled: bool,
modified: bool,
map: &Map,
) {
) -> TripSpawnPlan {
// TODO We'll want to repeat this validation when we spawn stuff later for a second leg...
match &spec {
TripSpec::VehicleAppearing {
@ -189,11 +193,32 @@ impl TripSpawner {
TripSpec::Remote { .. } => {}
};
self.trips.push((
person.id, start_time, spec, trip_start, purpose, cancelled, modified,
(
person, start_time, spec, trip_start, purpose, cancelled, modified,
)
}
/// Immediately schedule the requested trip
pub fn schedule_trip(
&mut self,
person: PersonID,
start_time: Time,
spec: TripSpec,
trip_start: TripEndpoint,
purpose: TripPurpose,
cancelled: bool,
modified: bool,
map: &Map,
) {
self.trips.push(self.schedule_trip_fast(
person, start_time, spec, trip_start, purpose, cancelled, modified, map,
));
}
pub fn schedule_trips(&mut self, trips: Vec<TripSpawnPlan>) {
self.trips.extend(trips);
}
pub fn finalize(
mut self,
map: &Map,