From 08cf9498553b88b0e41d3e4b233c04ac54e89c7a Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Thu, 18 Nov 2021 18:48:47 +0000 Subject: [PATCH] Change default block size alignment to be 4 for memory saving on 32-bit arch For a 32-bit userspace, `struct LinkedListEntry` takes 8 bytes for storing the two pointers, a default block allocator size alignment of 16-bytes would waste 50% of memory. By changing the alignment to size of a pointer, it saves >1MB memory postboot on wembley device. Bug: http://b/206889551 Test: bionic-unit-tests Change-Id: Ie92399c9bb3971f631396ee09bbbfd7eb17dc1a7 --- linker/linker_block_allocator.cpp | 19 ++++---- linker/linker_block_allocator.h | 3 ++ linker/linker_block_allocator_test.cpp | 65 +++++++++++++------------- 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/linker/linker_block_allocator.cpp b/linker/linker_block_allocator.cpp index 5b68b1d6c..60e5e1cdc 100644 --- a/linker/linker_block_allocator.cpp +++ b/linker/linker_block_allocator.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -39,11 +40,6 @@ static constexpr size_t kAllocateSize = PAGE_SIZE * 100; static_assert(kAllocateSize % PAGE_SIZE == 0, "Invalid kAllocateSize."); -// the multiplier should be power of 2 -static constexpr size_t round_up(size_t size, size_t multiplier) { - return (size + (multiplier - 1)) & ~(multiplier-1); -} - struct LinkerBlockAllocatorPage { LinkerBlockAllocatorPage* next; uint8_t bytes[kAllocateSize - 16] __attribute__((aligned(16))); @@ -54,13 +50,14 @@ struct FreeBlockInfo { size_t num_free_blocks; }; +static_assert(kBlockSizeAlign >= alignof(FreeBlockInfo)); +static_assert(kBlockSizeMin == sizeof(FreeBlockInfo)); + LinkerBlockAllocator::LinkerBlockAllocator(size_t block_size) - : block_size_( - round_up(block_size < sizeof(FreeBlockInfo) ? sizeof(FreeBlockInfo) : block_size, 16)), - page_list_(nullptr), - free_block_list_(nullptr), - allocated_(0) -{} + : block_size_(__BIONIC_ALIGN(MAX(block_size, kBlockSizeMin), kBlockSizeAlign)), + page_list_(nullptr), + free_block_list_(nullptr), + allocated_(0) {} void* LinkerBlockAllocator::alloc() { if (free_block_list_ == nullptr) { diff --git a/linker/linker_block_allocator.h b/linker/linker_block_allocator.h index 8ae4094be..32656c7f5 100644 --- a/linker/linker_block_allocator.h +++ b/linker/linker_block_allocator.h @@ -33,6 +33,9 @@ #include +static constexpr size_t kBlockSizeAlign = sizeof(void*); +static constexpr size_t kBlockSizeMin = sizeof(void*) * 2; + struct LinkerBlockAllocatorPage; /* diff --git a/linker/linker_block_allocator_test.cpp b/linker/linker_block_allocator_test.cpp index 6fb2b2680..56fbee8b7 100644 --- a/linker/linker_block_allocator_test.cpp +++ b/linker/linker_block_allocator_test.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -44,12 +45,16 @@ struct test_struct_nominal { }; /* - * this one has size below allocator cap which is 2*sizeof(void*) + * this one has size below kBlockSizeAlign */ struct test_struct_small { - char str[5]; + char str[3]; }; +struct test_struct_max_align { + char str[16]; +} __attribute__((aligned(16))); + /* * 1009 byte struct (1009 is prime) */ @@ -58,54 +63,49 @@ struct test_struct_larger { }; static size_t kPageSize = sysconf(_SC_PAGE_SIZE); -}; -TEST(linker_allocator, test_nominal) { - LinkerTypeAllocator allocator; +template +void linker_allocator_test_helper() { + LinkerTypeAllocator allocator; - test_struct_nominal* ptr1 = allocator.alloc(); + Element* ptr1 = allocator.alloc(); ASSERT_TRUE(ptr1 != nullptr); - ASSERT_EQ(0U, reinterpret_cast(ptr1) % 16); - test_struct_nominal* ptr2 = allocator.alloc(); - ASSERT_EQ(0U, reinterpret_cast(ptr2) % 16); + ASSERT_EQ(0U, reinterpret_cast(ptr1) % kBlockSizeAlign); + ASSERT_EQ(0U, reinterpret_cast(ptr1) % alignof(Element)); + Element* ptr2 = allocator.alloc(); + ASSERT_EQ(0U, reinterpret_cast(ptr2) % kBlockSizeAlign); + ASSERT_EQ(0U, reinterpret_cast(ptr2) % alignof(Element)); ASSERT_TRUE(ptr2 != nullptr); - // they should be next to each other. - ASSERT_EQ(reinterpret_cast(ptr1)+16, reinterpret_cast(ptr2)); - ptr1->value = 42; + // they should be next to each other. + size_t dist = __BIONIC_ALIGN(MAX(sizeof(Element), kBlockSizeMin), kBlockSizeAlign); + ASSERT_EQ(reinterpret_cast(ptr1) + dist, reinterpret_cast(ptr2)); allocator.free(ptr1); allocator.free(ptr2); } +}; // anonymous namespace + +TEST(linker_allocator, test_nominal) { + linker_allocator_test_helper(); +} + TEST(linker_allocator, test_small) { - LinkerTypeAllocator allocator; + linker_allocator_test_helper(); +} - char* ptr1 = reinterpret_cast(allocator.alloc()); - char* ptr2 = reinterpret_cast(allocator.alloc()); - - ASSERT_TRUE(ptr1 != nullptr); - ASSERT_EQ(0U, reinterpret_cast(ptr1) % 16); - ASSERT_TRUE(ptr2 != nullptr); - ASSERT_EQ(0U, reinterpret_cast(ptr2) % 16); - ASSERT_EQ(ptr1+16, ptr2); // aligned to 16 +TEST(linker_allocator, test_max_align) { + linker_allocator_test_helper(); } TEST(linker_allocator, test_larger) { + linker_allocator_test_helper(); + LinkerTypeAllocator allocator; - test_struct_larger* ptr1 = allocator.alloc(); - test_struct_larger* ptr2 = allocator.alloc(); - - ASSERT_TRUE(ptr1 != nullptr); - ASSERT_EQ(0U, reinterpret_cast(ptr1) % 16); - ASSERT_TRUE(ptr2 != nullptr); - ASSERT_EQ(0U, reinterpret_cast(ptr2) % 16); - - ASSERT_EQ(reinterpret_cast(ptr1) + 1024, reinterpret_cast(ptr2)); - // lets allocate until we reach next page. - size_t n = kPageSize/sizeof(test_struct_larger) + 1 - 2; + size_t n = kPageSize / sizeof(test_struct_larger) + 1; for (size_t i=0; i