-
Notifications
You must be signed in to change notification settings - Fork 661
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reduce code duplication in timedep forward/reverse #2987
Conversation
src/thor/timedep_forward.cc
Outdated
const TimeInfo& time_info, | ||
const valhalla::Location& destination, | ||
std::pair<int32_t, float>& best_path) { | ||
template <TimeDepForward::ExpansionType expansion_direction, typename EdgeLabelT> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note the EdgeLabelT - this is a temporary WIP trying to figure out how to handle EdgeLabel-vs-BDEdgeLabel.
src/thor/timedep_forward.cc
Outdated
} | ||
|
||
return disable_uturn; | ||
} | ||
|
||
template bool TimeDepForward::Expand<TimeDepForward::ExpansionType::reverse, BDEdgeLabel>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explicit declaration of reverse implementation so that the TimeDepReverse translation unit can find the template instantiation at link time. As the code stands, it's a bit weird to have a derived class trying to use template methods from the parent TU - I expect to refactor this detail away as I remove more code.
std::pair<int32_t, float>& best_path) { | ||
constexpr bool FORWARD = expansion_direction == TimeDepForward::ExpansionType::forward; | ||
|
||
if (!FORWARD) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question to readers: conceptually why is this early-exit only done for the reverse search? Is this a copypasta bug, or is there some rationale?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code has changed considerably since I left it, but in reverse searches I initially added an early exit based on the directed edge's reverseaccess to avoid having to get the opposing directed edge and perform the more complete costing Allowed check. I believe I did some benchmarking around this and found a slight performance improvement. I can't comment on why shortcut edges are skipped.
if (t2 == nullptr) { | ||
return false; | ||
} | ||
opp_edge_id = t2->GetOpposingEdgeId(meta.edge); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I renamed these from TimeDepReverse, they were oppedge
and opp_edge
there, which is a bit of a dubious naming scheme.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea, opp_edge_id is a better choice!
src/thor/timedep_forward.cc
Outdated
time_info.local_time, nodeinfo->timezone())) { | ||
return false; | ||
if (FORWARD) { | ||
if (meta.edge->is_shortcut() || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the forward search wrapped in is_shortcut()
, but the reverse is not?
src/thor/timedep_forward.cc
Outdated
if (FORWARD) { | ||
newcost += transition_cost; | ||
} else { | ||
newcost.cost += transition_cost.cost; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was similar to the thing found in the Dijkstra refactor - why does reverse only add cost? This seems like a bug, as it means a TimeDepReverse path won't accumulate time?
src/thor/timedep_forward.cc
Outdated
: edgelabels_.size(); | ||
best_path.first = (meta.edge_status->set() == EdgeSet::kTemporary) | ||
? meta.edge_status->index() | ||
: (FORWARD ? edgelabels_.size() : edgelabels_.size()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: these used to be different (edgelabels_rev_
and edgelabels_
) - I've left this in for now as a reminder that forward/reverse behaviour may be specialized here.
src/thor/timedep_forward.cc
Outdated
EdgeLabel& lab = edgelabels_[meta.edge_status->index()]; | ||
// TODO(danpat): can we slices down to EdgeLabel here safely? | ||
EdgeLabel& lab = | ||
FORWARD ? edgelabels_[meta.edge_status->index()] : edgelabels_[meta.edge_status->index()]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to above - previously had different EdgeLabel/BDEdgeLabel for forward/reverse - left this in as a temporary reminder until I confirm it's OK to use BDEdgeLabel in all cases.
src/thor/timedep_forward.cc
Outdated
if (newcost.cost < lab.cost().cost) { | ||
float newsortcost = lab.sortcost() - (lab.cost().cost - newcost.cost); | ||
adjacencylist_.decrease(meta.edge_status->index(), newsortcost); | ||
if (FORWARD) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And one more instance of the same.
src/thor/timedep_reverse.cc
Outdated
@@ -54,245 +33,20 @@ void TimeDepReverse::Init(const midgard::PointLL& origll, const midgard::PointLL | |||
// Reserve size for edge labels - do this here rather than in constructor so | |||
// to limit how much extra memory is used for persistent objects. | |||
// TODO - reserve based on estimate based on distance and route type. | |||
edgelabels_rev_.reserve(kInitialEdgeLabelCount); | |||
edgelabels_.reserve(kInitialEdgeLabelCount); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole Init() thing can likely go away if we can use the BDEdgeLabel object for the forward search.
@danpat as an anecdote i can say that i semi recently refactored the forward direction of isochrones to use BDEdgeLabel. I seem to remember losing about 10% performance but I clawed it back with optimization to other parts of the code. I would much prefer the simplicity of using BDEdgeLabel everywhere (multimodal is another question mark though) if we can, so its definitely worth doing and measuring to see if its palatable. |
…h template parameters - TODO: segfaulting sometimes, so this is incomplete.
Benchmark results. Switching to Invocation:
master
this branch
|
@danpat good news that the larger edgelabels didnt bother it. some of the results are suprisingly noisey in these benches though. ive been noticing it over the last few PRs. the standard deviation for example is off by orders of magnitude between runs sometimes. wtf is with that? im still so skeptical of gbench hahaha 😄 |
…ger-scale testing.
@kevinkreiser this bench running a small handful of quite slow routes - e.g. in the Forward test, 6 routes are calculated and it takes ~14 seconds. Given the duration of the individual test, I'm not all that surprised to see a pretty wobbly stddev, anything else happening on the box over that single timed 14 second run could interfere. A better test might be to divide it up into smaller faster chunks - more iterations of a faster test would probably give better signal. |
looks good to me save for those two nit picks |
@kevinkreiser yeah, not quite up-to-date with master. I'm still digging into two curiosities before I mark this good: I don't understand why reverse is only adding The second, more concerning issue is this: Even on a basic, unambiguous test, TimeDepReverse is returning different durations from node-to-node - IMO, this test should return identical results to the forward search version. It's also returning an extra node as you noted in the TODO there, so I think there's some off-by-one or missing termination condition somewhere in the reverse version of things. So far, what I know is that it seems that the reverse search is continuing for one extra expansion after arriving at the origin - I suspect it might be a 0-cost u-turn or something. This bug exists on master so I'm not going to kill myself trying to track it down, but I would like to clean up that cost adding thing. |
Ah yes, when i wrote a bunch of the test all algorithms tests I had to disable some because it wasnt adding up properly. It seems you are finding the same thing. I didnt have a chance to dive into it at the time but it will be good to get to the bottom of it! |
Got to the bottom of it - two problems in the reverse search:
With these two fixes, forward/reverse now give consistent results. Commits coming shortly once I verify all the other tests. UPDATE: c9caf70 contains the fix |
@kevinkreiser I think I'm good with the current state of this - 350 fewer lines of code and a couple of bugs fixed, |
…lla into danpat_timedep_refactor_1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks for this big cleanup (and squashed an imp bug too!) 🙏
Issue
PR No. 3 in the series towards #2885. This one tackles TimeDepForward/Reverse.
Main changes in this are:
TimeDep
toUnidirectionalAStar
to be consistent withBidirectionalAStar
unidirectionalastar.cc
codebase.Tasklist
Requirements / Relations
Link any requirements here. Other pull requests this PR is based on?