Skip to content

Commit

Permalink
sizeclass: distinguish min alloc and step size
Browse files Browse the repository at this point in the history
Add support for a minimum allocation size that isn't the minimum step of
the sizeclass table.
  • Loading branch information
nwf-msr committed Jan 4, 2024
1 parent de062e9 commit 7d0b53e
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 11 deletions.
23 changes: 19 additions & 4 deletions src/snmalloc/ds/allocconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,21 @@ namespace snmalloc
// Used to isolate values on cache lines to prevent false sharing.
static constexpr size_t CACHELINE_SIZE = 64;

// Minimum allocation size is space for two pointers.
static_assert(bits::next_pow2_const(sizeof(void*)) == sizeof(void*));
/// The "machine epsilon" for the small sizeclass machinery.
static constexpr size_t MIN_ALLOC_STEP_SIZE = 2 * sizeof(void*);

/// Derived from MIN_ALLOC_STEP_SIZE
static constexpr size_t MIN_ALLOC_STEP_BITS =
bits::ctz_const(MIN_ALLOC_STEP_SIZE);
static_assert(bits::is_pow2(MIN_ALLOC_STEP_SIZE));

/**
* Minimum allocation size is space for two pointers. If the small sizeclass
* machinery permits smaller values (that is, if MIN_ALLOC_STEP_SIZE is
* smaller than MIN_ALLOC_SIZE), which may be useful if MIN_ALLOC_SIZE must
* be large or not a power of two, those smaller size classes will be unused.
*/
static constexpr size_t MIN_ALLOC_SIZE = 2 * sizeof(void*);
static constexpr size_t MIN_ALLOC_BITS = bits::ctz_const(MIN_ALLOC_SIZE);

// Minimum slab size.
#if defined(SNMALLOC_QEMU_WORKAROUND) && defined(SNMALLOC_VA_BITS_64)
Expand Down Expand Up @@ -78,11 +89,15 @@ namespace snmalloc
static constexpr size_t REMOTE_MASK = REMOTE_SLOTS - 1;

static_assert(
INTERMEDIATE_BITS < MIN_ALLOC_BITS,
INTERMEDIATE_BITS < MIN_ALLOC_STEP_BITS,
"INTERMEDIATE_BITS must be less than MIN_ALLOC_BITS");
static_assert(
MIN_ALLOC_SIZE >= (sizeof(void*) * 2),
"MIN_ALLOC_SIZE must be sufficient for two pointers");
static_assert(
1 << (INTERMEDIATE_BITS + MIN_ALLOC_STEP_BITS) >=
bits::next_pow2_const(MIN_ALLOC_SIZE),
"Entire sizeclass exponent is below MIN_ALLOC_SIZE; adjust STEP_SIZE");
// Return remote small allocs when the local cache reaches this size.
static constexpr int64_t REMOTE_CACHE =
Expand Down
31 changes: 24 additions & 7 deletions src/snmalloc/mem/sizeclasstable.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace snmalloc
// For example, 24 byte allocations can be
// problematic for some data due to alignment issues.
auto sc = static_cast<smallsizeclass_t>(
bits::to_exp_mant_const<INTERMEDIATE_BITS, MIN_ALLOC_BITS>(size));
bits::to_exp_mant_const<INTERMEDIATE_BITS, MIN_ALLOC_STEP_BITS>(size));

SNMALLOC_ASSERT(sc == static_cast<uint8_t>(sc));

Expand Down Expand Up @@ -216,7 +216,8 @@ namespace snmalloc
auto& meta = fast_small(sizeclass);

size_t rsize =
bits::from_exp_mant<INTERMEDIATE_BITS, MIN_ALLOC_BITS>(sizeclass);
bits::from_exp_mant<INTERMEDIATE_BITS, MIN_ALLOC_STEP_BITS>(
sizeclass);
meta.size = rsize;
size_t slab_bits = bits::max(
bits::next_pow2_bits_const(MIN_OBJECT_COUNT * rsize), MIN_CHUNK_BITS);
Expand Down Expand Up @@ -407,7 +408,7 @@ namespace snmalloc
{
// We subtract and shift to reduce the size of the table, i.e. we don't have
// to store a value for every size.
return (s - 1) >> MIN_ALLOC_BITS;
return (s - 1) >> MIN_ALLOC_STEP_BITS;
}

constexpr size_t sizeclass_lookup_size =
Expand All @@ -423,13 +424,29 @@ namespace snmalloc

constexpr SizeClassLookup()
{
constexpr sizeclass_compress_t minimum_class =
static_cast<sizeclass_compress_t>(
size_to_sizeclass_const(MIN_ALLOC_SIZE));

/* Some unused sizeclasses is OK, but keep it within reason! */
static_assert(minimum_class < sizeclass_lookup_size);

size_t curr = 1;
for (sizeclass_compress_t sizeclass = 0;
sizeclass < NUM_SMALL_SIZECLASSES;
sizeclass++)

sizeclass_compress_t sizeclass = 0;
for (; sizeclass < minimum_class; sizeclass++)
{
for (; curr <= sizeclass_metadata.fast_small(sizeclass).size;
curr += 1 << MIN_ALLOC_STEP_BITS)
{
table[sizeclass_lookup_index(curr)] = minimum_class;
}
}

for (; sizeclass < NUM_SMALL_SIZECLASSES; sizeclass++)
{
for (; curr <= sizeclass_metadata.fast_small(sizeclass).size;
curr += 1 << MIN_ALLOC_BITS)
curr += 1 << MIN_ALLOC_STEP_BITS)
{
auto i = sizeclass_lookup_index(curr);
if (i == sizeclass_lookup_size)
Expand Down

0 comments on commit 7d0b53e

Please sign in to comment.