From cb4b8fa545af534444caa18ca1a9a8c436a0ebd5 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Tue, 19 Nov 2019 16:25:27 +0000 Subject: [PATCH] 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. --- src/mem/metaslab.h | 40 ++++++++++++++++++++++------------------ src/mem/sizeclass.h | 1 + src/mem/slab.h | 32 ++++++++++---------------------- 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/src/mem/metaslab.h b/src/mem/metaslab.h index b422e99..9acfd45 100644 --- a/src/mem/metaslab.h +++ b/src/mem/metaslab.h @@ -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); diff --git a/src/mem/sizeclass.h b/src/mem/sizeclass.h index eb2ef61..1a63d94 100644 --- a/src/mem/sizeclass.h +++ b/src/mem/sizeclass.h @@ -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); diff --git a/src/mem/slab.h b/src/mem/slab.h index a3fe45e..0fded27 100644 --- a/src/mem/slab.h +++ b/src/mem/slab.h @@ -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()