In commit "Add allocator for node based containers" (96d8e33acaa079491403d8e8afa6709978dec205)
I still think it's unfortunate to be adding this memusage specialization when it is not necessary. I don't like how it:
- Makes memusage.h depend node_allocator, when the job of memusage is just to tell us about memory usage of standard types, and it shouldn't need to be referencing a particular specialized allocator.
- Redefines the concept of memory usage for this one unordered_map+node_allocator container to not consider memory allocated by the container to be "used" by the container, even though the container allocated that memory, and is still responsible for deallocating (if not freeing) it.
- Will require new specializations of map+node_allocator or list+node_allocator to be added here if node_allocator is used with other map or list containers in the future.
I think code can be simpler, definition of "usage" can be more consistent, and cyclic dependencies and special cases can be removed using earlier suggestions from #22702 (review), and only downside would be adding a counter variable. On top of the current PR, changes would look like:
<details><summary>Diff</summary><p>
diff --git a/src/Makefile.am b/src/Makefile.am
index b39d03fe8cb..9d09682e243 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -217,7 +217,6 @@ BITCOIN_CORE_H = \
shutdown.h \
signet.h \
streams.h \
- support/allocators/node_allocator/allocator_fwd.h \
support/allocators/node_allocator/allocator.h \
support/allocators/node_allocator/factory.h \
support/allocators/node_allocator/memory_resource.h \
@@ -575,7 +574,6 @@ libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_util_a_SOURCES = \
support/lockedpool.cpp \
- support/allocators/node_allocator/memory_resource.cpp \
chainparamsbase.cpp \
clientversion.cpp \
compat/glibcxx_sanity.cpp \
diff --git a/src/memusage.h b/src/memusage.h
index bc20ee4052c..b9faff9b2d9 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -7,7 +7,6 @@
#include <indirectmap.h>
#include <prevector.h>
-#include <support/allocators/node_allocator/allocator_fwd.h>
#include <support/allocators/node_allocator/node_size.h>
#include <stdlib.h>
@@ -163,21 +162,13 @@ static inline size_t DynamicUsage(const std::unordered_set<X, Y>& s)
return MallocUsage(sizeof(unordered_node<X>)) * s.size() + MallocUsage(sizeof(void*) * s.bucket_count());
}
-template <typename Key, typename Value, typename Hash, typename Equals>
-static inline size_t DynamicUsage(const std::unordered_map<Key, Value, Hash, Equals>& m)
+template <typename Key, typename Value, typename Hash, typename Equals, typename Alloc>
+static inline size_t DynamicUsage(const std::unordered_map<Key, Value, Hash, Equals, Alloc>& m)
{
- auto node_size = node_allocator::NodeSize<std::unordered_map<Key, Value, Hash, Equals>>::Value();
+ auto node_size = node_allocator::NodeSize<std::unordered_map<Key, Value, Hash, Equals, Alloc>>::Value();
return MallocUsage(node_size) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count());
}
-template <typename Key, typename Value, typename Hash, typename Equals, typename AllocT, size_t AllocS>
-static inline size_t DynamicUsage(const std::unordered_map<Key, Value, Hash, Equals, node_allocator::Allocator<AllocT, AllocS>>& m)
-{
- // Since node_allocator is used, the memory of the nodes are the MemoryResource's responsibility and
- // won't be added here. Also multiple maps could use the same MemoryResource.
- return MallocUsage(sizeof(void*) * m.bucket_count());
-}
-
}
#endif // BITCOIN_MEMUSAGE_H
diff --git a/src/support/allocators/node_allocator/allocator.h b/src/support/allocators/node_allocator/allocator.h
index 778471bb20b..c728ab8638a 100644
--- a/src/support/allocators/node_allocator/allocator.h
+++ b/src/support/allocators/node_allocator/allocator.h
@@ -5,7 +5,6 @@
#ifndef BITCOIN_SUPPORT_ALLOCATORS_NODE_ALLOCATOR_ALLOCATOR_H
#define BITCOIN_SUPPORT_ALLOCATORS_NODE_ALLOCATOR_ALLOCATOR_H
-#include <support/allocators/node_allocator/allocator_fwd.h>
#include <support/allocators/node_allocator/memory_resource.h>
#include <cstdint>
diff --git a/src/support/allocators/node_allocator/allocator_fwd.h b/src/support/allocators/node_allocator/allocator_fwd.h
deleted file mode 100644
index e3fa0ddd889..00000000000
--- a/src/support/allocators/node_allocator/allocator_fwd.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2021 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_SUPPORT_ALLOCATORS_NODE_ALLOCATOR_ALLOCATOR_FWD_H
-#define BITCOIN_SUPPORT_ALLOCATORS_NODE_ALLOCATOR_ALLOCATOR_FWD_H
-
-#include <cstddef>
-
-namespace node_allocator {
-
-template <typename T, size_t ALLOCATION_SIZE_BYTES>
-class Allocator;
-
-} // namespace node_allocator
-
-#endif // BITCOIN_SUPPORT_ALLOCATORS_NODE_ALLOCATOR_ALLOCATOR_FWD_H
diff --git a/src/support/allocators/node_allocator/memory_resource.cpp b/src/support/allocators/node_allocator/memory_resource.cpp
deleted file mode 100644
index 368752fa2b9..00000000000
--- a/src/support/allocators/node_allocator/memory_resource.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <support/allocators/node_allocator/memory_resource.h>
-
-#include <memusage.h>
-
-namespace node_allocator::detail {
-
-size_t DynamicMemoryUsage(size_t pool_size_bytes, std::vector<std::unique_ptr<char[]>> const& allocated_pools)
-{
- return memusage::MallocUsage(pool_size_bytes) * allocated_pools.size() + memusage::DynamicUsage(allocated_pools);
-}
-
-} // namespace node_allocator::detail
diff --git a/src/support/allocators/node_allocator/memory_resource.h b/src/support/allocators/node_allocator/memory_resource.h
index f4ba0138924..e60e847c86d 100644
--- a/src/support/allocators/node_allocator/memory_resource.h
+++ b/src/support/allocators/node_allocator/memory_resource.h
@@ -8,6 +8,8 @@
#include <utility>
#include <vector>
+#include <memusage.h>
+
#ifndef BITCOIN_SUPPORT_ALLOCATORS_NODE_ALLOCATOR_MEMORY_RESOURCE_H
#define BITCOIN_SUPPORT_ALLOCATORS_NODE_ALLOCATOR_MEMORY_RESOURCE_H
@@ -38,12 +40,6 @@ template <typename T>
return ((size_max + alignment_max - 1U) / alignment_max) * alignment_max;
}
-/**
- * Calculates dynamic memory usage of a MemoryResource. Not a member of MemoryResource so we can implement this
- * in a cpp and don't depend on memusage.h in the header.
- */
-[[nodiscard]] size_t DynamicMemoryUsage(size_t pool_size_bytes, std::vector<std::unique_ptr<char[]>> const& allocated_pools);
-
} // namespace detail
/**
@@ -102,6 +98,7 @@ public:
{
static_assert(ALLOCATION_SIZE_BYTES == detail::RequiredAllocationSizeBytes<T>());
static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= std::alignment_of_v<T>, "make sure AllocatePool() aligns correctly");
+ ++m_allocations;
if (m_free_allocations) {
// we've already got data in the free list, unlink one element
@@ -138,6 +135,7 @@ public:
void Deallocate(void* p) noexcept
{
static_assert(ALLOCATION_SIZE_BYTES == detail::RequiredAllocationSizeBytes<T>());
+ --m_allocations;
// put it into the linked list.
//
@@ -150,11 +148,11 @@ public:
}
/**
- * Calculates bytes allocated by the memory resource.
+ * Calculates number of bytes allocated to the memory resource minus number of bytes allocated from the memory resource.
*/
[[nodiscard]] size_t DynamicMemoryUsage() const noexcept
{
- return detail::DynamicMemoryUsage(POOL_SIZE_BYTES, m_allocated_pools);
+ return memusage::MallocUsage(POOL_SIZE_BYTES) * m_allocated_pools.size() + memusage::DynamicUsage(m_allocated_pools) - ALLOCATION_SIZE_BYTES * m_allocations;
}
private:
@@ -171,6 +169,9 @@ private:
m_untouched_memory_end = m_untouched_memory_iterator + POOL_SIZE_BYTES;
}
+ //! Number of current allocations.
+ size_t m_allocations = 0;
+
//! Contains all allocated pools of memory, used to free the data in the destructor.
std::vector<std::unique_ptr<char[]>> m_allocated_pools{};
</p></details>