mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
refactor parallelized pathfinding and use it in trip viz too
This commit is contained in:
parent
f674527ef2
commit
1cdbe0ea81
@ -18,19 +18,23 @@ pub struct TripsVisualizer {
|
||||
|
||||
impl TripsVisualizer {
|
||||
pub fn new(ctx: &mut EventCtx, ui: &UI) -> TripsVisualizer {
|
||||
let trips = ctx.loading_screen(|_, mut timer| {
|
||||
let trips = ctx.loading_screen("load trip data", |_, mut timer| {
|
||||
let popdat: PopDat = abstutil::read_binary("../data/shapes/popdat", &mut timer)
|
||||
.expect("Couldn't load popdat");
|
||||
let mut all_trips = clip_trips(&popdat, ui, &mut timer);
|
||||
timer.start_iter("calculate routes", all_trips.len());
|
||||
let requests = all_trips
|
||||
.iter()
|
||||
.map(|trip| trip.path_req(&ui.primary.map))
|
||||
.collect();
|
||||
let paths = ui.primary.map.calculate_paths(requests, &mut timer);
|
||||
|
||||
let mut final_trips = Vec::new();
|
||||
for mut trip in all_trips.drain(..) {
|
||||
timer.start_iter("route geometry", paths.len());
|
||||
for (mut trip, (req, maybe_path)) in all_trips.drain(..).zip(paths) {
|
||||
timer.next();
|
||||
let req = trip.path_req(&ui.primary.map);
|
||||
if let Some(route) = ui
|
||||
.primary
|
||||
.map
|
||||
.pathfind(req.clone())
|
||||
// TODO path.trace is slow too and could be parallelized. Generalize
|
||||
// calculate_paths to just execute a callback and do the nice timer management.
|
||||
if let Some(route) = maybe_path
|
||||
.and_then(|path| path.trace(&ui.primary.map, req.start.dist_along(), None))
|
||||
{
|
||||
trip.route = Some(route);
|
||||
|
@ -59,7 +59,7 @@ impl ScenarioEditor {
|
||||
} else if menu.action("edit") {
|
||||
*self = ScenarioEditor::EditScenario(scenario.clone(), Wizard::new());
|
||||
} else if menu.action("instantiate") {
|
||||
ctx.loading_screen(|_, timer| {
|
||||
ctx.loading_screen("instantiate scenario", |_, timer| {
|
||||
scenario.instantiate(
|
||||
&mut ui.primary.sim,
|
||||
&ui.primary.map,
|
||||
|
@ -90,7 +90,7 @@ impl AgentSpawner {
|
||||
if ui.primary.sim.is_empty() {
|
||||
if sandbox_menu.action("seed the sim with agents") {
|
||||
// TODO This covers up the map. :\
|
||||
ctx.loading_screen(|_, timer| {
|
||||
ctx.loading_screen("seed sim with agents", |_, timer| {
|
||||
let map = &ui.primary.map;
|
||||
let s = if let Some(n) = ui.primary.current_flags.num_agents {
|
||||
Scenario::scaled_run(map, n)
|
||||
|
@ -395,7 +395,7 @@ pub struct PerMapUI {
|
||||
|
||||
impl PerMapUI {
|
||||
pub fn new(flags: Flags, cs: &ColorScheme, ctx: &mut EventCtx) -> PerMapUI {
|
||||
let (map, sim, draw_map) = ctx.loading_screen(|ctx, timer| {
|
||||
let (map, sim, draw_map) = ctx.loading_screen("load map", |ctx, timer| {
|
||||
let mut mem = MeasureMemory::new();
|
||||
let (map, sim, _) = flags.sim_flags.load(Some(Duration::seconds(30.0)), timer);
|
||||
mem.reset("Map and Sim", timer);
|
||||
|
@ -127,14 +127,19 @@ pub struct EventCtx<'a> {
|
||||
}
|
||||
|
||||
impl<'a> EventCtx<'a> {
|
||||
pub fn loading_screen<O, F: FnOnce(&mut EventCtx, &mut Timer) -> O>(&mut self, f: F) -> O {
|
||||
pub fn loading_screen<O, F: FnOnce(&mut EventCtx, &mut Timer) -> O>(
|
||||
&mut self,
|
||||
timer_name: &str,
|
||||
f: F,
|
||||
) -> O {
|
||||
let mut timer = Timer::new_with_sink(
|
||||
"Loading...",
|
||||
timer_name,
|
||||
Box::new(LoadingScreen::new(
|
||||
self.prerender,
|
||||
self.program,
|
||||
self.canvas.window_width,
|
||||
self.canvas.window_height,
|
||||
timer_name.to_string(),
|
||||
)),
|
||||
);
|
||||
f(self, &mut timer)
|
||||
@ -148,6 +153,7 @@ pub struct LoadingScreen<'a> {
|
||||
lines: VecDeque<String>,
|
||||
max_capacity: usize,
|
||||
last_drawn: Option<Instant>,
|
||||
title: String,
|
||||
}
|
||||
|
||||
impl<'a> LoadingScreen<'a> {
|
||||
@ -156,6 +162,7 @@ impl<'a> LoadingScreen<'a> {
|
||||
program: &'a glium::Program,
|
||||
initial_width: f64,
|
||||
initial_height: f64,
|
||||
title: String,
|
||||
) -> LoadingScreen<'a> {
|
||||
// TODO Ew! Expensive and wacky. Fix by not storing GlyphBrush in Canvas at all.
|
||||
let dejavu: &[u8] = include_bytes!("assets/DejaVuSans.ttf");
|
||||
@ -173,6 +180,7 @@ impl<'a> LoadingScreen<'a> {
|
||||
lines: VecDeque::new(),
|
||||
max_capacity: (0.8 * initial_height / line_height) as usize,
|
||||
last_drawn: None,
|
||||
title,
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +193,7 @@ impl<'a> LoadingScreen<'a> {
|
||||
}
|
||||
self.last_drawn = Some(Instant::now());
|
||||
|
||||
let mut txt = Text::prompt("Loading...");
|
||||
let mut txt = Text::prompt(&self.title);
|
||||
for l in &self.lines {
|
||||
txt.add_line(l.to_string());
|
||||
}
|
||||
|
@ -10,8 +10,10 @@ abstutil = { path = "../abstutil" }
|
||||
geom = { path = "../geom" }
|
||||
gtfs = { path = "../gtfs" }
|
||||
nbez = "0.1.0"
|
||||
num_cpus = "1.10.0"
|
||||
ordered-float = "1.0.1"
|
||||
petgraph = { version = "0.4.13", features = ["serde-1"] }
|
||||
pretty_assertions = "0.6.1"
|
||||
scoped_threadpool = "0.1.9"
|
||||
serde = "1.0.89"
|
||||
serde_derive = "1.0.89"
|
||||
|
@ -697,4 +697,31 @@ impl Map {
|
||||
side2[idx]
|
||||
}
|
||||
}
|
||||
|
||||
// Parallelizes pathfind()
|
||||
pub fn calculate_paths(
|
||||
&self,
|
||||
requests: Vec<PathRequest>,
|
||||
timer: &mut Timer,
|
||||
) -> Vec<(PathRequest, Option<Path>)> {
|
||||
scoped_threadpool::Pool::new(num_cpus::get() as u32).scoped(|scope| {
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
let mut results: Vec<(PathRequest, Option<Path>)> = Vec::new();
|
||||
for (idx, req) in requests.into_iter().enumerate() {
|
||||
results.push((req.clone(), None));
|
||||
let tx = tx.clone();
|
||||
scope.execute(move || {
|
||||
tx.send((idx, self.pathfind(req))).unwrap();
|
||||
});
|
||||
}
|
||||
drop(tx);
|
||||
|
||||
timer.start_iter("calculate paths", results.len());
|
||||
for (idx, path) in rx.iter() {
|
||||
timer.next();
|
||||
results[idx].1 = path;
|
||||
}
|
||||
results
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,10 @@ geom = { path = "../geom" }
|
||||
histogram = "0.6.9"
|
||||
map_model = { path = "../map_model" }
|
||||
more-asserts = "0.2.1"
|
||||
num_cpus = "1.10.0"
|
||||
petgraph = "0.4.13"
|
||||
pretty_assertions = "0.6.1"
|
||||
rand = { version = "0.6.5", features = ["serde1"] }
|
||||
rand_xorshift = "0.1.1"
|
||||
scoped_threadpool = "0.1.9"
|
||||
serde = "1.0.89"
|
||||
serde_derive = "1.0.89"
|
||||
structopt = "0.2.15"
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
};
|
||||
use abstutil::Timer;
|
||||
use geom::{Duration, Speed};
|
||||
use map_model::{BusRouteID, BusStopID, Map, Path, PathRequest, Position};
|
||||
use map_model::{BusRouteID, BusStopID, Map, PathRequest, Position};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
@ -155,8 +155,7 @@ impl TripSpawner {
|
||||
timer: &mut Timer,
|
||||
retry_if_no_room: bool,
|
||||
) {
|
||||
let paths = calculate_paths(
|
||||
map,
|
||||
let paths = map.calculate_paths(
|
||||
self.trips
|
||||
.iter()
|
||||
.map(|(_, _, _, spec)| spec.get_pathfinding_request(map, parking))
|
||||
@ -378,29 +377,3 @@ impl TripSpec {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_paths(
|
||||
map: &Map,
|
||||
requests: Vec<PathRequest>,
|
||||
timer: &mut Timer,
|
||||
) -> Vec<(PathRequest, Option<Path>)> {
|
||||
scoped_threadpool::Pool::new(num_cpus::get() as u32).scoped(|scope| {
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
let mut results: Vec<(PathRequest, Option<Path>)> = Vec::new();
|
||||
for (idx, req) in requests.into_iter().enumerate() {
|
||||
results.push((req.clone(), None));
|
||||
let tx = tx.clone();
|
||||
scope.execute(move || {
|
||||
tx.send((idx, map.pathfind(req))).unwrap();
|
||||
});
|
||||
}
|
||||
drop(tx);
|
||||
|
||||
timer.start_iter("calculate paths", results.len());
|
||||
for (idx, path) in rx.iter() {
|
||||
timer.next();
|
||||
results[idx].1 = path;
|
||||
}
|
||||
results
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user