diff --git a/src/ds/seqset.h b/src/ds/seqset.h index 13f9faf..da5eb46 100644 --- a/src/ds/seqset.h +++ b/src/ds/seqset.h @@ -159,5 +159,13 @@ namespace snmalloc v.end = &(item->next); } } + + /** + * Peek at next element in the set. + */ + SNMALLOC_FAST_PATH const T* peek() + { + return v.head; + } }; } // namespace snmalloc diff --git a/src/mem/corealloc.h b/src/mem/corealloc.h index 89adfc8..f5f03f8 100644 --- a/src/mem/corealloc.h +++ b/src/mem/corealloc.h @@ -689,11 +689,16 @@ namespace snmalloc { #ifdef SNMALLOC_CHECK_CLIENT // Occassionally don't use the last list. - if ( - SNMALLOC_UNLIKELY(alloc_classes[sizeclass].length == 1) && - (entropy.next_bit() == 0)) + if (SNMALLOC_UNLIKELY(alloc_classes[sizeclass].length == 1)) { - return small_alloc_slow(sizeclass, fast_free_list); + // If the slab has a lot of free space, then we shouldn't allocate a + // new slab. + auto min = alloc_classes[sizeclass] + .available.peek() + ->free_queue.min_list_length(); + if ((min * 2) < threshold_for_waking_slab(sizeclass)) + if (entropy.next_bit() == 0) + return small_alloc_slow(sizeclass, fast_free_list); } #endif diff --git a/src/mem/freelist.h b/src/mem/freelist.h index d2e5a18..fbd8509 100644 --- a/src/mem/freelist.h +++ b/src/mem/freelist.h @@ -740,6 +740,20 @@ namespace snmalloc UNUSED(domesticate); #endif } + + /** + * Returns length of the shorter free list. + * + * This method is only usable if the free list is adding randomisation + * as that is when it has two lists. + */ + template + [[nodiscard]] std::enable_if_t min_list_length() const + { + static_assert(RANDOM_ == RANDOM, "Don't set SFINAE parameter!"); + + return length[0] < length[1] ? length[0] : length[1]; + } }; } // namespace freelist } // namespace snmalloc