From bf2b45120a15a63d1db426533c40778c858e7325 Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Sun, 8 Apr 2018 16:37:08 +0000 Subject: [PATCH] Use ArrayStorage for boundary nodes to optimize MLD For the MLD algorithm we can partition the NodeID range into boundary and non-boundary nodes. Since there are only we boundary nodes we can use the ArrayStorage for those yielding much faster query times. --- .../datafacade/algorithm_datafacade.hpp | 2 + .../contiguous_internalmem_datafacade.hpp | 2 + .../routing_algorithms/shortest_path_impl.hpp | 21 ++++- include/engine/search_engine_data.hpp | 10 ++- include/partitioner/multi_level_graph.hpp | 8 ++ include/util/query_heap.hpp | 80 +++++++++++++++++-- include/util/xor_fast_hash_storage.hpp | 4 +- .../alternative_path_mld.cpp | 3 +- .../direct_shortest_path.cpp | 3 +- .../routing_algorithms/many_to_many_mld.cpp | 7 +- .../routing_algorithms/map_matching.cpp | 23 +++++- src/engine/search_engine_data.cpp | 12 +-- 12 files changed, 151 insertions(+), 24 deletions(-) diff --git a/include/engine/datafacade/algorithm_datafacade.hpp b/include/engine/datafacade/algorithm_datafacade.hpp index 00e02e0a5..cdf49c286 100644 --- a/include/engine/datafacade/algorithm_datafacade.hpp +++ b/include/engine/datafacade/algorithm_datafacade.hpp @@ -65,6 +65,8 @@ template <> class AlgorithmDataFacade // search graph access virtual unsigned GetNumberOfNodes() const = 0; + virtual unsigned GetMaxBorderNodeID() const = 0; + virtual unsigned GetNumberOfEdges() const = 0; virtual unsigned GetOutDegree(const NodeID n) const = 0; diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 4ec640324..846a1a04c 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -675,6 +675,8 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade : public Algo // search graph access unsigned GetNumberOfNodes() const override final { return query_graph.GetNumberOfNodes(); } + unsigned GetMaxBorderNodeID() const override final { return query_graph.GetMaxBorderNodeID(); } + unsigned GetNumberOfEdges() const override final { return query_graph.GetNumberOfEdges(); } unsigned GetOutDegree(const NodeID n) const override final diff --git a/include/engine/routing_algorithms/shortest_path_impl.hpp b/include/engine/routing_algorithms/shortest_path_impl.hpp index a22661777..0dea19897 100644 --- a/include/engine/routing_algorithms/shortest_path_impl.hpp +++ b/include/engine/routing_algorithms/shortest_path_impl.hpp @@ -207,6 +207,25 @@ void unpackLegs(const DataFacade &facade, phantom_nodes_vector[current_leg].target_phantom.forward_segment_id.id)); } } + +template +inline void initializeHeap(SearchEngineData &engine_working_data, + const DataFacade &facade) +{ + + const auto nodes_number = facade.GetNumberOfNodes(); + engine_working_data.InitializeOrClearFirstThreadLocalStorage(nodes_number); +} + +template <> +inline void initializeHeap(SearchEngineData &engine_working_data, + const DataFacade &facade) +{ + + const auto nodes_number = facade.GetNumberOfNodes(); + const auto border_nodes_number = facade.GetMaxBorderNodeID() + 1; + engine_working_data.InitializeOrClearFirstThreadLocalStorage(nodes_number, border_nodes_number); +} } template @@ -221,7 +240,7 @@ InternalRouteResult shortestPathSearch(SearchEngineData &engine_worki !(continue_straight_at_waypoint ? *continue_straight_at_waypoint : facade.GetContinueStraightDefault()); - engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); + initializeHeap(engine_working_data, facade); auto &forward_heap = *engine_working_data.forward_heap_1; auto &reverse_heap = *engine_working_data.reverse_heap_1; diff --git a/include/engine/search_engine_data.hpp b/include/engine/search_engine_data.hpp index 060599eb7..db2c51224 100644 --- a/include/engine/search_engine_data.hpp +++ b/include/engine/search_engine_data.hpp @@ -91,13 +91,13 @@ template <> struct SearchEngineData NodeID, EdgeWeight, MultiLayerDijkstraHeapData, - util::UnorderedMapStorage>; + util::TwoLevelStorage>; using ManyToManyQueryHeap = util::QueryHeap>; + util::TwoLevelStorage>; using SearchEngineHeapPtr = boost::thread_specific_ptr; using ManyToManyHeapPtr = boost::thread_specific_ptr; @@ -106,9 +106,11 @@ template <> struct SearchEngineData static SearchEngineHeapPtr reverse_heap_1; static ManyToManyHeapPtr many_to_many_heap; - void InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes); + void InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes, + unsigned number_of_boundary_nodes); - void InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes); + void InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes, + unsigned number_of_boundary_nodes); }; } } diff --git a/include/partitioner/multi_level_graph.hpp b/include/partitioner/multi_level_graph.hpp index 2c8c7204c..b652589f6 100644 --- a/include/partitioner/multi_level_graph.hpp +++ b/include/partitioner/multi_level_graph.hpp @@ -138,6 +138,14 @@ class MultiLevelGraph : public util::StaticGraph // We save the level as sentinel at the end LevelID GetNumberOfLevels() const { return node_to_edge_offset.back(); } + NodeID GetMaxBorderNodeID() const + { + auto num_levels = GetNumberOfLevels(); + BOOST_ASSERT((node_to_edge_offset.size() - 1) % num_levels == 0); + auto max_border_node_id = (node_to_edge_offset.size() - 1) / num_levels - 1; + return max_border_node_id; + } + private: template auto GetHighestBorderLevel(const MultiLevelPartition &mlp, const ContainerT &edges) const diff --git a/include/util/query_heap.hpp b/include/util/query_heap.hpp index 779f1f446..9b1152c4f 100644 --- a/include/util/query_heap.hpp +++ b/include/util/query_heap.hpp @@ -20,7 +20,7 @@ template class GenerationArrayStorage using GenerationCounter = std::uint16_t; public: - explicit GenerationArrayStorage(std::size_t size) + explicit GenerationArrayStorage(std::size_t size, std::size_t) : positions(size, 0), generation(1), generations(size, 0) { } @@ -60,7 +60,7 @@ template class GenerationArrayStorage template class ArrayStorage { public: - explicit ArrayStorage(std::size_t size) : positions(size, 0) {} + explicit ArrayStorage(std::size_t size, std::size_t) : positions(size, 0) {} ~ArrayStorage() {} @@ -77,7 +77,7 @@ template class ArrayStorage template class MapStorage { public: - explicit MapStorage(std::size_t) {} + explicit MapStorage(std::size_t, std::size_t) {} Key &operator[](NodeID node) { return nodes[node]; } @@ -100,7 +100,7 @@ template class MapStorage template class UnorderedMapStorage { public: - explicit UnorderedMapStorage(std::size_t) { nodes.rehash(1000); } + explicit UnorderedMapStorage(std::size_t, std::size_t) { nodes.rehash(1000); } Key &operator[](const NodeID node) { return nodes[node]; } @@ -126,6 +126,67 @@ template class UnorderedMapStorage std::unordered_map nodes; }; +template class BaseIndexStorage = UnorderedMapStorage, + template class OverlayIndexStorage = ArrayStorage> +class TwoLevelStorage +{ + public: + explicit TwoLevelStorage(std::size_t number_of_nodes, std::size_t number_of_overlay_nodes) + : number_of_overlay_nodes(number_of_overlay_nodes), base(number_of_nodes, number_of_nodes), + overlay(number_of_overlay_nodes, number_of_overlay_nodes) + { + } + + Key &operator[](const NodeID node) + { + if (node < number_of_overlay_nodes) + { + return overlay[node]; + } + else + { + return base[node]; + } + } + + Key peek_index(const NodeID node) const + { + if (node < number_of_overlay_nodes) + { + return overlay.peek_index(node); + } + else + { + return base.peek_index(node); + } + } + + Key const &operator[](const NodeID node) const + { + if (node < number_of_overlay_nodes) + { + return overlay[node]; + } + else + { + return base[node]; + } + } + + void Clear() + { + base.Clear(); + overlay.Clear(); + } + + private: + const std::size_t number_of_overlay_nodes; + BaseIndexStorage base; + OverlayIndexStorage overlay; +}; + template &sear const Partition &partition = facade.GetMultiLevelPartition(); // Prepare heaps for usage below. The searches will modify them in-place. - search_engine_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); + search_engine_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(), + facade.GetMaxBorderNodeID() + 1); Heap &forward_heap = *search_engine_data.forward_heap_1; Heap &reverse_heap = *search_engine_data.reverse_heap_1; diff --git a/src/engine/routing_algorithms/direct_shortest_path.cpp b/src/engine/routing_algorithms/direct_shortest_path.cpp index 7ba552aeb..182bb7a9e 100644 --- a/src/engine/routing_algorithms/direct_shortest_path.cpp +++ b/src/engine/routing_algorithms/direct_shortest_path.cpp @@ -69,7 +69,8 @@ InternalRouteResult directShortestPathSearch(SearchEngineData &e const DataFacade &facade, const PhantomNodes &phantom_nodes) { - engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); + engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(), + facade.GetMaxBorderNodeID() + 1); auto &forward_heap = *engine_working_data.forward_heap_1; auto &reverse_heap = *engine_working_data.reverse_heap_1; insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes); diff --git a/src/engine/routing_algorithms/many_to_many_mld.cpp b/src/engine/routing_algorithms/many_to_many_mld.cpp index adfccac0d..df9010bfb 100644 --- a/src/engine/routing_algorithms/many_to_many_mld.cpp +++ b/src/engine/routing_algorithms/many_to_many_mld.cpp @@ -258,7 +258,8 @@ std::vector oneToManySearch(SearchEngineData &engine_wo } // Initialize query heap - engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(facade.GetNumberOfNodes()); + engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( + facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1); auto &query_heap = *(engine_working_data.many_to_many_heap); // Check if node is in the destinations list and update weights/durations @@ -465,7 +466,7 @@ std::vector manyToManySearch(SearchEngineData &engine_w const auto &phantom = phantom_nodes[index]; engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( - facade.GetNumberOfNodes()); + facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1); auto &query_heap = *(engine_working_data.many_to_many_heap); if (DIRECTION == FORWARD_DIRECTION) @@ -492,7 +493,7 @@ std::vector manyToManySearch(SearchEngineData &engine_w // Clear heap and insert source nodes engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( - facade.GetNumberOfNodes()); + facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1); auto &query_heap = *(engine_working_data.many_to_many_heap); if (DIRECTION == FORWARD_DIRECTION) diff --git a/src/engine/routing_algorithms/map_matching.cpp b/src/engine/routing_algorithms/map_matching.cpp index 0a7a254fe..7d1b75901 100644 --- a/src/engine/routing_algorithms/map_matching.cpp +++ b/src/engine/routing_algorithms/map_matching.cpp @@ -46,6 +46,25 @@ unsigned getMedianSampleTime(const std::vector ×tamps) std::nth_element(first_elem, median, sample_times.end()); return *median; } + +template +inline void initializeHeap(SearchEngineData &engine_working_data, + const DataFacade &facade) +{ + + const auto nodes_number = facade.GetNumberOfNodes(); + engine_working_data.InitializeOrClearFirstThreadLocalStorage(nodes_number); +} + +template <> +inline void initializeHeap(SearchEngineData &engine_working_data, + const DataFacade &facade) +{ + + const auto nodes_number = facade.GetNumberOfNodes(); + const auto border_nodes_number = facade.GetMaxBorderNodeID() + 1; + engine_working_data.InitializeOrClearFirstThreadLocalStorage(nodes_number, border_nodes_number); +} } template @@ -131,9 +150,7 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, return sub_matchings; } - const auto nodes_number = facade.GetNumberOfNodes(); - engine_working_data.InitializeOrClearFirstThreadLocalStorage(nodes_number); - + initializeHeap(engine_working_data, facade); auto &forward_heap = *engine_working_data.forward_heap_1; auto &reverse_heap = *engine_working_data.reverse_heap_1; diff --git a/src/engine/search_engine_data.cpp b/src/engine/search_engine_data.cpp index 0069db56b..53912d7a1 100644 --- a/src/engine/search_engine_data.cpp +++ b/src/engine/search_engine_data.cpp @@ -96,7 +96,8 @@ SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_1 SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_1; SearchEngineData::ManyToManyHeapPtr SearchEngineData::many_to_many_heap; -void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes) +void SearchEngineData::InitializeOrClearFirstThreadLocalStorage( + unsigned number_of_nodes, unsigned number_of_boundary_nodes) { if (forward_heap_1.get()) { @@ -104,7 +105,7 @@ void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(unsigned nu } else { - forward_heap_1.reset(new QueryHeap(number_of_nodes)); + forward_heap_1.reset(new QueryHeap(number_of_nodes, number_of_boundary_nodes)); } if (reverse_heap_1.get()) @@ -113,11 +114,12 @@ void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(unsigned nu } else { - reverse_heap_1.reset(new QueryHeap(number_of_nodes)); + reverse_heap_1.reset(new QueryHeap(number_of_nodes, number_of_boundary_nodes)); } } -void SearchEngineData::InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes) +void SearchEngineData::InitializeOrClearManyToManyThreadLocalStorage( + unsigned number_of_nodes, unsigned number_of_boundary_nodes) { if (many_to_many_heap.get()) { @@ -125,7 +127,7 @@ void SearchEngineData::InitializeOrClearManyToManyThreadLocalStorage(unsign } else { - many_to_many_heap.reset(new ManyToManyQueryHeap(number_of_nodes)); + many_to_many_heap.reset(new ManyToManyQueryHeap(number_of_nodes, number_of_boundary_nodes)); } } }