When using snmalloc as header-only library in a project that globally defines `WIN32_LEAN_AND_MEAN`, there is a compile error for macro redefinition.
Guard the pal_windows.h define.
* Lift checking for init to ThreadAlloc
The check init code was tightly integrated into LocalAllocator. This commit pull that code out into ThreadAlloc, and passes a template parameter into the remaining LocalAllocator to perform the relevant TLS manipulations. This removes some of the awkward layering around register_clean_up.
* Reduce size of test due to failures.
Fully disable lotsofthreads test
Need to investigate if the test is unreliable, or we have actually
regressed perf. A quick mimalloc-bench didn't show any regressions.
* Simplify message queue initialisation
This introduces one additional branch on when processing a batch of messages, but it is likely to only be hit when a lot of messages are processed.
* Patch Domestication test.
* Refactor CoreAlloc/LocalAlloc
This combines the notion of CoreAlloc, LocalAlloc and LocalCache into a single class. Previously, these were separated so that a more complex structure would be stored directly in the TLS. This however, proved to be bad for compatibility if the allocator is part of the libc implementation.
This commit collapses all the stages of the allocator into a single class. This simplifies the sequencing and overall is a nice reduction in complexity.
* Re-enable lots of threads test.
* Reenable concept using alternative lazy checking for concepts.
* Self code review
This changes the shape of check_bounds to take a continuation to call if the bounds check succeeds. This is designed to allow for easily wrapping existing code with a bounds check, e.g.
```
void* memcpy(void* dest, const void* src, size_t n) {
return check_bounds(dest, n, [&] {
return memcpy_impl(dest, src, n);
});
}
```
If a thread forks, while another thread is holding an snmalloc lock, then the allocator could stop working.
This patch attempts to protect against the cases of this. There is one case that is not covered. If a fork occurs during the very first allocation. This can result in the installation of the fork handler racing with the fork, and all bets are off.
* Factor out small sizeclass check
* Update realloc(p,0) semantics
This commit changes the behaviour of realloc(p,0) to be free(p) if p!=nullptr, and malloc(0) if p== nullptr.
* Fix overflow by alignment
* Bug fix: Ensure bytes_free is the total
The bytes freed was not added to the total, but
overrode it. This meant it never fired. This
commit fixes that.
* Factor out explicit Config type
Instead of using snmalloc::Alloc::Config, expose snmalloc::Config, which is then used to derive the allocator type.
* Move globalalloc to front end.
* Remove unneed template parameter from global snmalloc functions.
* Remove SNMALLOC_PASS_THROUGH
VeronaRT now has an abstraction layer which can easily replace the allocator.
Having such a complex integration still in snmalloc does not make sense.
* Take some global functions off of local alloc.
* Drop comparison overloads on atomic Capptr.
Performing a comparison on two atomic ptr is a complex operation, and should not be implicit. The memory model order and such things needs to be considered by the caller.
* Remove function_ref and use templates
The implementation prefers to use templates over the function_ref. This now only exists in the Pal for a currently unused feature.
* Removing function_ref reduces stl needs.
* Remove use of __is_convertible to support older g++
* Inline function that is only used once.
* Remove unused function
* Restrict ThreadAlloc usage to globalalloc
This commit introduces various inline functions on snmalloc:: that perform allocation/deallocation using the thread local allocator.
They remove all usage from a particular test.
* Move cheri checks to own file.
* Refactor is_owned checks.
* Move alloc_size and check_size to globalalloc.
* Minor simplification of dealloc path
* Fix up is_owned to take a config
* Improve usage of scoped allocator.
* Handle Config_ in globalalloc.
* Add stress test benchmark
Co-authored-by: Alexander Nadeau <wareya@gmail.com>
* Add defensive code against spurious wakeup
This commit checks that wait_on_address has not returned spuriously.
* pal: spurious wake up.
The code in the Pal for wake on address was incorrectly assuming the operation returning success meant it had actually changed. The specification allows for spurious wake ups.
This change makes the Pals recheck for a change.
---------
Co-authored-by: Alexander Nadeau <wareya@gmail.com>
The Pagemap can potentially be accessed where there is no direct
knowledge of the location. On platforms with lazy commit this can
be handled by the OS faulting in a zero page. Here we modify the
Windows PAL to add an exception handler that will commit pages
in the read only range, i.e. the page map. We still require explicit
notify_using to be able to modify the pagemap.
When processing a remote batch, the system will process every single message that was available at the start of processing.
This can lead to a long pause time if there have been a considerable number of frees to this thread.
This commit introduces a new mechanism to only process messages up to a limit of 1MiB. The limit is configurable using CMake.
Choosing too small a limit can cause freeing to never catch up with the incoming messages.
* Removed unneeded headers
This removes some unneeded headers from the headers.
* Remove use of std::string
This stack allocates and copies a c-string to replace the calls to std::string.
* Pickup page size from unistd.h
This uses the PAGESIZE constant from the unistd.h on POSIX.
This should make the code more resilient to being compiled on platforms with
different page sizes.
* Allow pagesize to come from cmake.
* Update src/snmalloc/pal/pal_posix.h
Co-authored-by: Nathaniel Filardo <105816689+nwf-msr@users.noreply.github.com>
---------
Co-authored-by: Nathaniel Filardo <105816689+nwf-msr@users.noreply.github.com>
* Rename dealloc_local_object_slower to _meta
Unlike its brethren, `dealloc_local_object` and
`dealloc_local_object_slow`, the `dealloc_local_object_slower` method
does not take a pointer to free space. Make this slightly more apparent
by renaming it and adding some commentary to both definition and call
site.
* corealloc: get meta in dealloc_local_object
Make both _fast() and _slow() arms take the meta as an argument; _meta()
already did.
* Introduce RemoteMessage structure
Plumb its use around remoteallocator and remotecache
* NFC: Plumb metadata to remotecache dealloc
* Initial steps in batched remote messages
This prepares the recipient to process a batched message.
* Initial dealloc-side batching machinery
Exercise recipient machinery by having the senders collect adjacent frees to
the same slab into a batch.
* Match free batch keying to slab freelist keying
* freelist: add append_segment
* SlabMetadata: machinery for returning multiple objects
This might involve multiple (I think at most two, at the moment) transitions in
the slab lifecycle state machine. Towards that end, return indicators to the
caller that the slow path must be taken and how many objects of the original
set have not yet been counted as returned.
* corealloc: operate ring-at-a-time on remote queues
* RemoteCache associative cache of rings
* RemoteCache: N-set caching
* Initial CHERI support for free rings
* Matt's fix for slow-path codegen
* Try: remotecache: don't store allocator IDs
We can, as Matt so kindly reminds me, go get them from the pagemap. Since we
need this value only when closing a ring, the read from over there is probably
not very onerous. (We could also get the slab pointer from an object in the
ring, but we need that whenever inserting into the cache, so it's probably more
sensible to store that locally?)
* Make BatchIt optional
Move ring set bits and associativity knobs to allocconfig and expose them via
CMake. If associtivity is zero, use non-batched implementations of the
`RemoteMessage` and `RemoteDeallocCacheBatching` classes.
By default, kick BatchIt on when we have enough room in the minimum allocation
size to do it. Exactly how much space is enough is a function of which
mitigations we have enabled and whether or not we are compiling with C++20.
This commit reverts the change to `MIN_ALLOC_SIZE` made in "Introduce
RemoteMessage structure" now that we have multiple types, and zies, of
remote messages to choose from.
* RemoteDeallocCacheBatching: store metas as address
There's no need for a full pointer here, it'd just make the structure larger on
CHERI.
* NFC: plumb entropy from LocalAlloc to BatchIt
* BatchIt random eviction
In order not to thwart `mitigations(random_preserve)` too much, if it's on in
combination with BatchIt, roll the dice every time we append to a batch to
decide if we should stochastically evict this batch. By increasing the number
of batches, we allow the recipient allocator increased opportunity to randomly
stripe batches across the two `freelist::Builder` segments associated with each
slab.
---------
Co-authored-by: Nathaniel Wesley Filardo <nfilardo@microsoft.com>
Co-authored-by: Matthew Parkinson <mattpark@microsoft.com>
When building test/perf/singlethread to use the system allocator, gcc
(Debian 14.2.0-3) correctly sees that we were using the value of a
pointer after it had been passed to the privileged free(), which is UB.
Flip the check and dealloc, so that we query the set of pointers we're
tracking first, using the pointer while the allocation is still live.
In test/perf/startup, gcc (Debian 14.2.0-3) seems to get confused about
the size of the counters vector as the code was written. Rewrite the
code to pass the same value (`std::thread::hardware_concurrency()`, but
in a local) to both `counters.resize()` and the `ParallelTest` ctor.