Skip to content

Commit 35550d8

Browse files
danpatPatrick Niklaus
authored andcommitted
Parallelize generation of the edge-expanded-edges.
1 parent b68d794 commit 35550d8

File tree

12 files changed

+414
-229
lines changed

12 files changed

+414
-229
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- Added conditional restriction support with `parse-conditional-restrictions=true|false` to osrm-extract. This option saves conditional turn restrictions to the .restrictions file for parsing by contract later. Added `parse-conditionals-from-now=utc time stamp` and `--time-zone-file=/path/to/file` to osrm-contract
1414
- Command-line tools (osrm-extract, osrm-contract, osrm-routed, etc) now return error codes and legible error messages for common problem scenarios, rather than ugly C++ crashes
1515
- Speed up pre-processing by only running the Lua `node_function` for nodes that have tags. Cuts OSM file parsing time in half.
16+
- osrm-extract now performs generation of edge-expanded-edges using all available CPUs, which should make osrm-extract significantly faster on multi-CPU machines
1617
- Files
1718
- .osrm.nodes file was renamed to .nbg_nodes and .ebg_nodes was added
1819
- Guidance

include/extractor/edge_based_graph_factory.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "extractor/query_node.hpp"
1919
#include "extractor/restriction_map.hpp"
2020

21+
#include "util/concurrent_id_map.hpp"
2122
#include "util/deallocating_vector.hpp"
2223
#include "util/guidance/bearing_class.hpp"
2324
#include "util/guidance/entry_class.hpp"
@@ -41,6 +42,9 @@
4142

4243
#include <boost/filesystem/fstream.hpp>
4344

45+
#include <tbb/concurrent_unordered_map.h>
46+
#include <tbb/concurrent_vector.h>
47+
4448
namespace osrm
4549
{
4650
namespace extractor
@@ -167,9 +171,9 @@ class EdgeBasedGraphFactory
167171
std::size_t skipped_uturns_counter;
168172
std::size_t skipped_barrier_turns_counter;
169173

170-
std::unordered_map<util::guidance::BearingClass, BearingClassID> bearing_class_hash;
174+
util::ConcurrentIDMap<util::guidance::BearingClass, BearingClassID> bearing_class_hash;
171175
std::vector<BearingClassID> bearing_class_by_node_based_node;
172-
std::unordered_map<util::guidance::EntryClass, EntryClassID> entry_class_hash;
176+
util::ConcurrentIDMap<util::guidance::EntryClass, EntryClassID> entry_class_hash;
173177
};
174178
} // namespace extractor
175179
} // namespace osrm

include/extractor/guidance/turn_lane_handler.hpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,16 @@ const constexpr char *scenario_names[] = {"Simple",
6565

6666
class TurnLaneHandler
6767
{
68+
using UpgradableMutex = boost::interprocess::interprocess_upgradable_mutex;
69+
using ScopedReaderLock = boost::interprocess::sharable_lock<UpgradableMutex>;
70+
using ScopedWriterLock = boost::interprocess::scoped_lock<UpgradableMutex>;
71+
6872
public:
6973
typedef std::vector<TurnLaneData> LaneDataVector;
7074

7175
TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_graph,
72-
std::vector<std::uint32_t> &turn_lane_offsets,
73-
std::vector<TurnLaneType::Mask> &turn_lane_masks,
76+
const std::vector<std::uint32_t> &turn_lane_offsets,
77+
const std::vector<TurnLaneType::Mask> &turn_lane_masks,
7478
LaneDescriptionMap &lane_description_map,
7579
const TurnAnalysis &turn_analysis,
7680
util::guidance::LaneDataIdMap &id_map);
@@ -86,8 +90,8 @@ class TurnLaneHandler
8690
// we need to be able to look at previous intersections to, in some cases, find the correct turn
8791
// lanes for a turn
8892
const util::NodeBasedDynamicGraph &node_based_graph;
89-
std::vector<std::uint32_t> &turn_lane_offsets;
90-
std::vector<TurnLaneType::Mask> &turn_lane_masks;
93+
const std::vector<std::uint32_t> &turn_lane_offsets;
94+
const std::vector<TurnLaneType::Mask> &turn_lane_masks;
9195
LaneDescriptionMap &lane_description_map;
9296
const TurnAnalysis &turn_analysis;
9397
util::guidance::LaneDataIdMap &id_map;

include/extractor/guidance/turn_lane_types.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <boost/functional/hash.hpp>
1212

13+
#include "util/concurrent_id_map.hpp"
1314
#include "util/json_container.hpp"
1415
#include "util/typedefs.hpp"
1516

@@ -93,9 +94,9 @@ struct TurnLaneDescription_hash
9394
}
9495
};
9596

96-
typedef std::unordered_map<guidance::TurnLaneDescription,
97-
LaneDescriptionID,
98-
guidance::TurnLaneDescription_hash>
97+
typedef util::ConcurrentIDMap<guidance::TurnLaneDescription,
98+
LaneDescriptionID,
99+
guidance::TurnLaneDescription_hash>
99100
LaneDescriptionMap;
100101

101102
} // guidance

include/extractor/turn_data_container.hpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ void write(storage::io::FileWriter &writer,
3131
const detail::TurnDataContainerImpl<Ownership> &turn_data);
3232
}
3333

34+
struct TurnData
35+
{
36+
extractor::guidance::TurnInstruction turn_instruction;
37+
LaneDataID lane_data_id;
38+
EntryClassID entry_class_id;
39+
util::guidance::TurnBearing pre_turn_bearing;
40+
util::guidance::TurnBearing post_turn_bearing;
41+
};
42+
3443
namespace detail
3544
{
3645
template <storage::Ownership Ownership> class TurnDataContainerImpl
@@ -75,17 +84,20 @@ template <storage::Ownership Ownership> class TurnDataContainerImpl
7584

7685
// Used by EdgeBasedGraphFactory to fill data structure
7786
template <typename = std::enable_if<Ownership == storage::Ownership::Container>>
78-
void push_back(extractor::guidance::TurnInstruction turn_instruction,
79-
LaneDataID lane_data_id,
80-
EntryClassID entry_class_id,
81-
util::guidance::TurnBearing pre_turn_bearing,
82-
util::guidance::TurnBearing post_turn_bearing)
87+
void push_back(const TurnData &data)
88+
{
89+
turn_instructions.push_back(data.turn_instruction);
90+
lane_data_ids.push_back(data.lane_data_id);
91+
entry_class_ids.push_back(data.entry_class_id);
92+
pre_turn_bearings.push_back(data.pre_turn_bearing);
93+
post_turn_bearings.push_back(data.post_turn_bearing);
94+
}
95+
96+
template <typename = std::enable_if<Ownership == storage::Ownership::Container>>
97+
void append(const std::vector<TurnData> &others)
8398
{
84-
turn_instructions.push_back(turn_instruction);
85-
lane_data_ids.push_back(lane_data_id);
86-
entry_class_ids.push_back(entry_class_id);
87-
pre_turn_bearings.push_back(pre_turn_bearing);
88-
post_turn_bearings.push_back(post_turn_bearing);
99+
std::for_each(
100+
others.begin(), others.end(), [this](const TurnData &other) { push_back(other); });
89101
}
90102

91103
friend void serialization::read<Ownership>(storage::io::FileReader &reader,

include/util/concurrent_id_map.hpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#ifndef CONCURRENT_ID_MAP_HPP
2+
#define CONCURRENT_ID_MAP_HPP
3+
4+
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
5+
#include <boost/interprocess/sync/scoped_lock.hpp>
6+
#include <boost/interprocess/sync/sharable_lock.hpp>
7+
8+
#include <unordered_map>
9+
10+
namespace osrm
11+
{
12+
namespace util
13+
{
14+
15+
/**
16+
* This is a special purpose map for caching incrementing IDs
17+
*/
18+
template <typename KeyType, typename ValueType, typename HashType = std::hash<KeyType>>
19+
struct ConcurrentIDMap
20+
{
21+
static_assert(std::is_unsigned<ValueType>::value, "Only unsigned integer types are supported.");
22+
23+
using UpgradableMutex = boost::interprocess::interprocess_upgradable_mutex;
24+
using ScopedReaderLock = boost::interprocess::sharable_lock<UpgradableMutex>;
25+
using ScopedWriterLock = boost::interprocess::scoped_lock<UpgradableMutex>;
26+
27+
std::unordered_map<KeyType, ValueType, HashType> data;
28+
mutable UpgradableMutex mutex;
29+
30+
const ValueType ConcurrentFindOrAdd(const KeyType &key)
31+
{
32+
{
33+
ScopedReaderLock sentry{mutex};
34+
const auto result = data.find(key);
35+
if (result != data.end())
36+
{
37+
return result->second;
38+
}
39+
}
40+
{
41+
ScopedWriterLock sentry{mutex};
42+
const auto result = data.find(key);
43+
if (result != data.end())
44+
{
45+
return result->second;
46+
}
47+
const auto id = static_cast<ValueType>(data.size());
48+
data[key] = id;
49+
return id;
50+
}
51+
}
52+
};
53+
54+
} // util
55+
} // osrm
56+
57+
#endif // CONCURRENT_ID_MAP_HPP

include/util/guidance/turn_lanes.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <unordered_map>
88
#include <vector>
99

10+
#include "util/concurrent_id_map.hpp"
1011
#include "util/typedefs.hpp"
1112

1213
#include <boost/functional/hash.hpp>
@@ -97,7 +98,7 @@ class LaneTupleIdPair
9798
}
9899
};
99100

100-
using LaneDataIdMap = std::unordered_map<LaneTupleIdPair, LaneDataID, boost::hash<LaneTupleIdPair>>;
101+
using LaneDataIdMap = ConcurrentIDMap<LaneTupleIdPair, LaneDataID, boost::hash<LaneTupleIdPair>>;
101102

102103
} // namespace guidance
103104
} // namespace util

0 commit comments

Comments
 (0)