Randomise slab filling (#397)
# Free List builder track length This commit makes the free list builder track the length of the lists in the Random case. # Refactor free list creation. Minor refactoring to share code between the new free list and existing path. # Randomise slab filling Knowing when a slab is going to become full makes it easier to by pass the free list entries as protection for OOB writes. This commit randomises when a slab will become full. This commit changes two things * the free list builder can return some fraction of the deallocations on a slab. * when there is a single free slab, we can with some probability allocate an additional slab. These two combine to make it difficult to predict when a slab will be free. # Apply suggestions from code review Co-authored-by: Nathaniel Wesley Filardo <nfilardo@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
8ac2adc4e5
commit
bba66e4f7e
@@ -188,7 +188,7 @@ namespace snmalloc
|
||||
|
||||
static SNMALLOC_FAST_PATH void alloc_new_list(
|
||||
CapPtr<void, CBChunk>& bumpptr,
|
||||
FreeListIter& fast_free_list,
|
||||
Metaslab* meta,
|
||||
size_t rsize,
|
||||
size_t slab_size,
|
||||
LocalEntropy& entropy)
|
||||
@@ -197,8 +197,7 @@ namespace snmalloc
|
||||
|
||||
auto& key = entropy.get_free_list_key();
|
||||
|
||||
FreeListBuilder<false> b;
|
||||
SNMALLOC_ASSERT(b.empty());
|
||||
auto& b = meta->free_queue;
|
||||
|
||||
#ifdef SNMALLOC_CHECK_CLIENT
|
||||
// Structure to represent the temporary list elements
|
||||
@@ -243,7 +242,7 @@ namespace snmalloc
|
||||
auto curr_ptr = start_ptr;
|
||||
do
|
||||
{
|
||||
b.add(FreeObject::make(curr_ptr.as_void()), key);
|
||||
b.add(FreeObject::make(curr_ptr.as_void()), key, entropy);
|
||||
curr_ptr = curr_ptr->next;
|
||||
} while (curr_ptr != start_ptr);
|
||||
#else
|
||||
@@ -256,16 +255,14 @@ namespace snmalloc
|
||||
#endif
|
||||
// This code consumes everything up to slab_end.
|
||||
bumpptr = slab_end;
|
||||
|
||||
SNMALLOC_ASSERT(!b.empty());
|
||||
b.close(fast_free_list, key);
|
||||
}
|
||||
|
||||
ChunkRecord* clear_slab(Metaslab* meta, sizeclass_t sizeclass)
|
||||
{
|
||||
auto& key = entropy.get_free_list_key();
|
||||
FreeListIter fl;
|
||||
meta->free_queue.close(fl, key);
|
||||
auto more = meta->free_queue.close(fl, key);
|
||||
UNUSED(more);
|
||||
void* p = finish_alloc_no_zero(fl.take(key), sizeclass);
|
||||
|
||||
#ifdef SNMALLOC_CHECK_CLIENT
|
||||
@@ -278,6 +275,21 @@ namespace snmalloc
|
||||
count++;
|
||||
}
|
||||
// Check the list contains all the elements
|
||||
SNMALLOC_ASSERT(
|
||||
(count + more) == snmalloc::sizeclass_to_slab_object_count(sizeclass));
|
||||
|
||||
if (more > 0)
|
||||
{
|
||||
auto no_more = meta->free_queue.close(fl, key);
|
||||
SNMALLOC_ASSERT(no_more == 0);
|
||||
UNUSED(no_more);
|
||||
|
||||
while (!fl.empty())
|
||||
{
|
||||
fl.take(key);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
SNMALLOC_ASSERT(
|
||||
count == snmalloc::sizeclass_to_slab_object_count(sizeclass));
|
||||
#endif
|
||||
@@ -582,15 +594,32 @@ namespace snmalloc
|
||||
|
||||
// Look to see if we can grab a free list.
|
||||
auto& sl = alloc_classes[sizeclass].queue;
|
||||
if (likely(!(sl.is_empty())))
|
||||
if (likely(alloc_classes[sizeclass].length > 0))
|
||||
{
|
||||
#ifdef SNMALLOC_CHECK_CLIENT
|
||||
// Occassionally don't use the last list.
|
||||
if (
|
||||
unlikely(alloc_classes[sizeclass].length == 1) &&
|
||||
(entropy.next_bit() == 0))
|
||||
{
|
||||
return small_alloc_slow<zero_mem>(sizeclass, fast_free_list, rsize);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto meta = sl.pop();
|
||||
// Drop length of sl, and empty count if it was empty.
|
||||
alloc_classes[sizeclass].length--;
|
||||
if (meta->needed() == 0)
|
||||
alloc_classes[sizeclass].unused--;
|
||||
|
||||
auto p = Metaslab::alloc(meta, fast_free_list, entropy, sizeclass);
|
||||
auto [p, still_active] =
|
||||
Metaslab::alloc_free_list(meta, fast_free_list, entropy, sizeclass);
|
||||
|
||||
if (still_active)
|
||||
{
|
||||
alloc_classes[sizeclass].length++;
|
||||
sl.insert(meta);
|
||||
}
|
||||
|
||||
return finish_alloc<zero_mem, SharedStateHandle>(p, sizeclass);
|
||||
}
|
||||
@@ -641,16 +670,20 @@ namespace snmalloc
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Build a free list for the slab
|
||||
alloc_new_list(slab, fast_free_list, rsize, slab_size, entropy);
|
||||
|
||||
// Set meta slab to empty.
|
||||
meta->initialise(sizeclass);
|
||||
|
||||
auto& key = entropy.get_free_list_key();
|
||||
// Build a free list for the slab
|
||||
alloc_new_list(slab, meta, rsize, slab_size, entropy);
|
||||
|
||||
// take an allocation from the free list
|
||||
auto p = fast_free_list.take(key);
|
||||
auto [p, still_active] =
|
||||
Metaslab::alloc_free_list(meta, fast_free_list, entropy, sizeclass);
|
||||
|
||||
if (still_active)
|
||||
{
|
||||
alloc_classes[sizeclass].length++;
|
||||
alloc_classes[sizeclass].queue.insert(meta);
|
||||
}
|
||||
|
||||
return finish_alloc<zero_mem, SharedStateHandle>(p, sizeclass);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user