Skip to content

Commit 79fe909

Browse files
fix(mem usage): XORFastHash lost lines (#7456)
1 parent b066f6a commit 79fe909

5 files changed

Lines changed: 65 additions & 29 deletions

File tree

include/contractor/contractor_search.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,29 @@
1111
namespace osrm::contractor
1212
{
1313

14+
/**
15+
* Stop search after this many settled nodes during contraction simulation.
16+
*/
17+
constexpr std::size_t SIMULATION_SEARCH_SPACE_SIZE = 1000;
18+
/**
19+
* Stop search after this many settled nodes during contraction. Tuning parameter:
20+
* Bigger search space is slower but may produce smaller contracted graph.
21+
*/
22+
constexpr std::size_t FULL_SEARCH_SPACE_SIZE = 2000;
23+
/**
24+
* Size of the contractor heap storage. Bigger heap storage is faster but increases
25+
* memory consumption. Must be a power of two.
26+
*/
27+
constexpr std::size_t HASH_MAP_CAPACITY = 1u << 13;
28+
29+
static_assert((HASH_MAP_CAPACITY & (HASH_MAP_CAPACITY - 1)) == 0,
30+
"HASH_MAP_CAPACITY must be a power of two");
31+
/**
32+
* Stop search after this many relaxed nodes during contraction. Protection against heap
33+
* storage overflow. Must be less than HASH_MAP_CAPACITY. Should be 50-75% of HASH_MAP_CAPACITY.
34+
*/
35+
constexpr std::size_t RELAXED_NODE_LIMIT = HASH_MAP_CAPACITY * 0.75;
36+
1437
void search(ContractorHeap &heap,
1538
const ContractorGraph &graph,
1639
const std::vector<bool> &contractable,

include/util/linear_hash_storage.hpp

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
#define LINEAR_HASH_STORAGE
33

44
#include <concepts>
5+
#include <cstddef>
56
#include <cstdlib>
67
#include <limits>
78
#include <vector>
89

10+
#include <boost/assert.hpp>
11+
912
namespace osrm::util
1013
{
1114

@@ -45,25 +48,13 @@ class LinearHashStorage
4548
};
4649

4750
std::vector<HashCell> cells;
48-
unsigned current_timestamp;
51+
unsigned current_timestamp{0u};
4952
std::size_t mask;
5053

5154
public:
52-
explicit LinearHashStorage(std::size_t size) : current_timestamp{0u}
55+
explicit LinearHashStorage(std::size_t size) : cells(size), mask{size - 1}
5356
{
54-
// round up to the next power of two
55-
// See: Figure 3.3 in Warren Henry S., Hacker's Delight, 2nd ed., Pearson 2013
56-
--size;
57-
size = size | (size >> 1);
58-
size = size | (size >> 2);
59-
size = size | (size >> 4);
60-
size = size | (size >> 8);
61-
size = size | (size >> 16);
62-
size = size | (size >> 32);
63-
mask = size;
64-
++size;
65-
66-
cells.resize(size);
57+
BOOST_ASSERT_MSG((size & mask) == 0, "size must be a power of 2");
6758
}
6859

6960
ValueType &operator[](const KeyType key)

include/util/query_heap.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
#include "d_ary_heap.hpp"
88
#include <algorithm>
9+
#include <cstddef>
910
#include <limits>
10-
#include <optional>
1111
#include <unordered_map>
1212
#include <vector>
1313

@@ -168,10 +168,15 @@ class QueryHeap
168168
heap.clear();
169169
inserted_nodes.clear();
170170
node_index.Clear();
171+
occupancy = 0;
171172
}
172173

174+
/** Returns the number of nodes currently in the heap. */
173175
std::size_t Size() const { return heap.size(); }
174176

177+
/** Returns the total number of nodes inserted into the heap storage. */
178+
std::size_t Occupancy() const { return occupancy; }
179+
175180
bool Empty() const { return 0 == Size(); }
176181

177182
void Insert(NodeID node, Weight weight, const Data &data)
@@ -186,6 +191,7 @@ class QueryHeap
186191
[this](const auto &heapData, auto new_handle)
187192
{ inserted_nodes[heapData.index].handle = new_handle; });
188193
node_index[node] = index;
194+
++occupancy;
189195

190196
checkInvariants();
191197
}
@@ -337,6 +343,7 @@ class QueryHeap
337343
std::vector<HeapNode> inserted_nodes;
338344
HeapContainer heap;
339345
IndexStorage node_index;
346+
std::size_t occupancy{0};
340347
};
341348

342349
} // namespace osrm::util

src/contractor/contractor_search.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace osrm::contractor
88

99
namespace
1010
{
11-
void relaxNode(ContractorHeap &heap,
11+
bool relaxNode(ContractorHeap &heap,
1212
const ContractorGraph &graph,
1313
const std::vector<bool> &contractable,
1414
const NodeID node,
@@ -39,6 +39,8 @@ void relaxNode(ContractorHeap &heap,
3939
{
4040
continue;
4141
}
42+
if (heap.Occupancy() >= RELAXED_NODE_LIMIT)
43+
return true; // stop search
4244
heap.Insert(to, to_weight, ContractorHeapData{current_hop, false});
4345
}
4446
// Found a shorter Path -> Update weight
@@ -49,25 +51,26 @@ void relaxNode(ContractorHeap &heap,
4951
toHeapNode->data.hop = current_hop;
5052
}
5153
}
54+
return false;
5255
}
5356
} // namespace
5457

5558
void search(ContractorHeap &heap,
5659
const ContractorGraph &graph,
5760
const std::vector<bool> &contractable,
5861
const unsigned number_of_targets,
59-
const int node_limit,
62+
const int settled_node_limit,
6063
const EdgeWeight weight_limit,
6164
const NodeID forbidden_node)
6265
{
63-
int nodes = 0;
66+
int settled_nodes = 0;
6467
unsigned number_of_targets_found = 0;
6568
while (!heap.Empty())
6669
{
6770
const NodeID node = heap.DeleteMin();
6871
BOOST_ASSERT(node != SPECIAL_NODEID);
6972
const auto node_weight = heap.GetKey(node);
70-
if (++nodes > node_limit)
73+
if (++settled_nodes > settled_node_limit)
7174
{
7275
return;
7376
}
@@ -85,8 +88,8 @@ void search(ContractorHeap &heap,
8588
return;
8689
}
8790
}
88-
89-
relaxNode(heap, graph, contractable, node, node_weight, forbidden_node);
91+
if (relaxNode(heap, graph, contractable, node, node_weight, forbidden_node))
92+
return;
9093
}
9194
}
9295
} // namespace osrm::contractor

src/contractor/graph_contractor.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <boost/assert.hpp>
1414

15+
#include <cstddef>
1516
#include <tbb/blocked_range.h>
1617
#include <tbb/enumerable_thread_specific.h>
1718
#include <tbb/parallel_for.h>
@@ -33,6 +34,8 @@ struct ContractorThreadData
3334
std::vector<ContractorEdge> inserted_edges;
3435
std::vector<NodeID> neighbours;
3536
explicit ContractorThreadData(NodeID nodes) : heap(nodes) {}
37+
/** Code instrumentation: the max. occupancy of the heap */
38+
std::size_t max_heap_occupancy{0};
3639
};
3740

3841
struct ContractorNodeData
@@ -98,21 +101,19 @@ struct RemainingNodeData
98101

99102
struct ThreadDataContainer
100103
{
101-
explicit ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes) {}
104+
explicit ThreadDataContainer() {}
102105

103106
inline ContractorThreadData *GetThreadData()
104107
{
105108
bool exists = false;
106109
auto &ref = data.local(exists);
107110
if (!exists)
108111
{
109-
ref = std::make_shared<ContractorThreadData>(number_of_nodes);
112+
ref = std::make_shared<ContractorThreadData>(HASH_MAP_CAPACITY);
110113
}
111114

112115
return ref.get();
113116
}
114-
115-
int number_of_nodes;
116117
using EnumerableThreadData =
117118
tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>>;
118119
EnumerableThreadData data;
@@ -230,7 +231,6 @@ void ContractNode(ContractorThreadData *data,
230231

231232
if (RUNSIMULATION)
232233
{
233-
const int constexpr SIMULATION_SEARCH_SPACE_SIZE = 1000;
234234
search(heap,
235235
graph,
236236
contractable,
@@ -241,7 +241,6 @@ void ContractNode(ContractorThreadData *data,
241241
}
242242
else
243243
{
244-
const int constexpr FULL_SEARCH_SPACE_SIZE = 2000;
245244
search(heap,
246245
graph,
247246
contractable,
@@ -298,6 +297,7 @@ void ContractNode(ContractorThreadData *data,
298297
}
299298
}
300299
}
300+
data->max_heap_occupancy = std::max(heap.Occupancy(), data->max_heap_occupancy);
301301
}
302302

303303
// Check For One-Way Streets to decide on the creation of self-loops
@@ -567,7 +567,7 @@ std::vector<bool> contractGraph(ContractorGraph &graph,
567567

568568
const NodeID number_of_nodes = graph.GetNumberOfNodes();
569569

570-
ThreadDataContainer thread_data_list(number_of_nodes);
570+
ThreadDataContainer thread_data_list;
571571

572572
NodeID number_of_contracted_nodes = 0;
573573
std::vector<NodeID> new_to_old_node_id(number_of_nodes);
@@ -757,6 +757,18 @@ std::vector<bool> contractGraph(ContractorGraph &graph,
757757
node_data.Renumber(new_to_old_node_id);
758758
RenumberGraph(graph, new_to_old_node_id);
759759

760+
std::size_t max_heap_occupancy = 0;
761+
for (auto &data : thread_data_list.data.range())
762+
{
763+
max_heap_occupancy = std::max(max_heap_occupancy, data->max_heap_occupancy);
764+
}
765+
util::Log(logDEBUG) << "Max. heap occupancy = " << max_heap_occupancy;
766+
if (max_heap_occupancy >= RELAXED_NODE_LIMIT)
767+
{
768+
util::Log(logWARNING) << "Heap size insufficient. Please increase HASH_MAP_CAPACITY and "
769+
"recompile and/or open an issue on github.";
770+
}
771+
760772
return std::move(node_data.is_core);
761773
}
762774

0 commit comments

Comments
 (0)