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.
This commit is contained in:
Patrick Niklaus 2018-04-08 16:37:08 +00:00 committed by Patrick Niklaus
parent 7edf0f218c
commit bf2b45120a
12 changed files with 151 additions and 24 deletions

View File

@ -65,6 +65,8 @@ template <> class AlgorithmDataFacade<MLD>
// search graph access // search graph access
virtual unsigned GetNumberOfNodes() const = 0; virtual unsigned GetNumberOfNodes() const = 0;
virtual unsigned GetMaxBorderNodeID() const = 0;
virtual unsigned GetNumberOfEdges() const = 0; virtual unsigned GetNumberOfEdges() const = 0;
virtual unsigned GetOutDegree(const NodeID n) const = 0; virtual unsigned GetOutDegree(const NodeID n) const = 0;

View File

@ -675,6 +675,8 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public Algo
// search graph access // search graph access
unsigned GetNumberOfNodes() const override final { return query_graph.GetNumberOfNodes(); } 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 GetNumberOfEdges() const override final { return query_graph.GetNumberOfEdges(); }
unsigned GetOutDegree(const NodeID n) const override final unsigned GetOutDegree(const NodeID n) const override final

View File

@ -207,6 +207,25 @@ void unpackLegs(const DataFacade<Algorithm> &facade,
phantom_nodes_vector[current_leg].target_phantom.forward_segment_id.id)); phantom_nodes_vector[current_leg].target_phantom.forward_segment_id.id));
} }
} }
template <typename Algorithm>
inline void initializeHeap(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade)
{
const auto nodes_number = facade.GetNumberOfNodes();
engine_working_data.InitializeOrClearFirstThreadLocalStorage(nodes_number);
}
template <>
inline void initializeHeap<mld::Algorithm>(SearchEngineData<mld::Algorithm> &engine_working_data,
const DataFacade<mld::Algorithm> &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 <typename Algorithm> template <typename Algorithm>
@ -221,7 +240,7 @@ InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_worki
!(continue_straight_at_waypoint ? *continue_straight_at_waypoint !(continue_straight_at_waypoint ? *continue_straight_at_waypoint
: facade.GetContinueStraightDefault()); : facade.GetContinueStraightDefault());
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes()); initializeHeap(engine_working_data, facade);
auto &forward_heap = *engine_working_data.forward_heap_1; auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1; auto &reverse_heap = *engine_working_data.reverse_heap_1;

View File

@ -91,13 +91,13 @@ template <> struct SearchEngineData<routing_algorithms::mld::Algorithm>
NodeID, NodeID,
EdgeWeight, EdgeWeight,
MultiLayerDijkstraHeapData, MultiLayerDijkstraHeapData,
util::UnorderedMapStorage<NodeID, int>>; util::TwoLevelStorage<NodeID, int>>;
using ManyToManyQueryHeap = util::QueryHeap<NodeID, using ManyToManyQueryHeap = util::QueryHeap<NodeID,
NodeID, NodeID,
EdgeWeight, EdgeWeight,
ManyToManyMultiLayerDijkstraHeapData, ManyToManyMultiLayerDijkstraHeapData,
util::UnorderedMapStorage<NodeID, int>>; util::TwoLevelStorage<NodeID, int>>;
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>; using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
using ManyToManyHeapPtr = boost::thread_specific_ptr<ManyToManyQueryHeap>; using ManyToManyHeapPtr = boost::thread_specific_ptr<ManyToManyQueryHeap>;
@ -106,9 +106,11 @@ template <> struct SearchEngineData<routing_algorithms::mld::Algorithm>
static SearchEngineHeapPtr reverse_heap_1; static SearchEngineHeapPtr reverse_heap_1;
static ManyToManyHeapPtr many_to_many_heap; 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);
}; };
} }
} }

View File

@ -138,6 +138,14 @@ class MultiLevelGraph : public util::StaticGraph<EdgeDataT, Ownership>
// We save the level as sentinel at the end // We save the level as sentinel at the end
LevelID GetNumberOfLevels() const { return node_to_edge_offset.back(); } 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: private:
template <typename ContainerT> template <typename ContainerT>
auto GetHighestBorderLevel(const MultiLevelPartition &mlp, const ContainerT &edges) const auto GetHighestBorderLevel(const MultiLevelPartition &mlp, const ContainerT &edges) const

View File

@ -20,7 +20,7 @@ template <typename NodeID, typename Key> class GenerationArrayStorage
using GenerationCounter = std::uint16_t; using GenerationCounter = std::uint16_t;
public: public:
explicit GenerationArrayStorage(std::size_t size) explicit GenerationArrayStorage(std::size_t size, std::size_t)
: positions(size, 0), generation(1), generations(size, 0) : positions(size, 0), generation(1), generations(size, 0)
{ {
} }
@ -60,7 +60,7 @@ template <typename NodeID, typename Key> class GenerationArrayStorage
template <typename NodeID, typename Key> class ArrayStorage template <typename NodeID, typename Key> class ArrayStorage
{ {
public: public:
explicit ArrayStorage(std::size_t size) : positions(size, 0) {} explicit ArrayStorage(std::size_t size, std::size_t) : positions(size, 0) {}
~ArrayStorage() {} ~ArrayStorage() {}
@ -77,7 +77,7 @@ template <typename NodeID, typename Key> class ArrayStorage
template <typename NodeID, typename Key> class MapStorage template <typename NodeID, typename Key> class MapStorage
{ {
public: public:
explicit MapStorage(std::size_t) {} explicit MapStorage(std::size_t, std::size_t) {}
Key &operator[](NodeID node) { return nodes[node]; } Key &operator[](NodeID node) { return nodes[node]; }
@ -100,7 +100,7 @@ template <typename NodeID, typename Key> class MapStorage
template <typename NodeID, typename Key> class UnorderedMapStorage template <typename NodeID, typename Key> class UnorderedMapStorage
{ {
public: 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]; } Key &operator[](const NodeID node) { return nodes[node]; }
@ -126,6 +126,67 @@ template <typename NodeID, typename Key> class UnorderedMapStorage
std::unordered_map<NodeID, Key> nodes; std::unordered_map<NodeID, Key> nodes;
}; };
template <typename NodeID,
typename Key,
template <typename N, typename K> class BaseIndexStorage = UnorderedMapStorage,
template <typename N, typename K> 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<NodeID, Key> base;
OverlayIndexStorage<NodeID, Key> overlay;
};
template <typename NodeID, template <typename NodeID,
typename Key, typename Key,
typename Weight, typename Weight,
@ -137,7 +198,16 @@ class QueryHeap
using WeightType = Weight; using WeightType = Weight;
using DataType = Data; using DataType = Data;
explicit QueryHeap(std::size_t maxID) : node_index(maxID) { Clear(); } explicit QueryHeap(std::size_t number_of_elements, std::size_t number_of_overlay_nodes)
: node_index(number_of_elements, number_of_overlay_nodes)
{
Clear();
}
explicit QueryHeap(std::size_t number_of_elements)
: QueryHeap(number_of_elements, number_of_elements)
{
}
void Clear() void Clear()
{ {

View File

@ -31,7 +31,9 @@ class XORFastHashStorage
void operator=(const Key key_to_insert) { key = key_to_insert; } void operator=(const Key key_to_insert) { key = key_to_insert; }
}; };
explicit XORFastHashStorage(size_t) : positions(MaxNumElements), current_timestamp{0u} {} explicit XORFastHashStorage(size_t, size_t) : positions(MaxNumElements), current_timestamp{0u}
{
}
HashCell &operator[](const NodeID node) HashCell &operator[](const NodeID node)
{ {

View File

@ -700,7 +700,8 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
const Partition &partition = facade.GetMultiLevelPartition(); const Partition &partition = facade.GetMultiLevelPartition();
// Prepare heaps for usage below. The searches will modify them in-place. // 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 &forward_heap = *search_engine_data.forward_heap_1;
Heap &reverse_heap = *search_engine_data.reverse_heap_1; Heap &reverse_heap = *search_engine_data.reverse_heap_1;

View File

@ -69,7 +69,8 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &e
const DataFacade<mld::Algorithm> &facade, const DataFacade<mld::Algorithm> &facade,
const PhantomNodes &phantom_nodes) 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 &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1; auto &reverse_heap = *engine_working_data.reverse_heap_1;
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes); insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);

View File

@ -258,7 +258,8 @@ std::vector<EdgeDuration> oneToManySearch(SearchEngineData<Algorithm> &engine_wo
} }
// Initialize query heap // 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); auto &query_heap = *(engine_working_data.many_to_many_heap);
// Check if node is in the destinations list and update weights/durations // Check if node is in the destinations list and update weights/durations
@ -465,7 +466,7 @@ std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_w
const auto &phantom = phantom_nodes[index]; const auto &phantom = phantom_nodes[index];
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
facade.GetNumberOfNodes()); facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
auto &query_heap = *(engine_working_data.many_to_many_heap); auto &query_heap = *(engine_working_data.many_to_many_heap);
if (DIRECTION == FORWARD_DIRECTION) if (DIRECTION == FORWARD_DIRECTION)
@ -492,7 +493,7 @@ std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_w
// Clear heap and insert source nodes // Clear heap and insert source nodes
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage( engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
facade.GetNumberOfNodes()); facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
auto &query_heap = *(engine_working_data.many_to_many_heap); auto &query_heap = *(engine_working_data.many_to_many_heap);
if (DIRECTION == FORWARD_DIRECTION) if (DIRECTION == FORWARD_DIRECTION)

View File

@ -46,6 +46,25 @@ unsigned getMedianSampleTime(const std::vector<unsigned> &timestamps)
std::nth_element(first_elem, median, sample_times.end()); std::nth_element(first_elem, median, sample_times.end());
return *median; return *median;
} }
template <typename Algorithm>
inline void initializeHeap(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade)
{
const auto nodes_number = facade.GetNumberOfNodes();
engine_working_data.InitializeOrClearFirstThreadLocalStorage(nodes_number);
}
template <>
inline void initializeHeap<mld::Algorithm>(SearchEngineData<mld::Algorithm> &engine_working_data,
const DataFacade<mld::Algorithm> &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 <typename Algorithm> template <typename Algorithm>
@ -131,9 +150,7 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
return sub_matchings; return sub_matchings;
} }
const auto nodes_number = facade.GetNumberOfNodes(); initializeHeap(engine_working_data, facade);
engine_working_data.InitializeOrClearFirstThreadLocalStorage(nodes_number);
auto &forward_heap = *engine_working_data.forward_heap_1; auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1; auto &reverse_heap = *engine_working_data.reverse_heap_1;

View File

@ -96,7 +96,8 @@ SearchEngineData<MLD>::SearchEngineHeapPtr SearchEngineData<MLD>::forward_heap_1
SearchEngineData<MLD>::SearchEngineHeapPtr SearchEngineData<MLD>::reverse_heap_1; SearchEngineData<MLD>::SearchEngineHeapPtr SearchEngineData<MLD>::reverse_heap_1;
SearchEngineData<MLD>::ManyToManyHeapPtr SearchEngineData<MLD>::many_to_many_heap; SearchEngineData<MLD>::ManyToManyHeapPtr SearchEngineData<MLD>::many_to_many_heap;
void SearchEngineData<MLD>::InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes) void SearchEngineData<MLD>::InitializeOrClearFirstThreadLocalStorage(
unsigned number_of_nodes, unsigned number_of_boundary_nodes)
{ {
if (forward_heap_1.get()) if (forward_heap_1.get())
{ {
@ -104,7 +105,7 @@ void SearchEngineData<MLD>::InitializeOrClearFirstThreadLocalStorage(unsigned nu
} }
else 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()) if (reverse_heap_1.get())
@ -113,11 +114,12 @@ void SearchEngineData<MLD>::InitializeOrClearFirstThreadLocalStorage(unsigned nu
} }
else 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<MLD>::InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes) void SearchEngineData<MLD>::InitializeOrClearManyToManyThreadLocalStorage(
unsigned number_of_nodes, unsigned number_of_boundary_nodes)
{ {
if (many_to_many_heap.get()) if (many_to_many_heap.get())
{ {
@ -125,7 +127,7 @@ void SearchEngineData<MLD>::InitializeOrClearManyToManyThreadLocalStorage(unsign
} }
else 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));
} }
} }
} }