Simplify remote allocator.

Don't store the sizeclass, as we can find it easily, and already are
going to touch though cache lines in the common case.
This commit is contained in:
Matthew Parkinson
2019-02-05 13:06:24 +00:00
parent 122a5de811
commit 83c55fe5da
2 changed files with 27 additions and 69 deletions

View File

@@ -536,8 +536,7 @@ namespace snmalloc
this->size += sizeclass_to_size(sizeclass);
Remote* r = (Remote*)p;
r->set_sizeclass_and_target_id(target_id, sizeclass);
assert(r->sizeclass() == sizeclass);
r->set_target_id(target_id);
assert(r->target_id() == target_id);
RemoteList* l = &list[get_slot(target_id, 0)];
@@ -702,21 +701,34 @@ namespace snmalloc
{
if (p != &stub)
{
uint8_t sizeclass = p->sizeclass();
Superslab* super = Superslab::get(p);
if (p->target_id() == id())
if (super->get_kind() == Super)
{
stats().remote_receive(sizeclass);
if (sizeclass < NUM_SMALL_CLASSES)
small_dealloc(Superslab::get(p), p, sizeclass);
Slab* slab = Slab::get(p);
Metaslab& meta = super->get_meta(slab);
if (p->target_id() == id())
{
small_dealloc(super, p, meta.sizeclass);
}
else
medium_dealloc(Mediumslab::get(p), p, sizeclass);
{
// Queue for remote dealloc elsewhere.
remote.dealloc(p->target_id(), p, meta.sizeclass);
}
}
else
{
// Queue for remote dealloc elsewhere.
remote.dealloc(p->target_id(), p, sizeclass);
Mediumslab* slab = Mediumslab::get(p);
if (p->target_id() == id())
{
medium_dealloc(slab, p, slab->get_sizeclass());
}
else
{
// Queue for remote dealloc elsewhere.
remote.dealloc(p->target_id(), p, slab->get_sizeclass());
}
}
}
}

View File

@@ -10,13 +10,6 @@ namespace snmalloc
{
struct Remote
{
static const size_t PTR_BITS = sizeof(void*) * 8;
static const size_t SIZECLASS_BITS =
bits::next_pow2_bits_const(NUM_SIZECLASSES);
static const bool USE_TOP_BITS =
SIZECLASS_BITS + bits::ADDRESS_BITS < PTR_BITS;
static const uintptr_t SIZECLASS_MASK = ((1ULL << SIZECLASS_BITS) - 1);
using alloc_id_t = size_t;
union
{
@@ -24,66 +17,19 @@ namespace snmalloc
Remote* non_atomic_next;
};
// Uses an intptr_t so that when we use the TOP_BITS to encode the
// sizeclass, then we can use signed shift to correctly handle kernel versus
// user mode.
intptr_t value;
alloc_id_t allocator_id;
// This will not exist for the minimum object size. This is only used if
// USE_TOP_BITS is false, and the bottom bit of value is set.
uint8_t possible_sizeclass;
void set_sizeclass_and_target_id(alloc_id_t id, uint8_t sizeclass)
void set_target_id(alloc_id_t id)
{
if constexpr (USE_TOP_BITS)
{
value = (intptr_t)(
(id << SIZECLASS_BITS) | ((static_cast<uintptr_t>(sizeclass))));
}
else
{
assert((id & 1) == 0);
if (sizeclass == 0)
{
value = (intptr_t)(id | 1);
}
else
{
value = (intptr_t)id;
possible_sizeclass = sizeclass;
}
}
allocator_id = id;
}
alloc_id_t target_id()
{
if constexpr (USE_TOP_BITS)
{
return (alloc_id_t)(value >> SIZECLASS_BITS);
}
else
{
return (alloc_id_t)(value & ~1);
}
}
uint8_t sizeclass()
{
if constexpr (USE_TOP_BITS)
{
return (static_cast<uint8_t>((uintptr_t)value & SIZECLASS_MASK));
}
else
{
return ((value & 1) == 1) ? 0 : possible_sizeclass;
}
return allocator_id;
}
};
static_assert(
(offsetof(Remote, possible_sizeclass)) <= MIN_ALLOC_SIZE,
"Need to be able to cast any small alloc to Remote");
struct RemoteAllocator
{
using alloc_id_t = Remote::alloc_id_t;