Changes the representation in Metaslab Used
Used is now set to 1, when the slab is full. This means that the test for used - 1 == 0 can be used to detect leaving full, and entering empty, reducing fast path deallocation branchs by 1.
This commit is contained in:
@@ -61,14 +61,15 @@ namespace snmalloc
|
||||
used++;
|
||||
}
|
||||
|
||||
void sub_use()
|
||||
/**
|
||||
* Removes a use, if the slab is either
|
||||
* - empty after removing the use, or
|
||||
* - was full before the substraction
|
||||
* this returns true, otherwise returns false.
|
||||
**/
|
||||
bool sub_use()
|
||||
{
|
||||
used--;
|
||||
}
|
||||
|
||||
void set_unused()
|
||||
{
|
||||
used = 0;
|
||||
return (--used) == 0;
|
||||
}
|
||||
|
||||
bool is_unused()
|
||||
@@ -78,7 +79,9 @@ namespace snmalloc
|
||||
|
||||
bool is_full()
|
||||
{
|
||||
return link == 1;
|
||||
auto result = link == 1;
|
||||
assert(!result || head == 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
void set_full()
|
||||
@@ -86,6 +89,9 @@ namespace snmalloc
|
||||
assert(head == 1);
|
||||
assert(link != 1);
|
||||
link = 1;
|
||||
// Set used to 1, so that "sub_use" will return true after calling
|
||||
// set_full
|
||||
used = 1;
|
||||
}
|
||||
|
||||
SlabLink* get_link(Slab* slab)
|
||||
@@ -175,23 +181,21 @@ namespace snmalloc
|
||||
void debug_slab_invariant(bool is_short, Slab* slab)
|
||||
{
|
||||
#if !defined(NDEBUG) && !defined(SNMALLOC_CHEAP_CHECKS)
|
||||
size_t size = sizeclass_to_size(sizeclass);
|
||||
size_t offset = get_initial_offset(sizeclass, is_short);
|
||||
|
||||
if (is_unused())
|
||||
return;
|
||||
|
||||
size_t accounted_for = used * size + offset;
|
||||
|
||||
if (is_full())
|
||||
{
|
||||
// All the blocks must be used.
|
||||
assert(SLAB_SIZE == accounted_for);
|
||||
// There is no free list to validate
|
||||
// 'link' value is not important if full.
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_unused())
|
||||
return;
|
||||
|
||||
size_t size = sizeclass_to_size(sizeclass);
|
||||
size_t offset = get_initial_offset(sizeclass, is_short);
|
||||
size_t accounted_for = used * size + offset;
|
||||
|
||||
|
||||
// Block is not full
|
||||
assert(SLAB_SIZE > accounted_for);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace snmalloc
|
||||
// We use size_t as it generates better code.
|
||||
using sizeclass_t = size_t;
|
||||
// using sizeclass_t = uint8_t;
|
||||
using sizeclass_compress_t = uint8_t;
|
||||
|
||||
constexpr static uint16_t get_initial_offset(sizeclass_t sc, bool is_short);
|
||||
constexpr static size_t sizeclass_to_size(sizeclass_t sizeclass);
|
||||
|
||||
@@ -163,14 +163,9 @@ namespace snmalloc
|
||||
error("Detected potential double free.");
|
||||
#endif
|
||||
meta.debug_slab_invariant(is_short(), this);
|
||||
meta.sub_use();
|
||||
|
||||
bool was_full = meta.is_full();
|
||||
if (unlikely(was_full))
|
||||
return false;
|
||||
|
||||
bool is_unused = meta.is_unused();
|
||||
if (unlikely(is_unused))
|
||||
|
||||
if (unlikely(meta.sub_use()))
|
||||
return false;
|
||||
|
||||
// Update the head and the next pointer in the free list.
|
||||
@@ -198,13 +193,10 @@ namespace snmalloc
|
||||
{
|
||||
Metaslab& meta = super->get_meta(this);
|
||||
|
||||
bool was_full = meta.is_full();
|
||||
bool is_unused = meta.is_unused();
|
||||
|
||||
if (was_full)
|
||||
if (meta.is_full())
|
||||
{
|
||||
// We are not on the sizeclass list.
|
||||
if (is_unused)
|
||||
if (meta.allocated == 1)
|
||||
{
|
||||
// Dealloc on the superslab.
|
||||
if (is_short())
|
||||
@@ -217,6 +209,7 @@ namespace snmalloc
|
||||
assert(meta.head == 1);
|
||||
// assert(meta.fully_allocated(is_short()));
|
||||
meta.link = index;
|
||||
meta.used = meta.allocated - 1;
|
||||
|
||||
// Push on the list of slabs for this sizeclass.
|
||||
sl->insert_back(meta.get_link(this));
|
||||
@@ -224,18 +217,13 @@ namespace snmalloc
|
||||
return Superslab::NoSlabReturn;
|
||||
}
|
||||
|
||||
if (is_unused)
|
||||
{
|
||||
// Remove from the sizeclass list and dealloc on the superslab.
|
||||
sl->remove(meta.get_link(this));
|
||||
// Remove from the sizeclass list and dealloc on the superslab.
|
||||
sl->remove(meta.get_link(this));
|
||||
|
||||
if (is_short())
|
||||
return super->dealloc_short_slab(memory_provider);
|
||||
if (is_short())
|
||||
return super->dealloc_short_slab(memory_provider);
|
||||
|
||||
return super->dealloc_slab(this, memory_provider);
|
||||
}
|
||||
|
||||
abort();
|
||||
return super->dealloc_slab(this, memory_provider);
|
||||
}
|
||||
|
||||
bool is_short()
|
||||
|
||||
Reference in New Issue
Block a user