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

Renumber graph nodes after partitioning them #4089

Merged
merged 3 commits into from
Jun 2, 2017
Merged

Conversation

TheMarex
Copy link
Member

@TheMarex TheMarex commented May 24, 2017

Issue

This implements the second part of #3779

Tasklist

Requirements / Relations

This PR is rebased on #4056.

@TheMarex TheMarex added this to the 5.8.0 milestone May 24, 2017
@TheMarex TheMarex force-pushed the feature/renumber-graph branch from 9628aee to 5c61a92 Compare May 25, 2017 00:29
@TheMarex
Copy link
Member Author

Some tests are failing, need to investigate those.

Copy link
Contributor

@oxidase oxidase left a comment

Choose a reason for hiding this comment

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

LGTM, but some small open questions

for (auto edge : edge_based_graph.GetAdjacentEdgeRange(node))
{
const auto &data = edge_based_graph.GetEdgeData(edge);
max_turn_id = std::max(max_turn_id, data.turn_id);
Copy link
Contributor

Choose a reason for hiding this comment

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

Here can be a data race. It can fixed by

  • max_turn_id is atomic (bad)
  • use thread local values
  • use tbb::parallel_reduce

Copy link
Member Author

Choose a reason for hiding this comment

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

Urg good catch, that was a stupid mistake on my side.

auto target = graph.GetTarget(edge);
if (partition[node] != partition[target])
{
border_level[node] = level;
Copy link
Contributor

Choose a reason for hiding this comment

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

but why not border_level[node] = std::max(border_level[node], level);?
or level is always non-decreasing -> assertion border_level[node] <= level;


for (const auto &partition : partitions)
{
std::stable_sort(
Copy link
Contributor

Choose a reason for hiding this comment

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

please add in words what is this sort is doing and

}

auto border_level = getHighestBorderLevel(graph, partitions);
std::stable_sort(
Copy link
Contributor

Choose a reason for hiding this comment

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

.. what this sort adjusts after the first ordering.

old_to_new_edge[edge] = new_edge_index++;
}
// and all adjacent empty edges
for (auto edge = EndEdges(node); edge < number_of_edges && isDummy(edge); edge++)
Copy link
Contributor

Choose a reason for hiding this comment

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

just don't understand why dummy edges are needed? If it is only to have correct results of GetAdjacentEdgeRange and EndEdges then it is better to make an iteration over node_array directly and remove empty edges.

Copy link
Member Author

Choose a reason for hiding this comment

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

I mainly wanted the renumber operation to not interfere with the structure of the dynamic graph. Removing the dummy edges would compactify the structure but would have non-obvious side-effects like for example InsertEdge would now take O(n) because it needs to resize+copy the edge array and relocate the source node edges.

We might want an additional function shrink_to_fit or something like that, but I don't think we have good use for it right now.

@oxidase
Copy link
Contributor

oxidase commented May 26, 2017

@TheMarex tests fail for CH algorithms only in cases where MLD ordering is really used, probably some CH data also has to be reordered or data preprocessing must be split between CH and MLD steps

EDIT: swapping

queue.defer(this.contractData.bind(this), p);
queue.defer(this.partitionData.bind(this), p);
will "fix" tests, but in general the problem will remain, CH data depends on ordering by graph partitioning

@TheMarex
Copy link
Member Author

tests fail for CH algorithms only in cases where MLD ordering is really used, probably some CH data also has to be reordered or data preprocessing must be split between CH and MLD steps

Ah good point forgot that running contract before partition is also an option. I'll add some code that detects and .hsgr file and reorders it as well if present, to guarantee consistency.

@TheMarex TheMarex force-pushed the feature/renumber-graph branch 2 times, most recently from 4745e0c to 602dd39 Compare May 31, 2017 22:20
@TheMarex
Copy link
Member Author

Did some measurements today:

The memory access pattern for MLD improves significantly: It is concentrated around the low ids which are the border nodes. For CH we see some improved concentration as well. For MLD this translates into speedups, for CH there is no impact as far as I can tell.

Memory acces

Some plots that show the node id space on the x-axis and the time-slice on the y-axis. Basically these are snapshots of the accessed graph nodes very 10000 operations.

CH

Before:
memory_access_ch
After:
memory_access_ch_renumbered

MLD

Before:
memory_access_mld
After:
memory_access_mld_renumbered

Runtime

Left before renumbering, right after renumbering. These are for random routes on Bayern, measuring the whole HTTP request time with osrm-runner.

CH

time_ch

MLD

time_mld

@TheMarex
Copy link
Member Author

TheMarex commented Jun 1, 2017

The only failing test is https://github.com/Project-OSRM/osrm-backend/blob/master/features/testbot/zero-speed-updates.feature#L28 one of the zero-speed segment tests. Curiously it now returns a match. Might be related to the fact that the order in which osrm-contract and osrm-partition are run was changed.

@oxidase
Copy link
Contributor

oxidase commented Jun 1, 2017

@TheMarex ~22% speedup just from renumbering looks really awesome! I have just few remarks:

  • histogram values can be visualized in log-scale otherwise it is almost pure blue pattern
  • it is better to check speedup and access patterns on large-range >1000km qureies
  • zero-speed-updates.feature tests really depends on snapping and renumbering changes nodes order, so either a oneway flag or bearing must be added to the test. Or simply add @todo and "FIXME: Refactor insertion of source and target phantom nodes #4086"

@TheMarex
Copy link
Member Author

TheMarex commented Jun 1, 2017

@oxidase investigated the failing test case:

  1. We start on the reverse node (valid source and target since we only change the weight of 2,3 not 3,2)
  2. We do a u-turn on the forward node (both forward and reverse search)
  3. Search terminates since both forward + reverse search have met

This yields a path that includes an invalid weight.

I don't get how this test case was ever passing. There are only two nodes in the graph, renumbering should not have any effect on the graph structure. Also the rtree snapping is unique in this case since we don't place the coordinates on the nodes but in the middle of the segments.

@oxidase
Copy link
Contributor

oxidase commented Jun 1, 2017

@TheMarex idk atm why the response is Ok instead of NoMatch, basically these tests must be revisited in #4086

In the general a problem may occur if source node is a meeting node than a negative weight value of the source node is used to compute new_weight:

  • If new_weight < 0 the upper bound is ignored
  • new_weight >= 0 than incorrect path can be selected ifreverse_heap.GetKey(node) >= weight

@oxidase
Copy link
Contributor

oxidase commented Jun 2, 2017

@TheMarex is the fix of the failing test here

edges[data.turn_id].data.forward = true;
edges[data.turn_id].data.backward = false;
? It seems the fix is needed also for #4086

@TheMarex
Copy link
Member Author

TheMarex commented Jun 2, 2017

@oxidase #4086 should not be impacted because this bug only manifested when you wrote out the .ebg in osrm-partition again. Basically it was a mismatch between the format that osrm-extract produces and what osrm-partition wrote out after renumbering.

@TheMarex TheMarex force-pushed the feature/renumber-graph branch from 5c7288a to 5076ccd Compare June 2, 2017 15:28
TheMarex added 3 commits June 2, 2017 16:09
The new numbering uses the partition information
to sort border nodes first to compactify storages
that need access indexed by border node ID.

We also get an optimized cache performance for free
sincr we can also recursively sort the nodes by cell ID.

This implements issue #3779.
@TheMarex TheMarex force-pushed the feature/renumber-graph branch from 5076ccd to 6986153 Compare June 2, 2017 16:09
@TheMarex TheMarex merged commit 6c7f0ed into master Jun 2, 2017
@TheMarex TheMarex deleted the feature/renumber-graph branch June 2, 2017 18:12
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.

2 participants