SP: start plumbing CapPtr<>s

This commit is contained in:
Nathaniel Filardo
2021-03-05 16:46:25 +00:00
committed by Nathaniel Wesley Filardo
parent 313a682faf
commit 005f5787ef
10 changed files with 431 additions and 304 deletions

View File

@@ -17,9 +17,12 @@ namespace snmalloc
}
public:
static Metaslab& get_meta(Slab* self)
template<capptr_bounds B>
static CapPtr<Metaslab, B> get_meta(CapPtr<Slab, B> self)
{
Superslab* super = Superslab::get(self);
static_assert(B == CBArena || B == CBChunk);
auto super = Superslab::get(self);
return super->get_meta(self);
}
@@ -30,12 +33,12 @@ namespace snmalloc
* page.
*/
static SNMALLOC_FAST_PATH void alloc_new_list(
void*& bumpptr,
CapPtr<void, CBArena>& bumpptr,
FreeListIter& fast_free_list,
size_t rsize,
LocalEntropy& entropy)
{
void* slab_end = pointer_align_up<SLAB_SIZE>(pointer_offset(bumpptr, 1));
auto slab_end = pointer_align_up<SLAB_SIZE>(pointer_offset(bumpptr, 1));
FreeListBuilder<false> b;
SNMALLOC_ASSERT(b.empty());
@@ -46,23 +49,27 @@ namespace snmalloc
// Structure to represent the temporary list elements
struct PreAllocObject
{
PreAllocObject* next;
CapPtr<PreAllocObject, CBArena> next;
};
// The following code implements Sattolo's algorithm for generating
// random cyclic permutations. This implementation is in the opposite
// direction, so that the original space does not need initialising. This
// is described as outside-in without citation on Wikipedia, appears to be
// Folklore algorithm.
PreAllocObject* curr = pointer_offset<PreAllocObject>(bumpptr, 0);
auto curr =
pointer_offset(bumpptr, 0).template as_static<PreAllocObject>();
curr->next = curr;
uint16_t count = 1;
for (PreAllocObject* p = pointer_offset<PreAllocObject>(bumpptr, rsize);
p < slab_end;
p = pointer_offset<PreAllocObject>(p, rsize))
for (auto p = pointer_offset(bumpptr, rsize)
.template as_static<PreAllocObject>();
p.as_void() < slab_end;
p = pointer_offset(p, rsize).template as_static<PreAllocObject>())
{
size_t insert_index = entropy.sample(count);
p->next = std::exchange(
pointer_offset<PreAllocObject>(bumpptr, insert_index * rsize)->next,
pointer_offset(bumpptr, insert_index * rsize)
.template as_static<PreAllocObject>()
->next,
p);
count++;
}
@@ -70,18 +77,18 @@ namespace snmalloc
// Pick entry into space, and then build linked list by traversing cycle
// to the start.
auto start_index = entropy.sample(count);
auto start_ptr =
pointer_offset<PreAllocObject>(bumpptr, start_index * rsize);
auto start_ptr = pointer_offset(bumpptr, start_index * rsize)
.template as_static<PreAllocObject>();
auto curr_ptr = start_ptr;
do
{
b.add(curr_ptr, entropy);
b.add(FreeObject::make(curr_ptr.as_void()), entropy);
curr_ptr = curr_ptr->next;
} while (curr_ptr != start_ptr);
#else
for (void* p = bumpptr; p < slab_end; p = pointer_offset<void>(p, rsize))
for (auto p = bumpptr; p < slab_end; p = pointer_offset(p, rsize))
{
b.add(p, entropy);
b.add(FreeObject::make(p.as_void()), entropy);
}
#endif
// This code consumes everything up to slab_end.
@@ -94,20 +101,20 @@ namespace snmalloc
// Returns true, if it deallocation can proceed without changing any status
// bits. Note that this does remove the use from the meta slab, so it
// doesn't need doing on the slow path.
//
// This is pre-factored to take an explicit self parameter so that we can
// eventually annotate that pointer with additional information.
static SNMALLOC_FAST_PATH bool
dealloc_fast(Slab* self, Superslab* super, void* p, LocalEntropy& entropy)
static SNMALLOC_FAST_PATH bool dealloc_fast(
CapPtr<Slab, CBArena> self,
CapPtr<Superslab, CBArena> super,
CapPtr<FreeObject, CBArena> p,
LocalEntropy& entropy)
{
Metaslab& meta = super->get_meta(self);
SNMALLOC_ASSERT(!meta.is_unused());
auto meta = super->get_meta(self);
SNMALLOC_ASSERT(!meta->is_unused());
if (unlikely(meta.return_object()))
if (unlikely(meta->return_object()))
return false;
// Update the head and the next pointer in the free list.
meta.free_queue.add(p, entropy);
meta->free_queue.add(p, entropy);
return true;
}
@@ -116,23 +123,20 @@ namespace snmalloc
// This does not need to remove the "use" as done by the fast path.
// Returns a complex return code for managing the superslab meta data.
// i.e. This deallocation could make an entire superslab free.
//
// This is pre-factored to take an explicit self parameter so that we can
// eventually annotate that pointer with additional information.
static SNMALLOC_SLOW_PATH typename Superslab::Action dealloc_slow(
Slab* self,
CapPtr<Slab, CBArena> self,
SlabList* sl,
Superslab* super,
void* p,
CapPtr<Superslab, CBArena> super,
CapPtr<FreeObject, CBArena> p,
LocalEntropy& entropy)
{
Metaslab& meta = super->get_meta(self);
meta.debug_slab_invariant(self, entropy);
auto meta = super->get_meta(self);
meta->debug_slab_invariant(self, entropy);
if (meta.is_full())
if (meta->is_full())
{
auto allocated = get_slab_capacity(
meta.sizeclass(), Metaslab::is_short(Metaslab::get_slab(p)));
meta->sizeclass(), Metaslab::is_short(Metaslab::get_slab(p)));
// We are not on the sizeclass list.
if (allocated == 1)
{
@@ -143,15 +147,15 @@ namespace snmalloc
return super->dealloc_slab(self);
}
meta.free_queue.add(p, entropy);
meta->free_queue.add(p, entropy);
// Remove trigger threshold from how many we need before we have fully
// freed the slab.
meta.needed() =
allocated - meta.threshold_for_waking_slab(Metaslab::is_short(self));
meta->needed() =
allocated - meta->threshold_for_waking_slab(Metaslab::is_short(self));
// Push on the list of slabs for this sizeclass.
sl->insert_prev(&meta);
meta.debug_slab_invariant(self, entropy);
sl->insert_prev(meta.template as_static<SlabLink>());
meta->debug_slab_invariant(self, entropy);
return Superslab::NoSlabReturn;
}
@@ -160,7 +164,7 @@ namespace snmalloc
// Check free list is well-formed on platforms with
// integers as pointers.
FreeListIter fl;
meta.free_queue.close(fl, entropy);
meta->free_queue.close(fl, entropy);
while (!fl.empty())
{
@@ -169,7 +173,7 @@ namespace snmalloc
}
#endif
meta.remove();
meta->remove();
if (Metaslab::is_short(self))
return super->dealloc_short_slab();