The primary aim for this refactor is to use a representation for
sizeclasses that uniformly covers both large and small. This allows
certain operations such as alloc_size and external_pointer to be
uniformly implemented.
The additional types make clear which kind of sizeclass is in use.
This also tidies up the code for sizeclass based divisible by and
modulus.
It fixes a bug in rust_realloc that didn't correctly determine a realloc
was required for large classes.
With the new snmalloc2 changes it seems the larger window is leading to
more fragmentation and harming performance. Reducing size still
provides good batching, improves memory overhead.
On systems with larger than 16KiB page size, we have chunks
that divide a page. This seems a little strange, and if we
want to disable the pages backing a chunk, this is not possible.
This change ensures the chunk is always at least a single page.
# Pagemap
The Pagemap now stores all the meta-data for the object allocation. The meta-data in the pagemap is effectively a triple of the sizeclass, the remote allocator, and a pointer to a 64 byte block of meta-data for this chunk of memory. By storing the pointer to a block, it allows the pagemap to handle multiple slab sizes without branching on the fast path. There is one entry in the pagemap per 16KiB of address space, but by using the same entry in the pagemap for 4 adjacent entries, then we can treat a 64KiB range can be treated as a single slab of allocations.
This change also means there is almost no capability amplification required by the implementation on CHERI for finding meta-data. The only amplification is required, when we change the way a chunk is used to a size of object allocation.
# Backend
There is a second major aspect of the refactor that there is now a narrow API that abstracts the Pagemap, PAL and address space management. This should better enable the compartmentalisation and makes it easier to produce alternative backends for various research directions. This is a template parameter that can be used to specialised by the front-end in different ways.
# Thread local state
The thread local state has been refactored into two components, one (called 'localalloc') that is stored directly in the TLS and is constant initialised, and one that is allocated in the address space (called 'coreallloc') which is lazily created and pooled.
# Difference
This removes Superslabs/Medium slabs as there meta-data is now part of the pagemap.
This had not been observed as an issue prior to
923705e514 because CMakeLists.txt had, until
then, been using EQUAL, not STREQUAL, to test for oe (and to then enable
USE_SMALL_CHUNKS). This test would fail, and so the default SLAB_SIZE was
used. Absent this min operation, the use of a whole page on a 64KiB page
causes a crash when using the largest medium size class, as, ultimately, size
classes are not based on page sizes, and so committing a whole page to the
header leaves too little room for that class.
See also 3d3b048776.
This change makes the original 16MiB option not the common option.
It also changes the names of the defines to
SNMALLOC_USE_LARGE_CHUNKS
SNMALLOC_USE_SMALL_CHUNKS
The second should be set for Open Enclave configuration, and results in
256KiB chunk sizes. The first being set builds the original 16MiB chunk
sizes. If neither is set, then we default to 1MiB chunk sizes.
* Increase Remote batch size
The remote batch size has not changed since the fast path optimisations.
The optimisations mean we are checking the queue considerably less
often, so the batch should be larger. This has a dramatic improvement
on performance on a few of the mimalloc microbenchmarks.
It is set to 4096 as this should cover the worse case scenario of only
remote deallocation at 16 bytes for the 2^16 slab size.
* Fixes for Clang-10
Clang-10 outputs a warning for calling alignment intrinsic with an
alignment of 1. At add constexpr to handle this case.
Improve remote dealloc
- Outline the slow path to improve code gen significantly
- Handle message queue only on slow path for remote dealloc.
- Change remote size to count down 0, so fast path does not need a constant.
- Use signed value so that branch does not depend on addition.
This does not deallocate memory until the OS tells us that we are short
on memory, then tries to decommit all of the cached chunks (except for
the first page, used for the linked lists).
Nowhere near enough testing to commit to master yet!