From c5c00d57408699f96e56374ffcbc12855b507337 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Wed, 5 Sep 2018 17:13:26 -0700 Subject: [PATCH] record stack traces --- docs/design.md | 38 ++++++++++++++++++++++++++++++++++++++ headless/src/main.rs | 1 + sim/src/instrument.rs | 33 ++++++++++++++------------------- sim/src/lib.rs | 1 + sim/src/sim.rs | 3 +++ sim/src/transit.rs | 5 ++++- sim/src/walking.rs | 3 +++ 7 files changed, 64 insertions(+), 20 deletions(-) diff --git a/docs/design.md b/docs/design.md index 407656ac56..0191781e95 100644 --- a/docs/design.md +++ b/docs/design.md @@ -518,6 +518,37 @@ epsilon and negative checks everywhere in kinematics, but why? Should research it more, but I think the better approach is to use fixed-point arithmetic for everything (aka u8 or whatever). +Problems with floats: +- they dont natively order +- they arent PartialEq +- serialization sometimes breaks +- epsilon comparison issues + +Options: + - just to solve epsilon comparison issues + - https://crates.io/crates/float-cmp + - https://crates.io/crates/approx + - just to get Ord and Eq + - https://crates.io/crates/decorum + - https://crates.io/crates/ordered-float + - use rational / fraction types + - https://crates.io/crates/fraction + - https://crates.io/crates/rug + - this seems a bit overpowered + - use my own custom wrapper type around u8 or whatever size makes sense for each thing + - representing 0.1s or 0.1m or whatever + - use a fixed point arithmetic crate + - https://crates.io/crates/fpa + - https://crates.io/crates/fixed + - https://crates.io/crates/fix + - would want to wrap the types anyway; only some operations make sense + + +- can we compare results with the prev float approach? make them store the + other thing, compare results? or compare the results of a sim? +- is it possible to do this change gradually? unlikely... + + - moment in time (tick) - resolution: 0.1s with u32, so about 13.5 years - duration @@ -822,3 +853,10 @@ It happens because a car was previously throttling itself due to somebody in the way, but as soon as they start a turn, the car eagerly jumps ahead. ah no, it's because we use max_lookahead_dist in accel_to_follow, and the speed limit we assert is the old road's speed. + +## Moving away from piston + +- options + - gfx (pre-II or not?) + winit + - https://suhr.github.io/gsgt/ + - glium (unmaintained) diff --git a/headless/src/main.rs b/headless/src/main.rs index 72a9895a65..edf439e42c 100644 --- a/headless/src/main.rs +++ b/headless/src/main.rs @@ -71,4 +71,5 @@ fn main() { } }), ); + sim::save_backtraces("call_graph.json"); } diff --git a/sim/src/instrument.rs b/sim/src/instrument.rs index 4e77f064ca..eae2805d1d 100644 --- a/sim/src/instrument.rs +++ b/sim/src/instrument.rs @@ -1,20 +1,16 @@ +use abstutil; use backtrace::Backtrace; -use std::collections::HashMap; +use std::collections::HashSet; use std::sync::Mutex; -#[derive(Debug)] -struct CallStack { - calls: Vec, -} - lazy_static! { - static ref BACKTRACES: Mutex> = Mutex::new(HashMap::new()); + static ref BACKTRACES: Mutex>> = Mutex::new(HashSet::new()); } -pub fn capture_backtrace() { +pub fn capture_backtrace(event: &str) { let bt = Backtrace::new(); let mut found_this_fxn = false; - let mut calls: Vec = Vec::new(); + let mut calls: Vec = vec![event.to_string()]; for f in bt.frames() { let raw_name = format!("{}", f.symbols()[0].name().unwrap()); let mut raw_name_parts: Vec<&str> = raw_name.split("::").collect(); @@ -33,15 +29,14 @@ pub fn capture_backtrace() { } } - let caller = &calls[0]; - let stack = CallStack { - calls: calls[1..].to_vec(), - }; - println!("insert {}: {:?}", caller, stack); - let mut remember = BACKTRACES.lock().unwrap(); - remember.insert(caller.to_string(), stack); + BACKTRACES.lock().unwrap().insert(calls); } -// TODO dump to file -// TODO manually call when events are created and at other interesting points -// TODO compiler flag so capture_backtrace is usually a no-op +pub fn save_backtraces(path: &str) { + abstutil::write_json(path, &(*BACKTRACES.lock().unwrap())).unwrap(); +} + +// TODO call from all interesting methods in a few different types; maybe use macros to help +// TODO compiler flag so capture_backtrace is usually a no-op. actually, looks like this doesn't +// work in --release mode, so use that. +// TODO script to organize and visualize results diff --git a/sim/src/lib.rs b/sim/src/lib.rs index 63f70b1784..12ddb0ec1e 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -48,6 +48,7 @@ use dimensioned::si; pub use events::Event; use geom::{Angle, Pt2D}; pub use helpers::load; +pub use instrument::save_backtraces; use map_model::{LaneID, Map, TurnID}; pub use sim::{Benchmark, Sim}; use std::fmt; diff --git a/sim/src/sim.rs b/sim/src/sim.rs index 1e21051d25..5e6b416a1b 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -7,6 +7,7 @@ use draw_car::DrawCar; use draw_ped::DrawPedestrian; use driving::DrivingSimState; use failure::Error; +use instrument::capture_backtrace; use intersections::IntersectionSimState; use kinematics::Vehicle; use map_model::{IntersectionID, LaneID, LaneType, Map, Turn, TurnID}; @@ -169,6 +170,7 @@ impl Sim { &self.car_properties, )? { events.push(Event::CarReachedParkingSpot(p.clone())); + capture_backtrace("CarReachedParkingSpot"); self.parking_state.add_parked_car(p.clone()); self.spawner.car_reached_parking_spot( self.time, @@ -185,6 +187,7 @@ impl Sim { .step(&mut events, TIMESTEP, map, &mut self.intersection_state)? { events.push(Event::PedReachedParkingSpot(ped, spot)); + capture_backtrace("PedReachedParkingSpot"); self.spawner.ped_reached_parking_spot( self.time, ped, diff --git a/sim/src/transit.rs b/sim/src/transit.rs index 7a9714d481..4c4e7cb94a 100644 --- a/sim/src/transit.rs +++ b/sim/src/transit.rs @@ -138,7 +138,7 @@ impl TransitSimState { self.buses.get_mut(&car).unwrap().state = BusState::AtStop(stop_idx, time + 10.0 * si::S); events.push(Event::BusArrivedAtStop(car, stop.id)); - capture_backtrace(); + capture_backtrace("BusArrivedAtStop"); if view.debug { println!("{} arrived at stop {:?}, now waiting", car, stop); } @@ -156,6 +156,7 @@ impl TransitSimState { let next_stop = route.next_stop(stop_idx); self.buses.get_mut(&car).unwrap().state = BusState::DrivingToStop(next_stop); events.push(Event::BusDepartedFromStop(car, stop.id)); + capture_backtrace("BusDepartedFromStop"); if view.debug { println!("{} departing from stop {:?}", car, stop); } @@ -210,6 +211,7 @@ impl TransitSimState { for p in walking_sim.get_peds_waiting_at_stop(stop.id).into_iter() { if trips.should_ped_board_bus(p, b.route) { events.push(Event::PedEntersBus(p, b.car)); + capture_backtrace("PedEntersBus"); b.passengers.push(p); walking_sim.ped_joined_bus(p, stop.id); } @@ -226,6 +228,7 @@ impl TransitSimState { b.passengers.retain(|p| { if trips.should_ped_leave_bus(*p, stop.id) { events.push(Event::PedLeavesBus(*p, car)); + capture_backtrace("PedLeavesBus"); // TODO would be a little cleaner to return this info up to sim and have it // plumb through to spawner? not sure spawner.ped_finished_bus_ride(now, *p, stop.id, trips, map); diff --git a/sim/src/walking.rs b/sim/src/walking.rs index c9d2d7cc5f..2d5f24cf36 100644 --- a/sim/src/walking.rs +++ b/sim/src/walking.rs @@ -4,6 +4,7 @@ use dimensioned::si; use draw_ped::DrawPedestrian; use failure::Error; use geom::{Line, Pt2D}; +use instrument::capture_backtrace; use intersections::{IntersectionSimState, Request}; use map_model::{BuildingID, BusStop, IntersectionID, Lane, LaneID, Map, Turn, TurnID}; use multimap::MultiMap; @@ -216,6 +217,7 @@ impl Pedestrian { fp.dist_along -= new_dist; if fp.dist_along < 0.0 * si::M { events.push(Event::PedReachedBuilding(self.id, fp.bldg)); + capture_backtrace("PedReachedBuilding"); return true; } false @@ -399,6 +401,7 @@ impl WalkingSimState { Action::WaitAtBusStop(stop) => { self.peds.get_mut(&id).unwrap().active = false; events.push(Event::PedReachedBusStop(*id, stop)); + capture_backtrace("PedReachedBusStop"); self.peds_per_bus_stop.insert(stop, *id); } Action::StartParkedCar(ref spot) => {