From f89e8fb71a4893911ee5125f34bd5bbb99327d33 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sat, 15 May 2021 10:06:41 +0200 Subject: [PATCH] AK+LibC: Implement malloc_good_size() and use it for Vector/HashTable This implements the macOS API malloc_good_size() which returns the true allocation size for a given requested allocation size. This allows us to make use of all the available memory in a malloc chunk. For example, for a malloc request of 35 bytes our malloc would internally use a chunk of size 64, however the remaining 29 bytes would be unused. Knowing the true allocation size allows us to request more usable memory that would otherwise be wasted and make that available for Vector, HashTable and potentially other callers in the future. --- AK/HashTable.h | 1 + AK/Vector.h | 2 +- AK/kmalloc.h | 7 +++++++ Kernel/Heap/kmalloc.cpp | 5 +++++ Kernel/Heap/kmalloc.h | 2 ++ Userland/Libraries/LibC/malloc.cpp | 7 +++++++ Userland/Libraries/LibC/stdlib.h | 1 + 7 files changed, 24 insertions(+), 1 deletion(-) diff --git a/AK/HashTable.h b/AK/HashTable.h index eac567a5d6..acfddf9b58 100644 --- a/AK/HashTable.h +++ b/AK/HashTable.h @@ -258,6 +258,7 @@ private: void rehash(size_t new_capacity) { new_capacity = max(new_capacity, static_cast(4)); + new_capacity = kmalloc_good_size(new_capacity * sizeof(Bucket)) / sizeof(Bucket); auto* old_buckets = m_buckets; auto old_capacity = m_capacity; diff --git a/AK/Vector.h b/AK/Vector.h index 74601a2a89..7acc9bdd15 100644 --- a/AK/Vector.h +++ b/AK/Vector.h @@ -563,7 +563,7 @@ public: { if (m_capacity >= needed_capacity) return true; - size_t new_capacity = needed_capacity; + size_t new_capacity = kmalloc_good_size(needed_capacity * sizeof(T)) / sizeof(T); auto* new_buffer = (T*)kmalloc(new_capacity * sizeof(T)); if (new_buffer == nullptr) return false; diff --git a/AK/kmalloc.h b/AK/kmalloc.h index bd5e413a37..8217fe63f1 100644 --- a/AK/kmalloc.h +++ b/AK/kmalloc.h @@ -8,6 +8,12 @@ #ifndef __serenity__ # include + +# ifndef AK_OS_MACOS +inline size_t malloc_good_size(size_t size) { return size; } +# else +# include +# endif #endif #ifdef KERNEL @@ -27,6 +33,7 @@ # define kcalloc calloc # define kmalloc malloc +# define kmalloc_good_size malloc_good_size # define kfree free # define krealloc realloc diff --git a/Kernel/Heap/kmalloc.cpp b/Kernel/Heap/kmalloc.cpp index 1e96825f87..c7759f4ad7 100644 --- a/Kernel/Heap/kmalloc.cpp +++ b/Kernel/Heap/kmalloc.cpp @@ -277,6 +277,11 @@ void* krealloc(void* ptr, size_t new_size) return g_kmalloc_global->m_heap.reallocate(ptr, new_size); } +size_t kmalloc_good_size(size_t size) +{ + return size; +} + void* operator new(size_t size) noexcept { return kmalloc(size); diff --git a/Kernel/Heap/kmalloc.h b/Kernel/Heap/kmalloc.h index 6fdc974c32..624758ea53 100644 --- a/Kernel/Heap/kmalloc.h +++ b/Kernel/Heap/kmalloc.h @@ -66,4 +66,6 @@ inline void kfree_aligned(void* ptr) kfree((u8*)ptr - ((const ptrdiff_t*)ptr)[-1]); } +size_t kmalloc_good_size(size_t); + void kmalloc_enable_expand(); diff --git a/Userland/Libraries/LibC/malloc.cpp b/Userland/Libraries/LibC/malloc.cpp index c175c02daf..43519cf296 100644 --- a/Userland/Libraries/LibC/malloc.cpp +++ b/Userland/Libraries/LibC/malloc.cpp @@ -392,6 +392,13 @@ size_t malloc_size(void* ptr) return size; } +size_t malloc_good_size(size_t size) +{ + size_t good_size; + allocator_for_size(size, good_size); + return good_size; +} + void* realloc(void* ptr, size_t size) { if (!ptr) diff --git a/Userland/Libraries/LibC/stdlib.h b/Userland/Libraries/LibC/stdlib.h index 480e570cc7..c63e7eebc5 100644 --- a/Userland/Libraries/LibC/stdlib.h +++ b/Userland/Libraries/LibC/stdlib.h @@ -21,6 +21,7 @@ __BEGIN_DECLS __attribute__((malloc)) __attribute__((alloc_size(1))) void* malloc(size_t); __attribute__((malloc)) __attribute__((alloc_size(1, 2))) void* calloc(size_t nmemb, size_t); size_t malloc_size(void*); +size_t malloc_good_size(size_t); void serenity_dump_malloc_stats(void); void free(void*); __attribute__((alloc_size(2))) void* realloc(void* ptr, size_t);