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>, | ||||
|           bool UseSharedMemory = false, | ||||
|           std::uint32_t BRANCHING_FACTOR = 128, | ||||
|           std::uint32_t LEAF_NODE_SIZE = 128> | ||||
|           std::uint32_t LEAF_PAGE_SIZE = 4096> | ||||
| class StaticRTree | ||||
| { | ||||
|   public: | ||||
| @ -52,6 +52,10 @@ class StaticRTree | ||||
|     using EdgeData = EdgeDataT; | ||||
|     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 | ||||
|     { | ||||
|         Coordinate fixed_projected_coordinate; | ||||
| @ -72,7 +76,9 @@ class StaticRTree | ||||
|         LeafNode() : object_count(0), objects() {} | ||||
|         uint32_t object_count; | ||||
|         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: | ||||
|     struct WrappedInputElement | ||||
| @ -110,8 +116,6 @@ class StaticRTree | ||||
|     }; | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     boost::iostreams::mapped_file_source m_leaves_region; | ||||
| @ -128,13 +132,13 @@ class StaticRTree | ||||
|                          const std::string &tree_node_filename, | ||||
|                          const std::string &leaf_node_filename, | ||||
|                          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
 | ||||
|         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, | ||||
|              &coordinate_list](const tbb::blocked_range<uint64_t> &range) | ||||
|             { | ||||
| @ -162,7 +166,6 @@ class StaticRTree | ||||
| 
 | ||||
|         // open leaf file
 | ||||
|         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
 | ||||
|         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
 | ||||
|         uint64_t processed_objects_count = 0; | ||||
|         while (processed_objects_count < m_element_count) | ||||
|         while (processed_objects_count < element_count) | ||||
|         { | ||||
| 
 | ||||
|             LeafNode current_leaf; | ||||
| @ -178,7 +181,7 @@ class StaticRTree | ||||
|             for (std::uint32_t current_element_index = 0; LEAF_NODE_SIZE > 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 = | ||||
|                         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 *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree); | ||||
| 
 | ||||
|         m_leaves_region.open(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); | ||||
|         MapLeafNodesFile(leaf_node_filename); | ||||
|     } | ||||
| 
 | ||||
|     explicit StaticRTree(const boost::filesystem::path &node_file, | ||||
|                          const boost::filesystem::path &leaf_file, | ||||
|                          const std::shared_ptr<CoordinateListT> coordinate_list) | ||||
|         : m_leaf_node_filename(leaf_file.string()) | ||||
|     { | ||||
|         // open tree node file and load into RAM.
 | ||||
|         m_coordinate_list = coordinate_list; | ||||
| @ -300,43 +299,29 @@ class StaticRTree | ||||
|             tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size); | ||||
|         } | ||||
| 
 | ||||
|         // open leaf node file and store thread specific pointer
 | ||||
|         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); | ||||
|         MapLeafNodesFile(leaf_file); | ||||
|     } | ||||
| 
 | ||||
|     explicit StaticRTree(TreeNode *tree_node_ptr, | ||||
|                          const uint64_t number_of_nodes, | ||||
|                          const boost::filesystem::path &leaf_file, | ||||
|                          std::shared_ptr<CoordinateListT> coordinate_list) | ||||
|         : m_search_tree(tree_node_ptr, number_of_nodes), | ||||
|           m_coordinate_list(std::move(coordinate_list)) | ||||
|         : m_search_tree(tree_node_ptr, number_of_nodes) | ||||
|         , m_coordinate_list(std::move(coordinate_list)) | ||||
|     { | ||||
|         // open leaf node file and store thread specific pointer
 | ||||
|         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"); | ||||
|         } | ||||
|         MapLeafNodesFile(leaf_file); | ||||
|     } | ||||
| 
 | ||||
|         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); | ||||
|     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); | ||||
|             std::size_t num_leaves = m_leaves_region.size() / sizeof(LeafNode); | ||||
|             m_leaves.reset(reinterpret_cast<const LeafNode*>(m_leaves_region.data()), 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.
 | ||||
|  | ||||
| @ -330,16 +330,16 @@ std::size_t Contractor::LoadEdgeExpandedGraph( | ||||
| 
 | ||||
|             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) | ||||
|             { | ||||
|                 throw util::exception("Failed to open " + rtree_leaf_filename); | ||||
|             } | ||||
|             uint64_t m_element_count; | ||||
|             leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t)); | ||||
|             std::size_t leaf_nodes_count = leaf_node_file.tellg() / sizeof(LeafNode); | ||||
|             leaf_node_file.seekg(0, std::ios::beg); | ||||
| 
 | ||||
|             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)); | ||||
| 
 | ||||
| @ -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, | ||||
|                                     TEST_BRANCHING_FACTOR, | ||||
|                                     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)
 | ||||
| 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) | ||||
| { | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user