diff --git a/include/customizer/cell_customizer.hpp b/include/customizer/cell_customizer.hpp index d92bd411e..53570c51d 100644 --- a/include/customizer/cell_customizer.hpp +++ b/include/customizer/cell_customizer.hpp @@ -116,7 +116,6 @@ class CellCustomizer const std::vector &allowed_nodes, CellMetric &metric) const { - // std::cerr << "Customizing cells\n"; const auto number_of_nodes = graph.GetNumberOfNodes(); HeapPtr heaps([number_of_nodes]{ return Heap{number_of_nodes}; diff --git a/include/util/pool_allocator.hpp b/include/util/pool_allocator.hpp index 1f2b6510d..76bd27202 100644 --- a/include/util/pool_allocator.hpp +++ b/include/util/pool_allocator.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -14,40 +15,42 @@ namespace osrm::util { -class MemoryManager +class MemoryPool { private: - constexpr static size_t MIN_ITEMS_IN_BLOCK = 1024; + constexpr static size_t MIN_CHUNK_SIZE_BYTES = 4096; public: - static std::shared_ptr instance() + static std::shared_ptr instance() { - static thread_local std::shared_ptr instance; + static thread_local std::shared_ptr instance; if (!instance) { - instance = std::shared_ptr(new MemoryManager()); + instance = std::shared_ptr(new MemoryPool()); } return instance; } - // TODO: alignment!!! template - T *allocate(std::size_t n) + T *allocate(std::size_t items_count) { - size_t free_list_index = get_next_power_of_two_exponent(n * sizeof(T)); + static_assert(alignof(T) <= alignof(std::max_align_t), "Type is over-aligned for this allocator."); + + size_t free_list_index = get_next_power_of_two_exponent(items_count * sizeof(T)); auto &free_list = free_lists_[free_list_index]; - const auto items_in_block = 1u << free_list_index; if (free_list.empty()) { - // Check if there is space in current block - if (current_block_left_items_ < items_in_block) + size_t block_size_in_bytes = 1u << free_list_index; + block_size_in_bytes = align_up(block_size_in_bytes, alignof(std::max_align_t)); + // Check if there is space in current memory chunk + if (current_chunk_left_bytes_ < block_size_in_bytes) { - allocate_block(items_in_block); + allocate_chunk(block_size_in_bytes); } - free_list.push_back(current_block_ptr_); - current_block_left_items_ -= items_in_block; - current_block_ptr_ += items_in_block * sizeof(T); + free_list.push_back(current_chunk_ptr_); + current_chunk_left_bytes_ -= block_size_in_bytes; + current_chunk_ptr_ += block_size_in_bytes; } auto ptr = static_cast(free_list.back()); free_list.pop_back(); @@ -61,49 +64,54 @@ public: free_lists_[free_list_index].push_back(p); } - ~MemoryManager() + ~MemoryPool() { - std::cerr << "~MemoryManager()" << std::endl; - for (auto block : blocks_) + for (auto chunk : chunks_) { - std::free(block); + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) + std::free(chunk); } } private: - MemoryManager() = default; - MemoryManager(const MemoryManager &) = delete; - MemoryManager &operator=(const MemoryManager &) = delete; + MemoryPool() = default; + MemoryPool(const MemoryPool &) = delete; + MemoryPool &operator=(const MemoryPool &) = delete; - size_t get_next_power_of_two_exponent(size_t n) const + inline size_t get_next_power_of_two_exponent(size_t n) const { BOOST_ASSERT(n > 0); return (sizeof(size_t) * 8) - std::countl_zero(n - 1); } - template - void allocate_block(size_t items_in_block) + inline size_t align_up(size_t n, size_t alignment) { - items_in_block = std::max(items_in_block, MIN_ITEMS_IN_BLOCK); + return (n + alignment - 1) & ~(alignment - 1); + } - size_t block_size = items_in_block * sizeof(T); - void *block = std::malloc(block_size); - if (!block) + inline void* align_pointer(void* ptr, size_t alignment) + { + return reinterpret_cast(align_up(reinterpret_cast(ptr), alignment)); + } + + void allocate_chunk(size_t bytes) + { + auto chunk_size = std::max(bytes, MIN_CHUNK_SIZE_BYTES); + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) + void *chunk = std::malloc(chunk_size); + if (!chunk) { throw std::bad_alloc(); } - total_allocated_ += block_size; - blocks_.push_back(block); - current_block_ptr_ = static_cast(block); - current_block_left_items_ = items_in_block; + chunks_.push_back(chunk); + current_chunk_ptr_ = static_cast(chunk); + current_chunk_left_bytes_ = chunk_size; } std::array, 32> free_lists_; - std::vector blocks_; - uint8_t *current_block_ptr_ = nullptr; - size_t current_block_left_items_ = 0; - - size_t total_allocated_ = 0; + std::vector chunks_; + uint8_t *current_chunk_ptr_ = nullptr; + size_t current_chunk_left_bytes_ = 0; }; template @@ -112,10 +120,10 @@ class PoolAllocator public: using value_type = T; - PoolAllocator() noexcept : pool(MemoryManager::instance()) {}; + PoolAllocator() noexcept : pool(MemoryPool::instance()) {}; template - PoolAllocator(const PoolAllocator &) noexcept : pool(MemoryManager::instance()) {} + PoolAllocator(const PoolAllocator &) noexcept : pool(MemoryPool::instance()) {} template struct rebind @@ -133,17 +141,13 @@ public: pool->deallocate(p, n); } - ~PoolAllocator() { - std::cerr << "~PoolAllocator()" << std::endl; - } - PoolAllocator(const PoolAllocator &) = default; PoolAllocator &operator=(const PoolAllocator &) = default; PoolAllocator(PoolAllocator &&) noexcept = default; PoolAllocator &operator=(PoolAllocator &&) noexcept = default; private: - std::shared_ptr pool; + std::shared_ptr pool; }; template bool operator==(const PoolAllocator &, const PoolAllocator &) diff --git a/include/util/query_heap.hpp b/include/util/query_heap.hpp index fc71f208b..42818cb7f 100644 --- a/include/util/query_heap.hpp +++ b/include/util/query_heap.hpp @@ -36,10 +36,6 @@ template class UnorderedMapStorage public: explicit UnorderedMapStorage(std::size_t) { nodes.rehash(1000); } - ~UnorderedMapStorage() { - std::cerr << "~UnorderedMapStorage()" << std::endl; - } - Key &operator[](const NodeID node) { return nodes[node]; } Key peek_index(const NodeID node) const diff --git a/src/util/pool_allocator.cpp b/src/util/pool_allocator.cpp deleted file mode 100644 index 4b55e524c..000000000 --- a/src/util/pool_allocator.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "util/pool_allocator.hpp" - -namespace osrm::util -{ -} // namespace osrm::util \ No newline at end of file diff --git a/test/data/Makefile b/test/data/Makefile index b79e87fe0..2c617405b 100755 --- a/test/data/Makefile +++ b/test/data/Makefile @@ -65,4 +65,4 @@ benchmark: data $(DATA_NAME).requests checksum: $(MD5SUM) $(DATA_NAME).osm.pbf $(DATA_NAME).poly > data.md5sum -.PHONY: clean checksum benchmark data \ No newline at end of file +.PHONY: clean checksum benchmark data diff --git a/unit_tests/util/pool_allocator.cpp b/unit_tests/util/pool_allocator.cpp index 215cdebd5..de013f788 100644 --- a/unit_tests/util/pool_allocator.cpp +++ b/unit_tests/util/pool_allocator.cpp @@ -85,4 +85,33 @@ BOOST_AUTO_TEST_CASE(unordered_map) BOOST_CHECK_EQUAL(map[2], 43); } +BOOST_AUTO_TEST_CASE(alignment) +{ + PoolAllocator pool_char; + PoolAllocator pool_double; + + auto ptr_char = pool_char.allocate(1); + auto ptr_double = pool_double.allocate(1); + + BOOST_CHECK_NE(ptr_double, nullptr); + BOOST_CHECK_EQUAL(reinterpret_cast(ptr_double) % alignof(double), 0); + BOOST_CHECK_NE(ptr_char, nullptr); + BOOST_CHECK_EQUAL(reinterpret_cast(ptr_char) % alignof(char), 0); + + pool_char.deallocate(ptr_char, 1); + pool_double.deallocate(ptr_double, 1); + + + ptr_char = pool_char.allocate(2); + ptr_double = pool_double.allocate(1); + + BOOST_CHECK_NE(ptr_double, nullptr); + BOOST_CHECK_EQUAL(reinterpret_cast(ptr_double) % alignof(double), 0); + BOOST_CHECK_NE(ptr_char, nullptr); + BOOST_CHECK_EQUAL(reinterpret_cast(ptr_char) % alignof(char), 0); + + pool_char.deallocate(ptr_char, 2); + pool_double.deallocate(ptr_double, 1); +} + BOOST_AUTO_TEST_SUITE_END()