Skip to content
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

Via way restrictions #4255

Merged
merged 6 commits into from
Jul 31, 2017
Merged

Via way restrictions #4255

merged 6 commits into from
Jul 31, 2017

Conversation

MoKob
Copy link

@MoKob MoKob commented Jul 7, 2017

Issue

Tasklist

  • add regression / cucumber cases (see docs/testing.md)
  • add changelog entry indicating breaking changes to data-files
  • review
  • adjust for comments

Performance:

Extraction of Germany:

	Command being timed: "./build/osrm-extract /data/europe/germany/germany-latest.osm.pbf"
	User time (seconds): 1820.21
	System time (seconds): 120.63
	Percent of CPU this job got: 289%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 11:09.29
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 29249273856
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 558
	Minor (reclaiming a frame) page faults: 7944112
	Voluntary context switches: 1733
	Involuntary context switches: 6452780

Contraction:

	Command being timed: "./build/osrm-contract /data/europe/germany/germany-latest.osrm"
	User time (seconds): 5743.62
	System time (seconds): 61.59
	Percent of CPU this job got: 350%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 27:37.11
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 12026462208
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 237
	Minor (reclaiming a frame) page faults: 2390626
	Voluntary context switches: 2106
	Involuntary context switches: 3609162

Partition

[info] RAM: peak bytes used: 2839437312
	Command being timed: "./build/osrm-partition /data/europe/germany/germany-latest.osrm"
	User time (seconds): 2416.88
	System time (seconds): 48.81
	Percent of CPU this job got: 312%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 13:09.87
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 11357749248
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 133
	Minor (reclaiming a frame) page faults: 3211197
	Voluntary context switches: 33
	Involuntary context switches: 2509986

Customize

	Command being timed: "./build/osrm-customize /data/europe/germany/germany-latest.osrm"
	User time (seconds): 92.72
	System time (seconds): 4.02
	Percent of CPU this job got: 267%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 0:36.15
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 11178278912
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 153
	Minor (reclaiming a frame) page faults: 1078677
	Voluntary context switches: 18
	Involuntary context switches: 68336

Master

Extraction

	Command being timed: "./build/osrm-extract /data/europe/germany/germany-latest.osm.pbf"
	User time (seconds): 1803.88
	System time (seconds): 127.52
	Percent of CPU this job got: 285%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 11:16.82
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 29302489088
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 525
	Minor (reclaiming a frame) page faults: 9716627
	Voluntary context switches: 2248
	Involuntary context switches: 4430620

Contraction

	Command being timed: "./build/osrm-contract /data/europe/germany/germany-latest.osrm"
	User time (seconds): 5772.61
	System time (seconds): 68.48
	Percent of CPU this job got: 353%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 27:31.05
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 12026134528
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 232
	Minor (reclaiming a frame) page faults: 2396365
	Voluntary context switches: 3366
	Involuntary context switches: 4783880

Partition

	Command being timed: "./build/osrm-partition /data/europe/germany/germany-latest.osrm"
	User time (seconds): 2257.08
	System time (seconds): 46.40
	Percent of CPU this job got: 332%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 11:32.09
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 11366449152
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 133
	Minor (reclaiming a frame) page faults: 3355731
	Voluntary context switches: 33
	Involuntary context switches: 1645742

Customize

	Command being timed: "./build/osrm-customize /data/europe/germany/germany-latest.osrm"
	User time (seconds): 98.63
	System time (seconds): 5.48
	Percent of CPU this job got: 242%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 0:42.99
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 11177803776
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 155
	Minor (reclaiming a frame) page faults: 1078662
	Voluntary context switches: 15
	Involuntary context switches: 172589

@MoKob MoKob force-pushed the via-way-restrictions branch from cf5f718 to 9dc3c15 Compare July 7, 2017 14:02
@daniel-j-h daniel-j-h self-requested a review July 7, 2017 15:08
@MoKob MoKob force-pushed the via-way-restrictions branch from 9dc3c15 to 177f0fc Compare July 7, 2017 15:23
| ef |

And the relations
| type | way:from | way:via | way:from | restriction |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and below: shouldn't it be way:to instead of way:from twice?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course.

from.node = SPECIAL_NODEID;
to.node = SPECIAL_NODEID;
return flags.way_type ? boost::get<InputWayRestriction>(node_or_way).from
: boost::get<InputNodeRestriction>(node_or_way).from;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this construct - above we're using a variant but we're also storing flags? The variant already contains a flag and knows what actual type it is - I think you can use a visitor or a checked get call here.

using value_type = InputRestrictionContainer;
bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b) const
boost::variant<NodeRestriction, WayRestriction> node_or_way;
restriction_details::Bits flags;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an open change I have to do. I was originally using the normal structs that were in the data and only then switched to a true variant to avoid reinterpreting data over multiple types. Need to update that.

@MoKob MoKob force-pushed the via-way-restrictions branch 5 times, most recently from 58946c6 to 07459e9 Compare July 13, 2017 10:21
@MoKob
Copy link
Author

MoKob commented Jul 13, 2017

Demo Server:

screen shot 2017-07-13 at 15 19 57 2

This PR:

screen shot 2017-07-13 at 15 19 59 2

Relation in question: https://www.openstreetmap.org/relation/6495959#map=19/37.77034/-122.51128

@MoKob MoKob force-pushed the via-way-restrictions branch 3 times, most recently from 012c2f8 to 29e0cc7 Compare July 18, 2017 12:52
@MoKob
Copy link
Author

MoKob commented Jul 18, 2017

Impact so far on Baden Wuerttemberg:

extraction stays more or less the same speed:

without:
real 1m36.738s
user 4m12.325s
sys 0m17.995s

with:
real 1m35.268s
user 4m18.018s
sys 0m17.866s

Contraction measurements fluctuate quite a bit but do not show a consistent slowdown over current master branch.

@MoKob MoKob force-pushed the via-way-restrictions branch 3 times, most recently from 27cd3c7 to 6109840 Compare July 19, 2017 13:18
@MoKob MoKob changed the title Via way restrictions, resolves #2681 Via way restrictions Jul 24, 2017
@MoKob MoKob mentioned this pull request Jul 24, 2017
5 tasks
@MoKob MoKob force-pushed the via-way-restrictions branch from 6109840 to 6f81748 Compare July 24, 2017 14:49
Copy link
Member

@daniel-j-h daniel-j-h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left some early comments, didn't make it through completely today - will follow up tomorrow


And the relations
| type | way:from | node:via | way:to | restriction |
| restriction | abc | c | cgh | no_right_turn |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the via node is placed on a node that gets compressed? This should only ever be possible on degree-two intersections and then a restriction does not really make sense, no? What would happen in this case?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just ignore them. I would consider these a mapping error to begin with and not worry about them.
Internally

a - b - c and ab via b to bc should turn out as ac via b to ac after compression and be ignored as inconsistent.

a - b - c - - - - - - - - - - - - - - - - - - - f
| | \ /
i - d - e - - - - - - - - - - - - - - - - -
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the long geometry here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The correct turn needs to be undesirable, even without the turn restrictions. Otherwise having multiple non-working restrictions could be hidden by the fact that the non-restricted path is better, based on turn penalties alone.

When I route I should get
| from | to | route |
| a | j | left,first,right,right |
| f | e | right,third,left,left |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! ✨


And the relations
| type | way:from | way:via | way:to | restriction |
| restriction | ab | be | ef | only_left_on |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm is the behavior the same when I place a only_straight_on for the turn onto ef?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure whether I follow, but yes. We evaluate only_* without checking the postfix. Just as we did for via-nodes.


And the relations
| type | way:from | way:via | way:to | restriction |
| restriction | ab | be | ed | only_right_on |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question here

const std::string &cnbg_ebg_mapping_path);
const std::string &cnbg_ebg_mapping_path,
const RestrictionMap &restriction_map,
const WayRestrictionMap &way_restriction_map);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we name the RestrictionMap into NodeRestrictionMap then?


// the number of edge-based nodes is mostly made up out of the edges in the node-based graph.
// Any edge in the node-based graph represents a node in the edge-based graph. In addition, we
// add a set of artificial edge-based nodes into the mix to model via-way turn restrictions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you (capitalize the T :P and) add the ticket where we scoped out the idea behind via-way restrictions please

@@ -152,14 +157,16 @@ class EdgeBasedGraphFactory

unsigned RenumberEdges();

std::vector<NBGToEBG> GenerateEdgeExpandedNodes();
std::vector<NBGToEBG> GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the semantic meaning behind passing the way restriction map to GenerateEdgeExpandedNodes? Because it has to be aware of the artificial nodes? The idea here is not clear from the interface alone.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will document here. You are correct. EdgeExpandedNodes has to generate all our duplicated nodes as well. Therefor it requires access to the way-restriction-map.

const std::string &turn_penalties_index_filename);
const std::string &turn_penalties_index_filename,
const RestrictionMap &restriction_map,
const WayRestrictionMap &way_restriction_map);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here - why do we need the maps for edge expanded edge generation? Should this be refactored?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before they were stored as members and used within. We require the maps to check which turns are allowed. The intersection-generation / handling of via-way restrictions is required when looking at the edge-based-edges to find out which of the turns are valid (entry_allowed flag).

I just moved this to a reference parameter to get rid of some pointer usage we did beforehand.

unsigned max_internal_node_id;

// list of restrictions before we transform them into the output types
std::vector<InputConditionalTurnRestriction> restrictions_list;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With output types you mean the turn restriction vectors below? Why do we need to store both input and output then?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Input restrictions are generated during parsing and store OSM IDs. Only after we performed our re-mapping, we can assign the actual restrictions to be used later on.

Copy link
Member

@TheMarex TheMarex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the comments are duplicates that target the usage of lambda functions. The yoda-style (how before the what) of declaring them first and referencing them later makes it hard for me to follow the control flow, especially while reviewing, which is super frustrating. Please keep this in mind the future.

The approach is sound! I would be interested in some empirical measurements of graph size increase, just so we know what we are dealing here with. 👍

Q.A. wise I would love to see some sanity checks on California w.r.t to processing time, just to make sure we will not see unexpected results.


When I route I should get
| from | to | route |
| a | d | ab,be,ef,ef,de,de |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes it's helpful to include an extra comment column to explain what each row is testing. For example does not use turn ab,be,de or something like that.

@@ -5,111 +5,274 @@
#include "util/opening_hours.hpp"
#include "util/typedefs.hpp"

#include <boost/variant.hpp>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any particular reason why the boost version is used here? We already bundle the mapbox/variant, it might make sense to use it here as well.

return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via != SPECIAL_NODEID;
};

std::string ToString() const
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about moving this debug function outside of the class? I think we have an header for enabling pretty printers like this.

}
}

std::string ToString() const
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, pretty printers for debugging should be outside of the class.

// contracted move the head pointer to their respective head. Edges starting at tail move the
// tail values to their respective tails. Way turn restrictions are represented by two
// node-restrictions, so we can focus on them alone
boost::unordered_multimap<NodeID, NodeRestriction *> heads;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std also has a multimap, no need for boost.

Copy link
Author

@MoKob MoKob Jul 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://stackoverflow.com/questions/11519648/unordered-multimapequal-range-slow

Actually, that link is a wrong one. But @daniel-j-h, you had some links indicating performance problems on std::unordered_map, care to share them here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

};
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), extract_restrictions);

const auto as_duplicated_node =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this function gets inlined into by_duplicated_node we could simply use std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from) and avoid the copy over the tuple.

std::make_pair(std::make_pair(way.in_restriction.from, way.in_restriction.via), index));
++index;
};
std::for_each(restriction_data.begin(), restriction_data.end(), prepare_way_restriction);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a for loop for sure as it keep external state. Also as_duplicate_node is bound but not used, and I don't see a reference to duplication_id.

++offset;
return false; // continue until the end
};
std::adjacent_find(restriction_data.begin(), restriction_data.end(), add_offset_on_new_groups);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have util::for_each_pair for this, which makes the intend a little bit clearer.

std::size_t WayRestrictionMap::AsDuplicatedNodeID(const std::size_t restriction_id) const
{
return std::distance(duplicated_node_groups.begin(),
std::upper_bound(duplicated_node_groups.begin(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be split to two expression for readability, the 1 is almost sneaking away at the end.

{
// loop over all restrictions associated with the node. Mark as restricted based on
// is_only/restricted targets
for (std::size_t restriction_index = duplicated_node_groups[duplicated_node];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

util::irange can be used for this.

@MoKob MoKob force-pushed the via-way-restrictions branch 2 times, most recently from fdaee14 to 20ff5c5 Compare July 27, 2017 14:40
@MoKob MoKob force-pushed the via-way-restrictions branch from 20ff5c5 to d024c8e Compare July 27, 2017 14:51
Moritz Kobitzsch added 6 commits July 28, 2017 14:38
Makes turn restrictions into dedicated structures and diferentiates between them via a variant.
Ensures that we do not accidentally mess up ID types within our application.
In addition this improves the restriction performance by only parsing all edges
once at the cost of (at the time of writing) 22MB in terms of main memory usage.
…eation of edge-based-graph

initial version of handling via-way turn restrictions (this is dirty)

 - requires update of data structures
 - requires clean-up
 - requires optimisation
@MoKob MoKob force-pushed the via-way-restrictions branch from d024c8e to 49e77ac Compare July 28, 2017 12:39
@MoKob
Copy link
Author

MoKob commented Jul 28, 2017

I've addressed the reviews. Could you re-check?

@MoKob MoKob merged commit 8135f08 into master Jul 31, 2017
@MoKob MoKob deleted the via-way-restrictions branch July 31, 2017 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants