-
Notifications
You must be signed in to change notification settings - Fork 673
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
fixes(live-speed): Fixes underflow for traffic speed > 140kph #2325
Conversation
aa21816
to
b6f06c7
Compare
Can you add some notes on what the problem was and how this change fixes it? Are there tests we can add to verify the change (I understand that its already been tested in prod, but it will be good to have some unit tests, if possible)? |
@mandeepsandhu i can. basically when we do costing we compute the time it took to traverse an edge. to do so we need to do |
src/sif/autocost.cc
Outdated
@@ -314,7 +315,7 @@ class AutoCost : public DynamicCost { | |||
// We expose it within the source file for testing purposes | |||
public: | |||
VehicleType type_; // Vehicle type: car (default), motorcycle, etc | |||
float speedfactor_[kMaxSpeedKph + 1]; | |||
float speedfactor_[valhalla::baldr::traffic::MAX_TRAFFIC_SPEED_KPH + 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.
do no other costings do this? not even motorcycle, motorscooter or truck?
can anyone think of a way to write a unit test that exposes undefined behavior because of out of bounds access. i always struggle with this one. what is a good pattern for testing regressions of this type? |
@kevinkreiser That's a good use for If we made it an |
@danpat that one did occur to me but it felt a bit like cheating TDD to put the assert in the function thats buggy haha. but i think you're right its the only way to easily unit test it without an extremely complicated test setup. ah and a quick google shows that cmake already does the work of defining |
Nice catch! And thanks for the clear explanation. Would love to see it in the commit message for posterity. I think your assumption about division being slower than multiplication still holds true for modern processors. Small anecdote: I've been bitten by a very similar lookup table bug before. The code was trying to calculate "square" of a video pixel value by using a lookup table. The lookup table had 2000 entries since, when it was created, max resolution of a video frame was 1920x1080. Then came 4K videos and this program started crashing (since it was trying to find squares beyond the lookup table's bounds). On measuring performance of lookup table we found that just calculating the square ( |
See new code that renames the constants a bit. I'm trying to clarify the meaning of the various constants.
Agreed, commit amended.
This is a good idea but it seems difficult in practice. All dependencies seem to require being built with
I'm still working on a unit-test. |
b6f06c7
to
456b619
Compare
@@ -270,7 +270,7 @@ class AutoCost : public DynamicCost { | |||
* estimate is less than the least possible time along roads. | |||
*/ | |||
virtual float AStarCostFactor() const { | |||
return speedfactor_[kMaxSpeedKph]; | |||
return speedfactor_[kMaxAssumedSpeed]; |
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 breaks the assumptions of the heuristic. But changing it to use the new kMaxSpeedKph
would change existing routes without traffic I believe...
EDIT: Err, the larger speed would lead to a potentially larger expansion of the graph before finding a route.
cfc0c44
to
cf3ca96
Compare
0f8f9f2
to
a3b4fff
Compare
Ok, I just force pushed two commits. The first commit adds a test that inserts a high traffic speed and thus the test fails. The second commit fixes the out-of-bounds and thereby the test. |
The apparent underflow happened because of the use of the precomputed division tables in the costing functions. They were pre-computed using the assumed max speed of 140kph. Thus, when faced with speeds larger than that from traffic, out-of-bounds access occured and garbage data was read. This change tweaks the max speed to account for higher speeds in traffic data. Checks speedfactor out-of-bounds in debug with assert
b3752f4
to
43ca54d
Compare
src/sif/bicyclecost.cc
Outdated
@@ -7,6 +7,7 @@ | |||
#include "baldr/nodeinfo.h" | |||
#include "midgard/constants.h" | |||
#include "midgard/util.h" | |||
#include <assert.h> |
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.
same as above
@@ -31,6 +32,9 @@ constexpr uint16_t INVALID_SPEED_AGE_BUCKET = 0; | |||
constexpr uint16_t MAX_SPEED_AGE_BUCKET = 15; | |||
constexpr uint16_t SPEED_AGE_BUCKET_SIZE = 2; // 2 minutes per bucket | |||
|
|||
// Traffic speeds are encoded as 8 bits in `Speed` below | |||
constexpr uint32_t MAX_TRAFFIC_SPEED_KPH = 255; |
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 should be defined in graphconstants and used from there though right? its a bit annoying that we have the value in two places.
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, I was struggling with this. I wanted to avoid pulling in the graphconstants initially in order to avoid keep the C-interface a single file and instead settled with the static assert that the two were the same value.
|
||
// Assert these constants are the same | ||
// (We want to avoid including this file in graphconstants.h) | ||
static_assert(MAX_TRAFFIC_SPEED_KPH == valhalla::baldr::kMaxTrafficSpeed, |
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.
perhaps there was another reason why you didnt want to use the value from graphconstants? i was kind of thinking a static assert that made sure the value wasnt above 1<<8 - 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.
See comment at https://github.com/valhalla/valhalla/pull/2325/files#r412394756
There is also the test at https://github.com/valhalla/valhalla/pull/2325/files#diff-7db274cd70eab71e43c6dc96bff4d5cdR69
Ugh, seems windows has a special C++
|
@purew that usually just means that we are relying on some header that got included by another header we explicitly included. we probably just need to do an explicit include of |
No description provided.