Bug fix for superslab meta-data (#302)

* Replace time measuring macro

The DO_TIME macro was used originally to get performance numbers. The
macro makes tests hard to debug. This commit replaces it with a proper
C++ class with destructor.

* Bug fix

If the superslab meta data is large, then the calculation for the
sizeclasses that could use the short slab was incorrect.  This fixes
that calculation.

Co-authored-by: Nathaniel Wesley Filardo <nfilardo@microsoft.com>
This commit is contained in:
Matthew Parkinson
2021-03-23 12:42:11 +00:00
committed by GitHub
parent 04a185e634
commit 63f231f484
7 changed files with 91 additions and 57 deletions

View File

@@ -32,8 +32,7 @@ namespace snmalloc
static SNMALLOC_FAST_PATH void
alloc_new_list(void*& bumpptr, FreeListIter& fast_free_list, size_t rsize)
{
void* slab_end =
pointer_align_up<SLAB_SIZE>(pointer_offset(bumpptr, rsize));
void* slab_end = pointer_align_up<SLAB_SIZE>(pointer_offset(bumpptr, 1));
FreeListBuilder b;
SNMALLOC_ASSERT(b.empty());

View File

@@ -4,14 +4,32 @@
#include "allocslab.h"
#include "metaslab.h"
#include <iostream>
#include <new>
namespace snmalloc
{
/**
* Superslabs are, to first approximation, a `CHUNK_SIZE`-sized and -aligned
* region of address space, internally composed of a header (a `Superslab`
* structure) followed by an array of `Slab`s, each `SLAB_SIZE`-sized and
* -aligned. Each active `Slab` holds an array of identically sized
* allocations strung on an invasive free list, which is lazily constructed
* from a bump-pointer allocator (see `Metaslab::alloc_new_list`).
*
* In order to minimize overheads, Slab metadata is held externally, in
* `Metaslab` structures; all `Metaslab`s for the Slabs within a Superslab are
* densely packed within the `Superslab` structure itself. Moreover, as the
* `Superslab` structure is typically much smaller than `SLAB_SIZE`, a "short
* Slab" is overlaid with the `Superslab`. This short Slab can hold only
* allocations that are smaller than the `SLAB_SIZE - sizeof(Superslab)`
* bytes; see `Superslab::is_short_sizeclass`. The Metaslab state for a short
* slabs is constructed in a way that avoids branches on fast paths;
* effectively, the object slots that overlay the `Superslab` at the start are
* omitted from consideration.
*/
class Superslab : public Allocslab
{
// This is the view of a 16 mb superslab when it is being used to allocate
// 64 kb slabs.
private:
friend DLList<Superslab>;
@@ -73,8 +91,17 @@ namespace snmalloc
static bool is_short_sizeclass(sizeclass_t sizeclass)
{
constexpr sizeclass_t h = size_to_sizeclass_const(sizeof(Superslab));
return sizeclass <= h;
static_assert(SLAB_SIZE > sizeof(Superslab), "Meta data requires this.");
/*
* size_to_sizeclass_const rounds *up* and returns the smallest class that
* could contain (and so may be larger than) the free space available for
* the short slab. While we could detect the exact fit case and compare
* `<= h` therein, it's simpler to just treat this class as a strict upper
* bound and only permit strictly smaller classes in short slabs.
*/
constexpr sizeclass_t h =
size_to_sizeclass_const(SLAB_SIZE - sizeof(Superslab));
return sizeclass < h;
}
void init(RemoteAllocator* alloc)