19#include "pw_allocator/block/detailed_block.h"
20#include "pw_allocator/block_allocator.h"
21#include "pw_allocator/bucket/fast_sorted.h"
22#include "pw_allocator/bucket/unordered.h"
23#include "pw_allocator/config.h"
25namespace pw::allocator {
30template <
typename OffsetType>
46template <
typename BlockType = DlBlock<u
intptr_t>>
54 static constexpr size_t kMinSize = 8;
57 static constexpr size_t kNumFastBins = 10;
60 static constexpr size_t kNumSmallBins = 64;
61 static_assert((kNumSmallBins & (kNumSmallBins - 1)) == 0);
65 static constexpr size_t kNumLargeBins = kNumSmallBins - 1;
68 static constexpr size_t kBitmapBits = std::numeric_limits<uintptr_t>::digits;
69 static constexpr size_t kNumBitmaps =
70 AlignUp(kNumSmallBins + kNumLargeBins, kBitmapBits) / kBitmapBits;
90 BlockResult<BlockType>
ChooseBlock(Layout layout)
override;
99 void Flush()
override { ReleaseFastBins(); }
110 size_t GetIndex(
size_t size);
119 void ReleaseFastBins();
125 bool FindNextAvailable(
size_t& index);
129 void UpdateBitmaps(
size_t index,
bool empty);
131 std::array<FastBin, kNumFastBins> fast_bins_;
132 std::array<SmallBin, kNumSmallBins> small_bins_;
133 std::array<LargeBin, kNumLargeBins> large_bins_;
134 std::array<uintptr_t, kNumBitmaps> bitmaps_;
141template <
typename BlockType>
145 size_t bin_size = kMinSize;
146 size_t bins_in_round = kNumSmallBins;
147 while (bins_in_round > 1) {
148 for (
size_t i = 0; i < bins_in_round; ++i) {
150 if (index < kNumFastBins) {
151 fast_bins_[index].set_max_inner_size(size);
153 if (index < kNumSmallBins) {
154 small_bins_[index].set_max_inner_size(size);
156 large_bins_[index - kNumSmallBins].set_max_inner_size(size);
166template <
typename BlockType>
169 size_t bitmap_index = bitmaps_.size() - 1;
170 uintptr_t bitmap = bitmaps_[bitmap_index];
171 while (bitmap_index != 0 && bitmap == 0) {
173 bitmap = bitmaps_[bitmap_index];
180 size_t index = bitmap_index * kBitmapBits + bitmap_offset;
181 const BlockType* largest =
182 index < kNumSmallBins ? small_bins_[index].FindLargest()
183 : large_bins_[index - kNumSmallBins].FindLargest();
184 return largest ==
nullptr ? 0 : largest->InnerSize();
187template <
typename BlockType>
189 layout =
Layout(std::max(layout.size(), kMinSize), layout.alignment());
190 size_t index = GetIndex(layout.size());
192 if (index < kNumSmallBins) {
194 if (index < kNumFastBins) {
195 FastBin& fast_bin = fast_bins_[index];
197 if (block !=
nullptr) {
203 if (small_bins_[index].empty()) {
212 for (; FindNextAvailable(index) && index < kNumSmallBins; ++index) {
213 SmallBin& small_bin = small_bins_[index];
215 if (block !=
nullptr) {
216 UpdateBitmaps(index, small_bin.
empty());
217 return BlockType::AllocFirst(std::move(block), layout);
222 for (; FindNextAvailable(index); ++index) {
223 LargeBin& large_bin = large_bins_[index - kNumSmallBins];
225 if (block !=
nullptr) {
226 UpdateBitmaps(index, large_bin.
empty());
227 return BlockType::AllocFirst(std::move(block), layout);
235template <
typename BlockType>
237 size_t index = GetIndex(block.InnerSize());
238 if (index < kNumSmallBins) {
239 SmallBin& small_bin = small_bins_[index];
240 std::ignore = small_bin.
Remove(block);
241 UpdateBitmaps(index, small_bin.
empty());
243 LargeBin& large_bin = large_bins_[index - kNumSmallBins];
244 std::ignore = large_bin.
Remove(block);
245 UpdateBitmaps(index, large_bin.
empty());
249template <
typename BlockType>
251 size_t index = GetIndex(block.InnerSize());
252 if (index < kNumSmallBins) {
253 std::ignore = small_bins_[index].Add(block);
255 std::ignore = large_bins_[index - kNumSmallBins].Add(block);
257 UpdateBitmaps(index,
false);
260template <
typename BlockType>
263 size_t index = block->InnerSize() / kMinSize;
264 if (index < kNumFastBins) {
265 std::ignore = fast_bins_[index].Add(*block);
267 Base::DeallocateBlock(std::move(block));
271template <
typename BlockType>
274 size_t bin_size = kMinSize;
275 size_t bins_in_round = kNumSmallBins;
276 size =
AlignUp(size, kMinSize) - kMinSize;
277 while (bins_in_round > 1) {
278 size_t round_size = bin_size * bins_in_round;
279 if (size < round_size) {
280 return index + (size / bin_size);
283 index += bins_in_round;
290template <
typename BlockType>
291void DlAllocator<BlockType>::ReleaseFastBins() {
292 for (
auto& fast_bin : fast_bins_) {
293 while (!fast_bin.empty()) {
295 if constexpr (Hardening::kIncludesDebugChecks) {
296 PW_ASSERT(block !=
nullptr);
298 Base::DeallocateBlock(std::move(block));
303template <
typename BlockType>
304bool DlAllocator<BlockType>::FindNextAvailable(
size_t& index) {
305 size_t bitmap_index = index / kBitmapBits;
306 size_t bitmap_offset = index % kBitmapBits;
307 uintptr_t bitmap = bitmaps_[bitmap_index] & (~uintptr_t(0) << bitmap_offset);
308 while (bitmap == 0) {
310 if (bitmap_index >= kNumBitmaps) {
313 bitmap = bitmaps_[bitmap_index];
316 index = (bitmap_index * kBitmapBits) + bitmap_log2;
320template <
typename BlockType>
321void DlAllocator<BlockType>::UpdateBitmaps(
size_t index,
bool empty) {
322 size_t bitmap_index = index / kBitmapBits;
323 size_t bitmap_offset = index % kBitmapBits;
324 uintptr_t bitmap = uintptr_t(1) << bitmap_offset;
326 bitmaps_[bitmap_index] &= ~bitmap;
328 bitmaps_[bitmap_index] |= bitmap;
Definition: block_allocator.h:106
void Init(ByteSpan region)
Definition: block_allocator.h:310
Definition: detailed_block.h:88
Definition: dl_allocator.h:47
void RecycleBlock(BlockType &block) override
Definition: dl_allocator.h:250
void DeallocateBlock(BlockType *&&block) override
Definition: dl_allocator.h:261
BlockResult< BlockType > ChooseBlock(Layout layout) override
Definition: dl_allocator.h:188
void Flush() override
Definition: dl_allocator.h:99
void ReserveBlock(BlockType &block) override
Definition: dl_allocator.h:236
DlAllocator(ByteSpan region)
Definition: dl_allocator.h:81
constexpr DlAllocator()
Constexpr constructor. Callers must explicitly call Init.
Definition: dl_allocator.h:142
size_t DoGetMaxAllocatable() override
Definition: dl_allocator.h:167
Definition: fast_sorted.h:65
Definition: unordered.h:44
bool Remove(BlockType &block)
Definition: base.h:118
constexpr bool empty() const
Returns whether this buckets contains any free blocks.
Definition: base.h:70
BlockType * RemoveCompatible(Layout layout)
Definition: base.h:129
constexpr U CountRZero(T t)
Definition: base.h:224
constexpr U CountLZero(T t)
Definition: base.h:233
SmallBlock BlockType
Default block type to use for tests.
Definition: size_report.h:32
constexpr size_t AlignUp(uintptr_t value, size_t alignment)
Returns the value rounded up to the nearest multiple of alignment.
Definition: alignment.h:52