[OptTable] Fix typo VALUE => VALUES (NFCI) (#121523)
[llvm-project.git] / libc / test / src / __support / block_test.cpp
blob5e437db51b6092e838d71afb6f581455267958d9
1 //===-- Unittests for a block of memory -------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include <stddef.h>
10 #include "src/__support/CPP/array.h"
11 #include "src/__support/CPP/bit.h"
12 #include "src/__support/CPP/span.h"
13 #include "src/__support/block.h"
14 #include "src/string/memcpy.h"
15 #include "test/UnitTest/Test.h"
17 using LIBC_NAMESPACE::Block;
18 using LIBC_NAMESPACE::cpp::array;
19 using LIBC_NAMESPACE::cpp::bit_ceil;
20 using LIBC_NAMESPACE::cpp::byte;
21 using LIBC_NAMESPACE::cpp::span;
23 TEST(LlvmLibcBlockTest, CanCreateSingleAlignedBlock) {
24 constexpr size_t kN = 1024;
25 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
27 auto result = Block::init(bytes);
28 ASSERT_TRUE(result.has_value());
29 Block *block = *result;
31 Block *last = block->next();
32 ASSERT_NE(last, static_cast<Block *>(nullptr));
33 constexpr size_t last_outer_size = Block::BLOCK_OVERHEAD;
34 EXPECT_EQ(last->outer_size(), last_outer_size);
35 EXPECT_EQ(last->prev_free(), block);
36 EXPECT_TRUE(last->used());
38 EXPECT_EQ(block->outer_size(), kN - last_outer_size);
39 constexpr size_t last_prev_field_size = sizeof(size_t);
40 EXPECT_EQ(block->inner_size(), kN - last_outer_size - Block::BLOCK_OVERHEAD +
41 last_prev_field_size);
42 EXPECT_EQ(block->prev_free(), static_cast<Block *>(nullptr));
43 EXPECT_FALSE(block->used());
46 TEST(LlvmLibcBlockTest, CanCreateUnalignedSingleBlock) {
47 constexpr size_t kN = 1024;
49 // Force alignment, so we can un-force it below
50 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
51 span<byte> aligned(bytes);
53 auto result = Block::init(aligned.subspan(1));
54 EXPECT_TRUE(result.has_value());
57 TEST(LlvmLibcBlockTest, CannotCreateTooSmallBlock) {
58 array<byte, 2> bytes;
59 auto result = Block::init(bytes);
60 EXPECT_FALSE(result.has_value());
63 TEST(LlvmLibcBlockTest, CanSplitBlock) {
64 constexpr size_t kN = 1024;
65 constexpr size_t prev_field_size = sizeof(size_t);
66 // Give the split position a large alignment.
67 constexpr size_t kSplitN = 512 + prev_field_size;
69 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
70 auto result = Block::init(bytes);
71 ASSERT_TRUE(result.has_value());
72 auto *block1 = *result;
73 size_t orig_size = block1->outer_size();
75 result = block1->split(kSplitN);
76 ASSERT_TRUE(result.has_value());
77 auto *block2 = *result;
79 EXPECT_EQ(block1->inner_size(), kSplitN);
80 EXPECT_EQ(block1->outer_size(),
81 kSplitN - prev_field_size + Block::BLOCK_OVERHEAD);
83 EXPECT_EQ(block2->outer_size(), orig_size - block1->outer_size());
84 EXPECT_FALSE(block2->used());
86 EXPECT_EQ(block1->next(), block2);
87 EXPECT_EQ(block2->prev_free(), block1);
90 TEST(LlvmLibcBlockTest, CanSplitBlockUnaligned) {
91 constexpr size_t kN = 1024;
93 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
94 auto result = Block::init(bytes);
95 ASSERT_TRUE(result.has_value());
96 Block *block1 = *result;
97 size_t orig_size = block1->outer_size();
99 constexpr size_t kSplitN = 513;
100 constexpr size_t prev_field_size = sizeof(size_t);
101 uintptr_t split_addr =
102 reinterpret_cast<uintptr_t>(block1) + (kSplitN - prev_field_size);
103 // Round split_addr up to a multiple of the alignment.
104 split_addr += alignof(Block) - (split_addr % alignof(Block));
105 uintptr_t split_len = split_addr - (uintptr_t)&bytes + prev_field_size;
107 result = block1->split(kSplitN);
108 ASSERT_TRUE(result.has_value());
109 Block *block2 = *result;
111 EXPECT_EQ(block1->inner_size(), split_len);
113 EXPECT_EQ(block2->outer_size(), orig_size - block1->outer_size());
114 EXPECT_FALSE(block2->used());
116 EXPECT_EQ(block1->next(), block2);
117 EXPECT_EQ(block2->prev_free(), block1);
120 TEST(LlvmLibcBlockTest, CanSplitMidBlock) {
121 // split once, then split the original block again to ensure that the
122 // pointers get rewired properly.
123 // I.e.
124 // [[ BLOCK 1 ]]
125 // block1->split()
126 // [[ BLOCK1 ]][[ BLOCK2 ]]
127 // block1->split()
128 // [[ BLOCK1 ]][[ BLOCK3 ]][[ BLOCK2 ]]
130 constexpr size_t kN = 1024;
131 constexpr size_t kSplit1 = 512;
132 constexpr size_t kSplit2 = 256;
134 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
135 auto result = Block::init(bytes);
136 ASSERT_TRUE(result.has_value());
137 Block *block1 = *result;
139 result = block1->split(kSplit1);
140 ASSERT_TRUE(result.has_value());
141 Block *block2 = *result;
143 result = block1->split(kSplit2);
144 ASSERT_TRUE(result.has_value());
145 Block *block3 = *result;
147 EXPECT_EQ(block1->next(), block3);
148 EXPECT_EQ(block3->prev_free(), block1);
149 EXPECT_EQ(block3->next(), block2);
150 EXPECT_EQ(block2->prev_free(), block3);
153 TEST(LlvmLibcBlockTest, CannotSplitTooSmallBlock) {
154 constexpr size_t kN = 64;
155 constexpr size_t kSplitN = kN + 1;
157 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
158 auto result = Block::init(bytes);
159 ASSERT_TRUE(result.has_value());
160 Block *block = *result;
162 result = block->split(kSplitN);
163 ASSERT_FALSE(result.has_value());
166 TEST(LlvmLibcBlockTest, CannotSplitBlockWithoutHeaderSpace) {
167 constexpr size_t kN = 1024;
168 constexpr size_t kSplitN = kN - 2 * Block::BLOCK_OVERHEAD - 1;
170 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
171 auto result = Block::init(bytes);
172 ASSERT_TRUE(result.has_value());
173 Block *block = *result;
175 result = block->split(kSplitN);
176 ASSERT_FALSE(result.has_value());
179 TEST(LlvmLibcBlockTest, CannotMakeBlockLargerInSplit) {
180 // Ensure that we can't ask for more space than the block actually has...
181 constexpr size_t kN = 1024;
183 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
184 auto result = Block::init(bytes);
185 ASSERT_TRUE(result.has_value());
186 Block *block = *result;
188 result = block->split(block->inner_size() + 1);
189 ASSERT_FALSE(result.has_value());
192 TEST(LlvmLibcBlockTest, CannotMakeSecondBlockLargerInSplit) {
193 // Ensure that the second block in split is at least of the size of header.
194 constexpr size_t kN = 1024;
196 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
197 auto result = Block::init(bytes);
198 ASSERT_TRUE(result.has_value());
199 Block *block = *result;
201 result = block->split(block->inner_size() - Block::BLOCK_OVERHEAD + 1);
202 ASSERT_FALSE(result.has_value());
205 TEST(LlvmLibcBlockTest, CanMakeMinimalSizeFirstBlock) {
206 // This block does support splitting with minimal payload size.
207 constexpr size_t kN = 1024;
208 constexpr size_t minimal_size = sizeof(size_t);
210 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
211 auto result = Block::init(bytes);
212 ASSERT_TRUE(result.has_value());
213 Block *block = *result;
215 result = block->split(minimal_size);
216 ASSERT_TRUE(result.has_value());
217 EXPECT_EQ(block->inner_size(), minimal_size);
220 TEST(LlvmLibcBlockTest, CanMakeMinimalSizeSecondBlock) {
221 // Likewise, the split block can be minimal-width.
222 constexpr size_t kN = 1024;
223 constexpr size_t minimal_size = sizeof(size_t);
225 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
226 auto result = Block::init(bytes);
227 ASSERT_TRUE(result.has_value());
228 Block *block1 = *result;
230 result = block1->split(block1->inner_size() - Block::BLOCK_OVERHEAD);
231 ASSERT_TRUE(result.has_value());
232 Block *block2 = *result;
234 EXPECT_EQ(block2->inner_size(), minimal_size);
237 TEST(LlvmLibcBlockTest, CanMarkBlockUsed) {
238 constexpr size_t kN = 1024;
240 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
241 auto result = Block::init(bytes);
242 ASSERT_TRUE(result.has_value());
243 Block *block = *result;
244 size_t orig_size = block->outer_size();
246 block->mark_used();
247 EXPECT_TRUE(block->used());
248 EXPECT_EQ(block->outer_size(), orig_size);
250 block->mark_free();
251 EXPECT_FALSE(block->used());
254 TEST(LlvmLibcBlockTest, CannotSplitUsedBlock) {
255 constexpr size_t kN = 1024;
256 constexpr size_t kSplitN = 512;
258 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
259 auto result = Block::init(bytes);
260 ASSERT_TRUE(result.has_value());
261 Block *block = *result;
263 block->mark_used();
264 result = block->split(kSplitN);
265 ASSERT_FALSE(result.has_value());
268 TEST(LlvmLibcBlockTest, CanMergeWithNextBlock) {
269 // Do the three way merge from "CanSplitMidBlock", and let's
270 // merge block 3 and 2
271 constexpr size_t kN = 1024;
272 // Give the split positions large alignments.
273 constexpr size_t prev_field_size = sizeof(size_t);
274 constexpr size_t kSplit1 = 512 + prev_field_size;
275 constexpr size_t kSplit2 = 256 + prev_field_size;
277 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
278 auto result = Block::init(bytes);
279 ASSERT_TRUE(result.has_value());
280 Block *block1 = *result;
281 size_t orig_size = block1->outer_size();
283 result = block1->split(kSplit1);
284 ASSERT_TRUE(result.has_value());
286 result = block1->split(kSplit2);
287 ASSERT_TRUE(result.has_value());
288 Block *block3 = *result;
290 EXPECT_TRUE(block3->merge_next());
292 EXPECT_EQ(block1->next(), block3);
293 EXPECT_EQ(block3->prev_free(), block1);
294 EXPECT_EQ(block1->inner_size(), kSplit2);
295 EXPECT_EQ(block3->outer_size(), orig_size - block1->outer_size());
298 TEST(LlvmLibcBlockTest, CannotMergeWithFirstOrLastBlock) {
299 constexpr size_t kN = 1024;
300 constexpr size_t kSplitN = 512;
302 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
303 auto result = Block::init(bytes);
304 ASSERT_TRUE(result.has_value());
305 Block *block1 = *result;
307 // Do a split, just to check that the checks on next/prev are different...
308 result = block1->split(kSplitN);
309 ASSERT_TRUE(result.has_value());
310 Block *block2 = *result;
312 EXPECT_FALSE(block2->merge_next());
315 TEST(LlvmLibcBlockTest, CannotMergeUsedBlock) {
316 constexpr size_t kN = 1024;
317 constexpr size_t kSplitN = 512;
319 alignas(Block::ALIGNMENT) array<byte, kN> bytes;
320 auto result = Block::init(bytes);
321 ASSERT_TRUE(result.has_value());
322 Block *block = *result;
324 // Do a split, just to check that the checks on next/prev are different...
325 result = block->split(kSplitN);
326 ASSERT_TRUE(result.has_value());
328 block->mark_used();
329 EXPECT_FALSE(block->merge_next());
332 TEST(LlvmLibcBlockTest, CanGetBlockFromUsableSpace) {
333 constexpr size_t kN = 1024;
335 array<byte, kN> bytes{};
336 auto result = Block::init(bytes);
337 ASSERT_TRUE(result.has_value());
338 Block *block1 = *result;
340 void *ptr = block1->usable_space();
341 Block *block2 = Block::from_usable_space(ptr);
342 EXPECT_EQ(block1, block2);
345 TEST(LlvmLibcBlockTest, CanGetConstBlockFromUsableSpace) {
346 constexpr size_t kN = 1024;
348 array<byte, kN> bytes{};
349 auto result = Block::init(bytes);
350 ASSERT_TRUE(result.has_value());
351 const Block *block1 = *result;
353 const void *ptr = block1->usable_space();
354 const Block *block2 = Block::from_usable_space(ptr);
355 EXPECT_EQ(block1, block2);
358 TEST(LlvmLibcBlockTest, CanAllocate) {
359 constexpr size_t kN = 1024 + Block::BLOCK_OVERHEAD;
361 // Ensure we can allocate everything up to the block size within this block.
362 for (size_t i = 0; i < kN - 2 * Block::BLOCK_OVERHEAD; ++i) {
363 alignas(Block::ALIGNMENT) array<byte, kN> bytes{};
364 auto result = Block::init(bytes);
365 ASSERT_TRUE(result.has_value());
366 Block *block = *result;
368 constexpr size_t ALIGN = 1; // Effectively ignores alignment.
369 EXPECT_TRUE(block->can_allocate(ALIGN, i));
371 // For each can_allocate, we should be able to do a successful call to
372 // allocate.
373 auto info = Block::allocate(block, ALIGN, i);
374 EXPECT_NE(info.block, static_cast<Block *>(nullptr));
377 alignas(Block::ALIGNMENT) array<byte, kN> bytes{};
378 auto result = Block::init(bytes);
379 ASSERT_TRUE(result.has_value());
380 Block *block = *result;
382 // Given a block of size N (assuming it's also a power of two), we should be
383 // able to allocate a block within it that's aligned to N/2. This is
384 // because regardless of where the buffer is located, we can always find a
385 // starting location within it that meets this alignment.
386 EXPECT_TRUE(block->can_allocate(block->outer_size() / 2, 1));
387 auto info = Block::allocate(block, block->outer_size() / 2, 1);
388 EXPECT_NE(info.block, static_cast<Block *>(nullptr));
391 TEST(LlvmLibcBlockTest, AllocateAlreadyAligned) {
392 constexpr size_t kN = 1024;
394 alignas(Block::ALIGNMENT) array<byte, kN> bytes{};
395 auto result = Block::init(bytes);
396 ASSERT_TRUE(result.has_value());
397 Block *block = *result;
399 // This should result in no new blocks.
400 constexpr size_t kAlignment = Block::ALIGNMENT;
401 constexpr size_t prev_field_size = sizeof(size_t);
402 constexpr size_t kExpectedSize = Block::ALIGNMENT + prev_field_size;
403 EXPECT_TRUE(block->can_allocate(kAlignment, kExpectedSize));
405 auto [aligned_block, prev, next] =
406 Block::allocate(block, Block::ALIGNMENT, kExpectedSize);
408 // Since this is already aligned, there should be no previous block.
409 EXPECT_EQ(prev, static_cast<Block *>(nullptr));
411 // Ensure we the block is aligned and the size we expect.
412 EXPECT_NE(aligned_block, static_cast<Block *>(nullptr));
413 EXPECT_TRUE(aligned_block->is_usable_space_aligned(Block::ALIGNMENT));
414 EXPECT_EQ(aligned_block->inner_size(), kExpectedSize);
416 // Check the next block.
417 EXPECT_NE(next, static_cast<Block *>(nullptr));
418 EXPECT_EQ(aligned_block->next(), next);
419 EXPECT_EQ(reinterpret_cast<byte *>(next) + next->outer_size(),
420 bytes.data() + bytes.size() - Block::BLOCK_OVERHEAD);
423 TEST(LlvmLibcBlockTest, AllocateNeedsAlignment) {
424 constexpr size_t kN = 1024;
426 alignas(kN) array<byte, kN> bytes{};
427 auto result = Block::init(bytes);
428 ASSERT_TRUE(result.has_value());
429 Block *block = *result;
431 // Ensure first the usable_data is only aligned to the block alignment.
432 ASSERT_EQ(block->usable_space(), bytes.data() + Block::BLOCK_OVERHEAD);
433 ASSERT_EQ(block->prev_free(), static_cast<Block *>(nullptr));
435 // Now pick an alignment such that the usable space is not already aligned to
436 // it. We want to explicitly test that the block will split into one before
437 // it.
438 constexpr size_t kAlignment = bit_ceil(Block::BLOCK_OVERHEAD) * 8;
439 ASSERT_FALSE(block->is_usable_space_aligned(kAlignment));
441 constexpr size_t kSize = 10;
442 EXPECT_TRUE(block->can_allocate(kAlignment, kSize));
444 auto [aligned_block, prev, next] = Block::allocate(block, kAlignment, kSize);
446 // Check the previous block was created appropriately. Since this block is the
447 // first block, a new one should be made before this.
448 EXPECT_NE(prev, static_cast<Block *>(nullptr));
449 EXPECT_EQ(aligned_block->prev_free(), prev);
450 EXPECT_EQ(prev->next(), aligned_block);
451 EXPECT_EQ(prev->outer_size(), reinterpret_cast<uintptr_t>(aligned_block) -
452 reinterpret_cast<uintptr_t>(prev));
454 // Ensure we the block is aligned and the size we expect.
455 EXPECT_NE(next, static_cast<Block *>(nullptr));
456 EXPECT_TRUE(aligned_block->is_usable_space_aligned(kAlignment));
458 // Check the next block.
459 EXPECT_NE(next, static_cast<Block *>(nullptr));
460 EXPECT_EQ(aligned_block->next(), next);
461 EXPECT_EQ(reinterpret_cast<byte *>(next) + next->outer_size(),
462 bytes.data() + bytes.size() - Block::BLOCK_OVERHEAD);
465 TEST(LlvmLibcBlockTest, PreviousBlockMergedIfNotFirst) {
466 constexpr size_t kN = 1024;
468 alignas(kN) array<byte, kN> bytes{};
469 auto result = Block::init(bytes);
470 ASSERT_TRUE(result.has_value());
471 Block *block = *result;
473 // Split the block roughly halfway and work on the second half.
474 auto result2 = block->split(kN / 2);
475 ASSERT_TRUE(result2.has_value());
476 Block *newblock = *result2;
477 ASSERT_EQ(newblock->prev_free(), block);
478 size_t old_prev_size = block->outer_size();
480 // Now pick an alignment such that the usable space is not already aligned to
481 // it. We want to explicitly test that the block will split into one before
482 // it.
483 constexpr size_t kAlignment = bit_ceil(Block::BLOCK_OVERHEAD) * 8;
484 ASSERT_FALSE(newblock->is_usable_space_aligned(kAlignment));
486 // Ensure we can allocate in the new block.
487 constexpr size_t kSize = Block::ALIGNMENT;
488 EXPECT_TRUE(newblock->can_allocate(kAlignment, kSize));
490 auto [aligned_block, prev, next] =
491 Block::allocate(newblock, kAlignment, kSize);
493 // Now there should be no new previous block. Instead, the padding we did
494 // create should be merged into the original previous block.
495 EXPECT_EQ(prev, static_cast<Block *>(nullptr));
496 EXPECT_EQ(aligned_block->prev_free(), block);
497 EXPECT_EQ(block->next(), aligned_block);
498 EXPECT_GT(block->outer_size(), old_prev_size);
501 TEST(LlvmLibcBlockTest, CanRemergeBlockAllocations) {
502 // Finally to ensure we made the split blocks correctly via allocate. We
503 // should be able to reconstruct the original block from the blocklets.
505 // This is the same setup as with the `AllocateNeedsAlignment` test case.
506 constexpr size_t kN = 1024;
508 alignas(kN) array<byte, kN> bytes{};
509 auto result = Block::init(bytes);
510 ASSERT_TRUE(result.has_value());
511 Block *block = *result;
512 Block *last = block->next();
514 // Ensure first the usable_data is only aligned to the block alignment.
515 ASSERT_EQ(block->usable_space(), bytes.data() + Block::BLOCK_OVERHEAD);
516 ASSERT_EQ(block->prev_free(), static_cast<Block *>(nullptr));
518 // Now pick an alignment such that the usable space is not already aligned to
519 // it. We want to explicitly test that the block will split into one before
520 // it.
521 constexpr size_t kAlignment = bit_ceil(Block::BLOCK_OVERHEAD) * 8;
522 ASSERT_FALSE(block->is_usable_space_aligned(kAlignment));
524 constexpr size_t kSize = Block::ALIGNMENT;
525 EXPECT_TRUE(block->can_allocate(kAlignment, kSize));
527 auto [aligned_block, prev, next] = Block::allocate(block, kAlignment, kSize);
529 // Check we have the appropriate blocks.
530 ASSERT_NE(prev, static_cast<Block *>(nullptr));
531 ASSERT_EQ(aligned_block->prev_free(), prev);
532 EXPECT_NE(next, static_cast<Block *>(nullptr));
533 EXPECT_EQ(aligned_block->next(), next);
534 EXPECT_EQ(next->next(), last);
536 // Now check for successful merges.
537 EXPECT_TRUE(prev->merge_next());
538 EXPECT_EQ(prev->next(), next);
539 EXPECT_TRUE(prev->merge_next());
540 EXPECT_EQ(prev->next(), last);
542 // We should have the original buffer.
543 EXPECT_EQ(reinterpret_cast<byte *>(prev), &*bytes.begin());
544 EXPECT_EQ(prev->outer_size(), bytes.size() - Block::BLOCK_OVERHEAD);
545 EXPECT_EQ(reinterpret_cast<byte *>(prev) + prev->outer_size(),
546 &*bytes.end() - Block::BLOCK_OVERHEAD);