-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an Allocator::deallocate_zeroed
trait method
#137
Comments
The default implementation would just be to call How do you expect collections to make use of
No? I think you must have mixed something up somewhere. Background zeroing is already supported just fine, e.g. something like unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
self.work_queue.push(|| async move {
cooperative_memset(ptr, 0, layout.size()).await;
unsafe { self.deallocate_zeroed(ptr, layout) };
});
}
|
Thanks for the response!
Thanks, I was indeed thinking backwards in this case (was thinking about adapting a
A
Two things:
Anyways, I do appreciate that this is a fairly niche use case, and might not be worth investing in from an ecosystem point of view. FWIW, I've started a crate that introduces a |
This isn't particularly composable either, as now your structure is doing more work to zero the used memory region even for allocators that just treat the entire dealloc as uninitialized. So what you need is something more like realloc, in that you pass both the alloc layout and more info, in this case the subregions which need to be zeroed. I think your use case would be best served by something like the |
Summary
Add an
Allocator::deallocate_zeroed
trait method that is a dual toallocate_zeroed
. It would inheritAllocator::deallocate
'sunsafe
contract and additionally require that callers only pass memory that is already zeroed.Motivation
I am working in a soft real-time embedded system where
Because of (2) I cannot rely on fresh
mmap
s to get zero pages, usemadvise(DONTNEED)
, or let the OS zero pages in the background for me.Instead, I use a custom allocator which keeps track of already-zeroed memory blocks. This makes on-demand zeroing during allocation unnecessary, and we can avoid zeroing memory on the critical path. The zeroing is performed asynchronously, off the critical path, in a cooperatively-yielding loop that zeroes up-to-N-bytes-large chunks of a memory block during each iteration. Additionally, I can sometimes avoid zeroing the full memory block, relying on application logic to determine that certain portions of the (initially zero) memory block were not modified (and therefore remain zeroed). Once the memory block has been fully zeroed, it is then returned to the allocator, which inserts the block into its already-zeroed freelist.1
Anyways, this system works if I call my allocator's methods directly, but it does not play nice with the
Allocator
trait. This prevents abstraction, librarification, and separation of concerns.Open Questions
Should this be a provided method? If so, what should the default be?
Should it be effectively a
memset(0)
followed byself.free
?That would always be correct, and is ideal when there is no OS/virtual memory. However, it may be undesirable for large allocations when virtual memory and syscalls are available, and you can just do the equivalent of
madvise(DONTNEED)
. The tricky bit is that (AFAIK) there isn't a mechanism forstd
to override default provided methods of traits fromalloc
. I suppose concreteAllocator
implementations can always override the method to domadvise(DONTNEED)
themselves, but if every implementation is doing the same override under the same conditions, then that seems unfortunate.Alternatively, the method could be fallible, and could simply return an error by default and force callers to figure out what to do in that case. This essentially un-asks the previous question around
memset(0)
vsmadvise(DONTNEED)
. But it doesn't really seem like all callers can make effective decisions here, what should a collection library do if the method returns an error? Unclear.We could also make it required method, but that seems like an annoying complication to an otherwise-simple trait. Especially for a relatively niche use case.
Alternatives
Footnotes
This system is similar to the concurrent bulk zeroing described in Why Nothing Matters: The Impact of Zeroing by Yang et al, and
Allocator::allocate_zeroed
's default implementation is what that paper calls "hot-path zeroing". Essentially, theAllocator
trait only supports lazy, on-demand, "hot-path" zeroing. Adding this method would extend its support to eager, concurrent, background zeroing. ↩The text was updated successfully, but these errors were encountered: