Conjure Traffic Seitan, a tool to make byzantine live map edits, to cause chaos and flush out bugs...

This commit is contained in:
Dustin Carlino 2020-10-01 18:24:35 -07:00
parent afa27e0903
commit f73d9da080
10 changed files with 94 additions and 4 deletions

12
Cargo.lock generated
View File

@ -3253,6 +3253,18 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "traffic_seitan"
version = "0.1.0"
dependencies = [
"abstutil 0.1.0",
"geom 0.1.0",
"map_model 0.1.0",
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sim 0.1.0",
]
[[package]]
name = "try-lock"
version = "0.2.2"

View File

@ -12,6 +12,7 @@ members = [
"map_model",
"map_tests",
"sim",
"traffic_seitan",
"updater",
"widgetry",
]

View File

@ -141,6 +141,10 @@ Common utilities:
- `geom`: types for GPS and map-space points, lines, angles, polylines,
polygons, circles, durations, speeds
Other:
- `traffic_seitan`: a bug-finding tool that randomly generates live map edits
## Code conventions
All code is automatically formatted using

View File

@ -514,6 +514,9 @@ pub struct Flags {
// Number of agents to generate when requested. If unspecified, trips to/from borders will be
// included.
pub num_agents: Option<usize>,
// If true, all map edits immediately apply to the live simulation. Otherwise, most edits
// require resetting to midnight.
pub live_map_edits: bool,
}
// All of the state that's bound to a specific map+edit has to live here.

View File

@ -90,7 +90,7 @@ impl EditMode {
app.primary
.map
.recalculate_pathfinding_after_edits(&mut timer);
if app.primary.current_flags.sim_flags.opts.live_map_edits {
if app.primary.current_flags.live_map_edits {
app.primary.sim = old_sim;
app.primary.dirty_from_edits = true;
app.primary

View File

@ -42,6 +42,7 @@ fn main() {
let mut flags = Flags {
sim_flags: SimFlags::from_args(&mut args),
num_agents: args.optional_parse("--num_agents", |s| s.parse()),
live_map_edits: args.enabled("--live_map_edits"),
};
let mut opts = options::Options::default();
opts.dev = args.enabled("--dev");

View File

@ -76,7 +76,6 @@ pub struct SimOptions {
pub enable_pandemic_model: Option<XorShiftRng>,
pub alerts: AlertHandler,
pub pathfinding_upfront: bool,
pub live_map_edits: bool,
pub infinite_parking: bool,
}
@ -112,7 +111,6 @@ impl SimOptions {
})
.unwrap_or(AlertHandler::Print),
pathfinding_upfront: args.enabled("--pathfinding_upfront"),
live_map_edits: args.enabled("--live_map_edits"),
infinite_parking: args.enabled("--infinite_parking"),
}
}
@ -146,7 +144,6 @@ impl SimOptions {
enable_pandemic_model: None,
alerts: AlertHandler::Print,
pathfinding_upfront: false,
live_map_edits: false,
infinite_parking: false,
}
}

13
traffic_seitan/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "traffic_seitan"
version = "0.1.0"
authors = ["Dustin Carlino <dabreegster@gmail.com>"]
edition = "2018"
[dependencies]
abstutil = { path = "../abstutil" }
geom = { path = "../geom" }
map_model = { path = "../map_model" }
rand = "0.7.0"
rand_xorshift = "0.2.0"
sim = { path = "../sim" }

View File

@ -0,0 +1,59 @@
// This is a tool that runs a simulation, constantly interrupting to apply random map edits to the
// live sim without resetting to midnight. The purpose is to trigger crashes and find bugs.
//
// TODO When something does crash, we'll need to repro in the GUI. Savestate and give instructions
// how to make the last edit at a time?
//
// TODO Eventually rewrite this to go through the public API. Faster to iterate in Rust for now.
use abstutil::{CmdArgs, Timer};
use geom::Duration;
use map_model::{LaneID, LaneType, Map, MapEdits};
use rand::seq::SliceRandom;
use rand_xorshift::XorShiftRng;
use sim::{Sim, SimFlags};
fn main() {
let mut args = CmdArgs::new();
let sim_flags = SimFlags::from_args(&mut args);
args.done();
let mut timer = Timer::new("cause mass chaos");
let (mut map, mut sim, mut rng) = sim_flags.load(&mut timer);
run(&mut map, &mut sim, &mut rng, &mut timer);
}
fn run(map: &mut Map, sim: &mut Sim, rng: &mut XorShiftRng, timer: &mut Timer) {
let edit_frequency = Duration::minutes(5);
while !sim.is_done() {
sim.timed_step(map, edit_frequency, &mut None, timer);
let mut edits = map.get_edits().clone();
edits.edits_name = "chaos".to_string();
nuke_random_parking(map, rng, &mut edits);
map.must_apply_edits(edits, timer);
map.recalculate_pathfinding_after_edits(timer);
}
}
// TODO This doesn't cause any interesting crash yet. Find somebody in the act of
// parking/unparking/going to a spot, and nuke that instead.
fn nuke_random_parking(map: &Map, rng: &mut XorShiftRng, edits: &mut MapEdits) {
let num_edits = 5;
let mut parking_lanes: Vec<LaneID> = map
.all_lanes()
.iter()
.filter(|l| l.is_parking())
.map(|l| l.id)
.collect();
parking_lanes.shuffle(rng);
for l in parking_lanes.into_iter().take(num_edits) {
let r = map.get_parent(l);
edits.commands.push(map.edit_road_cmd(r.id, |new| {
new.lanes_ltr[r.offset(l)].0 = LaneType::Construction;
}));
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB