Refactor: Remove unused features and functions, and move most allocator operations to a global namespace. (#750)
* Factor out explicit Config type Instead of using snmalloc::Alloc::Config, expose snmalloc::Config, which is then used to derive the allocator type. * Move globalalloc to front end. * Remove unneed template parameter from global snmalloc functions. * Remove SNMALLOC_PASS_THROUGH VeronaRT now has an abstraction layer which can easily replace the allocator. Having such a complex integration still in snmalloc does not make sense. * Take some global functions off of local alloc. * Drop comparison overloads on atomic Capptr. Performing a comparison on two atomic ptr is a complex operation, and should not be implicit. The memory model order and such things needs to be considered by the caller. * Remove function_ref and use templates The implementation prefers to use templates over the function_ref. This now only exists in the Pal for a currently unused feature. * Removing function_ref reduces stl needs. * Remove use of __is_convertible to support older g++ * Inline function that is only used once. * Remove unused function * Restrict ThreadAlloc usage to globalalloc This commit introduces various inline functions on snmalloc:: that perform allocation/deallocation using the thread local allocator. They remove all usage from a particular test. * Move cheri checks to own file. * Refactor is_owned checks. * Move alloc_size and check_size to globalalloc. * Minor simplification of dealloc path * Fix up is_owned to take a config * Improve usage of scoped allocator. * Handle Config_ in globalalloc.
This commit is contained in:
committed by
GitHub
parent
6d50141e35
commit
5f7baef755
@@ -75,13 +75,12 @@ size_t swapcount;
|
||||
|
||||
void test_tasks_f(size_t id)
|
||||
{
|
||||
auto& a = ThreadAlloc::get();
|
||||
xoroshiro::p128r32 r(id + 5000);
|
||||
|
||||
for (size_t n = 0; n < swapcount; n++)
|
||||
{
|
||||
size_t size = 16 + (r.next() % 1024);
|
||||
size_t* res = (size_t*)(use_malloc ? malloc(size) : a.alloc(size));
|
||||
size_t* res = (size_t*)(use_malloc ? malloc(size) : snmalloc::alloc(size));
|
||||
|
||||
if (res != nullptr)
|
||||
{
|
||||
@@ -102,7 +101,7 @@ void test_tasks_f(size_t id)
|
||||
if (use_malloc)
|
||||
free(out);
|
||||
else
|
||||
a.dealloc(out, size);
|
||||
snmalloc::dealloc(out, size);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -111,8 +110,6 @@ void test_tasks(size_t num_tasks, size_t count, size_t size)
|
||||
{
|
||||
std::cout << "Sequential setup" << std::endl;
|
||||
|
||||
auto& a = ThreadAlloc::get();
|
||||
|
||||
contention = new std::atomic<size_t*>[size];
|
||||
xoroshiro::p128r32 r;
|
||||
|
||||
@@ -120,7 +117,7 @@ void test_tasks(size_t num_tasks, size_t count, size_t size)
|
||||
{
|
||||
size_t alloc_size = 16 + (r.next() % 1024);
|
||||
size_t* res =
|
||||
(size_t*)(use_malloc ? malloc(alloc_size) : a.alloc(alloc_size));
|
||||
(size_t*)(use_malloc ? malloc(alloc_size) : snmalloc::alloc(alloc_size));
|
||||
*res = alloc_size;
|
||||
contention[n] = res;
|
||||
}
|
||||
@@ -146,7 +143,7 @@ void test_tasks(size_t num_tasks, size_t count, size_t size)
|
||||
if (use_malloc)
|
||||
free(contention[n]);
|
||||
else
|
||||
a.dealloc(contention[n], *contention[n]);
|
||||
snmalloc::dealloc(contention[n], *contention[n]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +151,7 @@ void test_tasks(size_t num_tasks, size_t count, size_t size)
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
snmalloc::debug_check_empty<snmalloc::Alloc::Config>();
|
||||
snmalloc::debug_check_empty();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace test
|
||||
// Pre allocate all the objects
|
||||
size_t* objects[count];
|
||||
|
||||
NOINLINE void setup(xoroshiro::p128r64& r, Alloc& alloc)
|
||||
NOINLINE void setup(xoroshiro::p128r64& r)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
@@ -31,28 +31,27 @@ namespace test
|
||||
if (size < 16)
|
||||
size = 16;
|
||||
// store object
|
||||
objects[i] = (size_t*)alloc.alloc(size);
|
||||
objects[i] = (size_t*)snmalloc::alloc(size);
|
||||
if (objects[i] == nullptr)
|
||||
abort();
|
||||
// Store allocators size for this object
|
||||
*objects[i] = alloc.alloc_size(objects[i]);
|
||||
*objects[i] = snmalloc::alloc_size(objects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
NOINLINE void teardown(Alloc& alloc)
|
||||
NOINLINE void teardown()
|
||||
{
|
||||
// Deallocate everything
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
alloc.dealloc(objects[i]);
|
||||
snmalloc::dealloc(objects[i]);
|
||||
}
|
||||
|
||||
snmalloc::debug_check_empty<snmalloc::Alloc::Config>();
|
||||
snmalloc::debug_check_empty();
|
||||
}
|
||||
|
||||
void test_external_pointer(xoroshiro::p128r64& r)
|
||||
{
|
||||
auto& alloc = ThreadAlloc::get();
|
||||
// This is very slow on Windows at the moment. Until this is fixed, help
|
||||
// CI terminate.
|
||||
#if defined(NDEBUG) && !defined(_MSC_VER)
|
||||
@@ -66,7 +65,7 @@ namespace test
|
||||
static constexpr size_t iterations = 100000;
|
||||
# endif
|
||||
#endif
|
||||
setup(r, alloc);
|
||||
setup(r);
|
||||
|
||||
{
|
||||
MeasureTime m;
|
||||
@@ -76,12 +75,12 @@ namespace test
|
||||
size_t rand = (size_t)r.next();
|
||||
size_t oid = rand & (((size_t)1 << count_log) - 1);
|
||||
size_t* external_ptr = objects[oid];
|
||||
if (!alloc.is_snmalloc_owned(external_ptr))
|
||||
if (!snmalloc::is_owned(external_ptr))
|
||||
continue;
|
||||
size_t size = *external_ptr;
|
||||
size_t offset = (size >> 4) * (rand & 15);
|
||||
void* interior_ptr = pointer_offset(external_ptr, offset);
|
||||
void* calced_external = alloc.external_pointer(interior_ptr);
|
||||
void* calced_external = snmalloc::external_pointer(interior_ptr);
|
||||
if (calced_external != external_ptr)
|
||||
{
|
||||
abort();
|
||||
@@ -89,13 +88,12 @@ namespace test
|
||||
}
|
||||
}
|
||||
|
||||
teardown(alloc);
|
||||
teardown();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
#ifndef SNMALLOC_PASS_THROUGH // Depends on snmalloc specific features
|
||||
setup();
|
||||
|
||||
xoroshiro::p128r64 r;
|
||||
@@ -105,5 +103,4 @@ int main(int, char**)
|
||||
for (size_t n = 0; n < nn; n++)
|
||||
test::test_external_pointer(r);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class Queue
|
||||
|
||||
Node* new_node(size_t size)
|
||||
{
|
||||
auto result = (Node*)ThreadAlloc::get().alloc(size);
|
||||
auto result = (Node*)snmalloc::alloc(size);
|
||||
result->next = nullptr;
|
||||
return result;
|
||||
}
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
return false;
|
||||
|
||||
Node* next = head->next;
|
||||
ThreadAlloc::get().dealloc(head);
|
||||
snmalloc::dealloc(head);
|
||||
head = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ void shape(size_t size)
|
||||
// the memcpys. constexpr size_t alignment = 16; offset = (my_random() %
|
||||
// size / alignment) * alignment;
|
||||
Shape s;
|
||||
s.object = ThreadAlloc::get().alloc(rsize);
|
||||
s.object = snmalloc::alloc(rsize);
|
||||
s.dst = static_cast<unsigned char*>(s.object) + offset;
|
||||
// Bring into cache the destination of the copy.
|
||||
memset(s.dst, 0xFF, size);
|
||||
@@ -47,7 +47,7 @@ void unshape()
|
||||
{
|
||||
for (auto& s : allocs)
|
||||
{
|
||||
ThreadAlloc::get().dealloc(s.object);
|
||||
snmalloc::dealloc(s.object);
|
||||
}
|
||||
allocs.clear();
|
||||
}
|
||||
@@ -68,7 +68,7 @@ void test(
|
||||
Memcpy mc,
|
||||
std::vector<std::pair<size_t, std::chrono::nanoseconds>>& stats)
|
||||
{
|
||||
auto src = ThreadAlloc::get().alloc(size);
|
||||
auto src = snmalloc::alloc(size);
|
||||
shape(size);
|
||||
for (size_t i = 0; i < 10; i++)
|
||||
{
|
||||
@@ -77,7 +77,7 @@ void test(
|
||||
auto time = m.get_time();
|
||||
stats.push_back({size, time});
|
||||
}
|
||||
ThreadAlloc::get().dealloc(src);
|
||||
snmalloc::dealloc(src);
|
||||
unshape();
|
||||
}
|
||||
|
||||
@@ -108,7 +108,6 @@ void memcpy_platform_checked(void* dst, const void* src, size_t size)
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
opt::Opt opt(argc, argv);
|
||||
#ifndef SNMALLOC_PASS_THROUGH
|
||||
bool full_test = opt.has("--full_test");
|
||||
|
||||
// size_t size = 0;
|
||||
@@ -182,8 +181,5 @@ int main(int argc, char** argv)
|
||||
stats_platform.clear();
|
||||
stats_platform_checked.clear();
|
||||
}
|
||||
#else
|
||||
snmalloc::UNUSED(opt);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,46 +36,6 @@ void chatty(const char* p, ...)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Interpret SNMALLOC_PASS_THROUGH ourselves to make this a bit more fair of a
|
||||
* comparison, since relying of snmalloc itself to do the passing through
|
||||
* results in it imposing its own idea of alignment onto the underlying
|
||||
* allocator, which might result in it taking less optimized paths.
|
||||
*/
|
||||
#ifdef SNMALLOC_PASS_THROUGH
|
||||
struct MyAlloc
|
||||
{
|
||||
MyAlloc() {}
|
||||
|
||||
void* alloc(size_t sz)
|
||||
{
|
||||
return malloc(sz);
|
||||
}
|
||||
|
||||
void dealloc(void* p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
};
|
||||
#else
|
||||
struct MyAlloc
|
||||
{
|
||||
snmalloc::Alloc& a;
|
||||
|
||||
MyAlloc() : a(ThreadAlloc::get()) {}
|
||||
|
||||
void* alloc(size_t sz)
|
||||
{
|
||||
return a.alloc(sz);
|
||||
}
|
||||
|
||||
void dealloc(void* p)
|
||||
{
|
||||
a.dealloc(p);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FreeListMPSCQ make for convenient MPSC queues, so we use those for sending
|
||||
* "messages". Each consumer or proxy has its own (source) queue.
|
||||
@@ -106,7 +66,6 @@ freelist::HeadPtr domesticate_nop(freelist::QueuePtr p)
|
||||
|
||||
void consumer(const struct params* param, size_t qix)
|
||||
{
|
||||
MyAlloc a{};
|
||||
auto& myq = param->msgqueue[qix];
|
||||
|
||||
chatty("Cl %zu q is %p\n", qix, &myq);
|
||||
@@ -118,13 +77,11 @@ void consumer(const struct params* param, size_t qix)
|
||||
if (myq.can_dequeue(domesticate_nop, domesticate_nop))
|
||||
{
|
||||
myq.dequeue(
|
||||
domesticate_nop,
|
||||
domesticate_nop,
|
||||
[qix, &a, &reap](freelist::HeadPtr o) {
|
||||
domesticate_nop, domesticate_nop, [qix, &reap](freelist::HeadPtr o) {
|
||||
UNUSED(qix);
|
||||
auto p = o.as_void().unsafe_ptr();
|
||||
chatty("Cl %zu free %p\n", qix, p);
|
||||
a.dealloc(p);
|
||||
snmalloc::dealloc(p);
|
||||
reap++;
|
||||
return true;
|
||||
});
|
||||
@@ -145,7 +102,7 @@ void consumer(const struct params* param, size_t qix)
|
||||
producers_live || (queue_gate > param->N_CONSUMER));
|
||||
|
||||
chatty("Cl %zu fini\n", qix);
|
||||
a.dealloc(myq.destroy().unsafe_ptr());
|
||||
snmalloc::dealloc(myq.destroy().unsafe_ptr());
|
||||
}
|
||||
|
||||
void proxy(const struct params* param, size_t qix)
|
||||
@@ -178,13 +135,12 @@ void proxy(const struct params* param, size_t qix)
|
||||
|
||||
chatty("Px %zu fini\n", qix);
|
||||
|
||||
MyAlloc().dealloc(myq.destroy().unsafe_ptr());
|
||||
snmalloc::dealloc(myq.destroy().unsafe_ptr());
|
||||
queue_gate--;
|
||||
}
|
||||
|
||||
void producer(const struct params* param, size_t pix)
|
||||
{
|
||||
MyAlloc a{};
|
||||
static constexpr size_t msgsizes[] = {48, 64, 96, 128};
|
||||
static constexpr size_t nmsgsizes = sizeof(msgsizes) / sizeof(msgsizes[0]);
|
||||
|
||||
@@ -206,7 +162,7 @@ void producer(const struct params* param, size_t pix)
|
||||
/* Allocate batch and form list */
|
||||
for (size_t msgix = 0; msgix < nmsg; msgix++)
|
||||
{
|
||||
auto msg = a.alloc(msgsize);
|
||||
auto msg = snmalloc::alloc(msgsize);
|
||||
chatty("Pd %zu make %p\n", pix, msg);
|
||||
|
||||
auto msgc = capptr::Alloc<void>::unsafe_from(msg)
|
||||
|
||||
@@ -8,8 +8,6 @@ using namespace snmalloc;
|
||||
template<ZeroMem zero_mem>
|
||||
void test_alloc_dealloc(size_t count, size_t size, bool write)
|
||||
{
|
||||
auto& alloc = ThreadAlloc::get();
|
||||
|
||||
{
|
||||
MeasureTime m;
|
||||
m << "Count: " << std::setw(6) << count << ", Size: " << std::setw(6)
|
||||
@@ -20,7 +18,7 @@ void test_alloc_dealloc(size_t count, size_t size, bool write)
|
||||
// alloc 1.5x objects
|
||||
for (size_t i = 0; i < ((count * 3) / 2); i++)
|
||||
{
|
||||
void* p = alloc.alloc<zero_mem>(size);
|
||||
void* p = snmalloc::alloc<zero_mem>(size);
|
||||
SNMALLOC_CHECK(set.find(p) == set.end());
|
||||
|
||||
if (write)
|
||||
@@ -36,13 +34,13 @@ void test_alloc_dealloc(size_t count, size_t size, bool write)
|
||||
void* p = *it;
|
||||
set.erase(it);
|
||||
SNMALLOC_CHECK(set.find(p) == set.end());
|
||||
alloc.dealloc(p, size);
|
||||
snmalloc::dealloc(p, size);
|
||||
}
|
||||
|
||||
// alloc 1x objects
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
void* p = alloc.alloc<zero_mem>(size);
|
||||
void* p = snmalloc::alloc<zero_mem>(size);
|
||||
SNMALLOC_CHECK(set.find(p) == set.end());
|
||||
|
||||
if (write)
|
||||
@@ -55,12 +53,12 @@ void test_alloc_dealloc(size_t count, size_t size, bool write)
|
||||
while (!set.empty())
|
||||
{
|
||||
auto it = set.begin();
|
||||
alloc.dealloc(*it, size);
|
||||
snmalloc::dealloc(*it, size);
|
||||
set.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
snmalloc::debug_check_empty<snmalloc::Alloc::Config>();
|
||||
snmalloc::debug_check_empty();
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
|
||||
@@ -77,8 +77,7 @@ int main()
|
||||
ParallelTest test(
|
||||
[](size_t id) {
|
||||
auto start = Aal::tick();
|
||||
auto& alloc = snmalloc::ThreadAlloc::get();
|
||||
alloc.dealloc(alloc.alloc(1));
|
||||
snmalloc::dealloc(snmalloc::alloc(1));
|
||||
auto end = Aal::tick();
|
||||
counters[id] = end - start;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user