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:
Matthew Parkinson
2019-11-19 16:25:27 +00:00
parent b889f11d04
commit cb4b8fa545
3 changed files with 33 additions and 40 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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()