Bitcoin Core  31.0.0
P2P Digital Currency
poolresourcetester.h
Go to the documentation of this file.
1 // Copyright (c) 2022-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H
6 #define BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H
7 
9 #include <util/check.h>
10 
11 #include <algorithm>
12 #include <cassert>
13 #include <cstddef>
14 #include <cstdint>
15 #include <vector>
16 
21 {
22  struct PtrAndBytes {
23  uintptr_t ptr;
24  std::size_t size;
25 
26  PtrAndBytes(const void* p, std::size_t s)
27  : ptr(reinterpret_cast<uintptr_t>(p)), size(s)
28  {
29  }
30 
34  friend bool operator<(PtrAndBytes const& a, PtrAndBytes const& b)
35  {
36  return a.ptr < b.ptr;
37  }
38  };
39 
40 public:
44  template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
45  static std::vector<std::size_t> FreeListSizes(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource)
46  {
47  auto sizes = std::vector<std::size_t>();
48  for (const auto* ptr : resource.m_free_lists) {
49  size_t size = 0;
50  while (ptr != nullptr) {
51  ++size;
52  const auto* ptr_ = ptr;
54  ptr = ptr->m_next;
56  }
57  sizes.push_back(size);
58  }
59  return sizes;
60  }
61 
65  template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
67  {
68  return resource.m_available_memory_end - resource.m_available_memory_it;
69  }
70 
78  template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
80  {
81  // collect all free blocks by iterating all freelists
82  std::vector<PtrAndBytes> free_blocks;
83  for (std::size_t freelist_idx = 0; freelist_idx < resource.m_free_lists.size(); ++freelist_idx) {
84  std::size_t bytes = freelist_idx * resource.ELEM_ALIGN_BYTES;
85  auto* ptr = resource.m_free_lists[freelist_idx];
86  while (ptr != nullptr) {
87  free_blocks.emplace_back(ptr, bytes);
88  const auto* ptr_ = ptr;
90  ptr = ptr->m_next;
92  }
93  }
94  // also add whatever has not yet been used for blocks
95  auto num_available_bytes = resource.m_available_memory_end - resource.m_available_memory_it;
96  if (num_available_bytes > 0) {
97  free_blocks.emplace_back(resource.m_available_memory_it, num_available_bytes);
98  }
99 
100  // collect all chunks
101  std::vector<PtrAndBytes> chunks;
102  for (const std::byte* ptr : resource.m_allocated_chunks) {
103  chunks.emplace_back(ptr, resource.ChunkSizeBytes());
104  }
105 
106  // now we have all the data from all freelists on the one hand side, and all chunks on the other hand side.
107  // To check if all of them match, sort by address and iterate.
108  std::sort(free_blocks.begin(), free_blocks.end());
109  std::sort(chunks.begin(), chunks.end());
110 
111  auto chunk_it = chunks.begin();
112  auto chunk_ptr_remaining = chunk_it->ptr;
113  auto chunk_size_remaining = chunk_it->size;
114  for (const auto& free_block : free_blocks) {
115  if (chunk_size_remaining == 0) {
116  assert(chunk_it != chunks.end());
117  ++chunk_it;
118  assert(chunk_it != chunks.end());
119  chunk_ptr_remaining = chunk_it->ptr;
120  chunk_size_remaining = chunk_it->size;
121  }
122  assert(free_block.ptr == chunk_ptr_remaining); // ensure addresses match
123  assert(free_block.size <= chunk_size_remaining); // ensure no overflow
124  assert((free_block.ptr & (resource.ELEM_ALIGN_BYTES - 1)) == 0); // ensure correct alignment
125  chunk_ptr_remaining += free_block.size;
126  chunk_size_remaining -= free_block.size;
127  }
128  // ensure we are at the end of the chunks
129  assert(chunk_ptr_remaining == chunk_it->ptr + chunk_it->size);
130  ++chunk_it;
131  assert(chunk_it == chunks.end());
132  assert(chunk_size_remaining == 0);
133  }
134 };
135 
136 #endif // BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H
assert(!tx.IsCoinBase())
std::byte * m_available_memory_it
Points to the beginning of available memory for carving out allocations.
Definition: pool.h:114
std::array< ListNode *, MAX_BLOCK_SIZE_BYTES/ELEM_ALIGN_BYTES+1 > m_free_lists
Single linked lists of all data that came from deallocating.
Definition: pool.h:109
static std::size_t AvailableMemoryFromChunk(const PoolResource< MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > &resource)
How many bytes are still available from the last allocated chunk.
friend bool operator<(PtrAndBytes const &a, PtrAndBytes const &b)
defines a sort ordering by the pointer value
static constexpr std::size_t ELEM_ALIGN_BYTES
Internal alignment value.
Definition: pool.h:90
In-place linked list of the allocations, used for the freelist.
Definition: pool.h:80
Helper to get access to private parts of PoolResource.
#define ASAN_POISON_MEMORY_REGION(addr, size)
Definition: check.h:140
static std::vector< std::size_t > FreeListSizes(const PoolResource< MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > &resource)
Extracts the number of elements per freelist.
static void CheckAllDataAccountedFor(const PoolResource< MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > &resource)
Once all blocks are given back to the resource, tests that the freelists are consistent: ...
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)
Definition: check.h:141
size_t ChunkSizeBytes() const
Size in bytes to allocate per chunk, currently hardcoded to a fixed size.
Definition: pool.h:278
std::byte * m_available_memory_end
Points to the end of available memory for carving out allocations.
Definition: pool.h:122
std::list< std::byte * > m_allocated_chunks
Contains all allocated pools of memory, used to free the data in the destructor.
Definition: pool.h:103
PtrAndBytes(const void *p, std::size_t s)
A memory resource similar to std::pmr::unsynchronized_pool_resource, but optimized for node-based con...
Definition: pool.h:72