Make LeafNode aligned to memory pages.
Changes: * LeafNode is aligned to LEAF_PAGE_SIZE. Alignment brings 24 bytes memory overhead for 4096, but reduces cache misses rate. * Unused m_element_count from leaf nodes file. The size is computed as m_leaves_region.size() / LEAF_PAGE_SIZE. * Added try/catch for mmap exceptions messages.
This commit is contained in:
parent
8849015bbf
commit
2acde49f0f
@ -44,7 +44,7 @@ template <class EdgeDataT,
|
|||||||
class CoordinateListT = std::vector<Coordinate>,
|
class CoordinateListT = std::vector<Coordinate>,
|
||||||
bool UseSharedMemory = false,
|
bool UseSharedMemory = false,
|
||||||
std::uint32_t BRANCHING_FACTOR = 128,
|
std::uint32_t BRANCHING_FACTOR = 128,
|
||||||
std::uint32_t LEAF_NODE_SIZE = 128>
|
std::uint32_t LEAF_PAGE_SIZE = 4096>
|
||||||
class StaticRTree
|
class StaticRTree
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -52,6 +52,10 @@ class StaticRTree
|
|||||||
using EdgeData = EdgeDataT;
|
using EdgeData = EdgeDataT;
|
||||||
using CoordinateList = CoordinateListT;
|
using CoordinateList = CoordinateListT;
|
||||||
|
|
||||||
|
static_assert(LEAF_PAGE_SIZE >= sizeof(uint32_t) + sizeof(EdgeDataT), "LEAF_PAGE_SIZE is too small");
|
||||||
|
static_assert(((LEAF_PAGE_SIZE - 1) & LEAF_PAGE_SIZE) == 0, "LEAF_PAGE_SIZE is not a power of 2");
|
||||||
|
static constexpr std::uint32_t LEAF_NODE_SIZE = (LEAF_PAGE_SIZE - sizeof(uint32_t)) / sizeof(EdgeDataT);
|
||||||
|
|
||||||
struct CandidateSegment
|
struct CandidateSegment
|
||||||
{
|
{
|
||||||
Coordinate fixed_projected_coordinate;
|
Coordinate fixed_projected_coordinate;
|
||||||
@ -72,7 +76,9 @@ class StaticRTree
|
|||||||
LeafNode() : object_count(0), objects() {}
|
LeafNode() : object_count(0), objects() {}
|
||||||
uint32_t object_count;
|
uint32_t object_count;
|
||||||
std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
|
std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
|
||||||
|
unsigned char leaf_page_padding[LEAF_PAGE_SIZE - sizeof(object_count) - sizeof(objects)];
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(LeafNode) == LEAF_PAGE_SIZE, "LeafNode size does not fit the page size");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct WrappedInputElement
|
struct WrappedInputElement
|
||||||
@ -110,8 +116,6 @@ class StaticRTree
|
|||||||
};
|
};
|
||||||
|
|
||||||
typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
|
typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
|
||||||
uint64_t m_element_count;
|
|
||||||
const std::string m_leaf_node_filename;
|
|
||||||
std::shared_ptr<CoordinateListT> m_coordinate_list;
|
std::shared_ptr<CoordinateListT> m_coordinate_list;
|
||||||
|
|
||||||
boost::iostreams::mapped_file_source m_leaves_region;
|
boost::iostreams::mapped_file_source m_leaves_region;
|
||||||
@ -128,13 +132,13 @@ class StaticRTree
|
|||||||
const std::string &tree_node_filename,
|
const std::string &tree_node_filename,
|
||||||
const std::string &leaf_node_filename,
|
const std::string &leaf_node_filename,
|
||||||
const std::vector<CoordinateT> &coordinate_list)
|
const std::vector<CoordinateT> &coordinate_list)
|
||||||
: m_element_count(input_data_vector.size())
|
|
||||||
{
|
{
|
||||||
std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
|
const uint64_t element_count = input_data_vector.size();
|
||||||
|
std::vector<WrappedInputElement> input_wrapper_vector(element_count);
|
||||||
|
|
||||||
// generate auxiliary vector of hilbert-values
|
// generate auxiliary vector of hilbert-values
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
tbb::blocked_range<uint64_t>(0, m_element_count),
|
tbb::blocked_range<uint64_t>(0, element_count),
|
||||||
[&input_data_vector, &input_wrapper_vector,
|
[&input_data_vector, &input_wrapper_vector,
|
||||||
&coordinate_list](const tbb::blocked_range<uint64_t> &range)
|
&coordinate_list](const tbb::blocked_range<uint64_t> &range)
|
||||||
{
|
{
|
||||||
@ -162,7 +166,6 @@ class StaticRTree
|
|||||||
|
|
||||||
// open leaf file
|
// open leaf file
|
||||||
boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
|
boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
|
||||||
leaf_node_file.write((char *)&m_element_count, sizeof(uint64_t));
|
|
||||||
|
|
||||||
// sort the hilbert-value representatives
|
// sort the hilbert-value representatives
|
||||||
tbb::parallel_sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
|
tbb::parallel_sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
|
||||||
@ -170,7 +173,7 @@ class StaticRTree
|
|||||||
|
|
||||||
// pack M elements into leaf node and write to leaf file
|
// pack M elements into leaf node and write to leaf file
|
||||||
uint64_t processed_objects_count = 0;
|
uint64_t processed_objects_count = 0;
|
||||||
while (processed_objects_count < m_element_count)
|
while (processed_objects_count < element_count)
|
||||||
{
|
{
|
||||||
|
|
||||||
LeafNode current_leaf;
|
LeafNode current_leaf;
|
||||||
@ -178,7 +181,7 @@ class StaticRTree
|
|||||||
for (std::uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
|
for (std::uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
|
||||||
++current_element_index)
|
++current_element_index)
|
||||||
{
|
{
|
||||||
if (m_element_count > (processed_objects_count + current_element_index))
|
if (element_count > (processed_objects_count + current_element_index))
|
||||||
{
|
{
|
||||||
std::uint32_t index_of_next_object =
|
std::uint32_t index_of_next_object =
|
||||||
input_wrapper_vector[processed_objects_count + current_element_index]
|
input_wrapper_vector[processed_objects_count + current_element_index]
|
||||||
@ -267,16 +270,12 @@ class StaticRTree
|
|||||||
tree_node_file.write((char *)&size_of_tree, sizeof(std::uint32_t));
|
tree_node_file.write((char *)&size_of_tree, sizeof(std::uint32_t));
|
||||||
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree);
|
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree);
|
||||||
|
|
||||||
m_leaves_region.open(leaf_node_filename);
|
MapLeafNodesFile(leaf_node_filename);
|
||||||
std::uint64_t num_leaves = reinterpret_cast<const std::uint64_t*>(m_leaves_region.data())[0];
|
|
||||||
const char* m_leaves_begin = m_leaves_region.data() + sizeof(std::uint64_t);
|
|
||||||
m_leaves.reset(reinterpret_cast<const LeafNode*>(m_leaves_begin), num_leaves);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit StaticRTree(const boost::filesystem::path &node_file,
|
explicit StaticRTree(const boost::filesystem::path &node_file,
|
||||||
const boost::filesystem::path &leaf_file,
|
const boost::filesystem::path &leaf_file,
|
||||||
const std::shared_ptr<CoordinateListT> coordinate_list)
|
const std::shared_ptr<CoordinateListT> coordinate_list)
|
||||||
: m_leaf_node_filename(leaf_file.string())
|
|
||||||
{
|
{
|
||||||
// open tree node file and load into RAM.
|
// open tree node file and load into RAM.
|
||||||
m_coordinate_list = coordinate_list;
|
m_coordinate_list = coordinate_list;
|
||||||
@ -300,43 +299,29 @@ class StaticRTree
|
|||||||
tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size);
|
tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// open leaf node file and store thread specific pointer
|
MapLeafNodesFile(leaf_file);
|
||||||
if (!boost::filesystem::exists(leaf_file))
|
|
||||||
{
|
|
||||||
throw exception("mem index file does not exist");
|
|
||||||
}
|
|
||||||
if (0 == boost::filesystem::file_size(leaf_file))
|
|
||||||
{
|
|
||||||
throw exception("mem index file is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_leaves_region.open(leaf_file);
|
|
||||||
std::uint64_t num_leaves = reinterpret_cast<const std::uint64_t*>(m_leaves_region.data())[0];
|
|
||||||
const char* m_leaves_begin = m_leaves_region.data() + sizeof(std::uint64_t);
|
|
||||||
m_leaves.reset(reinterpret_cast<const LeafNode*>(m_leaves_begin), num_leaves);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit StaticRTree(TreeNode *tree_node_ptr,
|
explicit StaticRTree(TreeNode *tree_node_ptr,
|
||||||
const uint64_t number_of_nodes,
|
const uint64_t number_of_nodes,
|
||||||
const boost::filesystem::path &leaf_file,
|
const boost::filesystem::path &leaf_file,
|
||||||
std::shared_ptr<CoordinateListT> coordinate_list)
|
std::shared_ptr<CoordinateListT> coordinate_list)
|
||||||
: m_search_tree(tree_node_ptr, number_of_nodes),
|
: m_search_tree(tree_node_ptr, number_of_nodes)
|
||||||
m_coordinate_list(std::move(coordinate_list))
|
, m_coordinate_list(std::move(coordinate_list))
|
||||||
{
|
{
|
||||||
// open leaf node file and store thread specific pointer
|
MapLeafNodesFile(leaf_file);
|
||||||
if (!boost::filesystem::exists(leaf_file))
|
|
||||||
{
|
|
||||||
throw exception("mem index file does not exist");
|
|
||||||
}
|
|
||||||
if (0 == boost::filesystem::file_size(leaf_file))
|
|
||||||
{
|
|
||||||
throw exception("mem index file is empty");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapLeafNodesFile(const boost::filesystem::path &leaf_file)
|
||||||
|
{
|
||||||
|
// open leaf node file and return a pointer to the mapped leaves data
|
||||||
|
try {
|
||||||
m_leaves_region.open(leaf_file);
|
m_leaves_region.open(leaf_file);
|
||||||
std::uint64_t num_leaves = reinterpret_cast<const std::uint64_t*>(m_leaves_region.data())[0];
|
std::size_t num_leaves = m_leaves_region.size() / sizeof(LeafNode);
|
||||||
const char* m_leaves_begin = m_leaves_region.data() + sizeof(std::uint64_t);
|
m_leaves.reset(reinterpret_cast<const LeafNode*>(m_leaves_region.data()), num_leaves);
|
||||||
m_leaves.reset(reinterpret_cast<const LeafNode*>(m_leaves_begin), num_leaves);
|
} catch (std::exception& exc) {
|
||||||
|
throw exception(boost::str(boost::format("Leaf file %1% mapping failed: %2%") % leaf_file % exc.what()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns all features inside the bounding box.
|
/* Returns all features inside the bounding box.
|
||||||
|
@ -330,16 +330,16 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
|
|||||||
|
|
||||||
using LeafNode = util::StaticRTree<extractor::EdgeBasedNode>::LeafNode;
|
using LeafNode = util::StaticRTree<extractor::EdgeBasedNode>::LeafNode;
|
||||||
|
|
||||||
std::ifstream leaf_node_file(rtree_leaf_filename, std::ios::binary | std::ios::in);
|
std::ifstream leaf_node_file(rtree_leaf_filename, std::ios::binary | std::ios::in | std::ios::ate);
|
||||||
if (!leaf_node_file)
|
if (!leaf_node_file)
|
||||||
{
|
{
|
||||||
throw util::exception("Failed to open " + rtree_leaf_filename);
|
throw util::exception("Failed to open " + rtree_leaf_filename);
|
||||||
}
|
}
|
||||||
uint64_t m_element_count;
|
std::size_t leaf_nodes_count = leaf_node_file.tellg() / sizeof(LeafNode);
|
||||||
leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
|
leaf_node_file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
LeafNode current_node;
|
LeafNode current_node;
|
||||||
while (m_element_count > 0)
|
while (leaf_nodes_count > 0)
|
||||||
{
|
{
|
||||||
leaf_node_file.read(reinterpret_cast<char *>(¤t_node), sizeof(current_node));
|
leaf_node_file.read(reinterpret_cast<char *>(¤t_node), sizeof(current_node));
|
||||||
|
|
||||||
@ -435,7 +435,7 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_element_count -= current_node.object_count;
|
--leaf_nodes_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ using TestStaticRTree = StaticRTree<TestData,
|
|||||||
false,
|
false,
|
||||||
TEST_BRANCHING_FACTOR,
|
TEST_BRANCHING_FACTOR,
|
||||||
TEST_LEAF_NODE_SIZE>;
|
TEST_LEAF_NODE_SIZE>;
|
||||||
using MiniStaticRTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 3>;
|
using MiniStaticRTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 128>;
|
||||||
|
|
||||||
// Choosen by a fair W20 dice roll (this value is completely arbitrary)
|
// Choosen by a fair W20 dice roll (this value is completely arbitrary)
|
||||||
constexpr unsigned RANDOM_SEED = 42;
|
constexpr unsigned RANDOM_SEED = 42;
|
||||||
@ -266,7 +266,7 @@ void construction_test(const std::string &prefix, FixtureT *fixture)
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE(construct_tiny, TestRandomGraphFixture_10_30)
|
BOOST_FIXTURE_TEST_CASE(construct_tiny, TestRandomGraphFixture_10_30)
|
||||||
{
|
{
|
||||||
using TinyTestTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 1>;
|
using TinyTestTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 64>;
|
||||||
construction_test<TinyTestTree>("test_tiny", this);
|
construction_test<TinyTestTree>("test_tiny", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user