Startup improvements (#639)

* Benchmark for testing startup performance.

* Make pool pass spare space to pooled item

The pool will result in power of 2 allocations as it doesn't have a
local state when it is initially set up.

This commit passes this extra space to the constructor of the pooled
type, so that it can be feed into the freshly created allocator.

Co-authored-by: Nathaniel Wesley Filardo <nfilardo@microsoft.com>
This commit is contained in:
Matthew Parkinson
2023-09-28 14:53:39 +01:00
committed by GitHub
parent 126e77f2a5
commit 5543347543
10 changed files with 175 additions and 23 deletions

View File

@@ -11,7 +11,7 @@ struct PoolAEntry : Pooled<PoolAEntry>
{
int field;
PoolAEntry() : field(1){};
PoolAEntry(Range<capptr::bounds::Alloc>&) : field(1){};
};
using PoolA = Pool<PoolAEntry, Alloc::Config>;
@@ -20,8 +20,8 @@ struct PoolBEntry : Pooled<PoolBEntry>
{
int field;
PoolBEntry() : field(0){};
PoolBEntry(int f) : field(f){};
PoolBEntry(Range<capptr::bounds::Alloc>&) : field(0){};
PoolBEntry(Range<capptr::bounds::Alloc>&, int f) : field(f){};
};
using PoolB = Pool<PoolBEntry, Alloc::Config>;
@@ -30,7 +30,7 @@ struct PoolLargeEntry : Pooled<PoolLargeEntry>
{
std::array<int, 2'000'000> payload;
PoolLargeEntry()
PoolLargeEntry(Range<capptr::bounds::Alloc>&)
{
printf(".");
fflush(stdout);
@@ -48,7 +48,7 @@ struct PoolSortEntry : Pooled<PoolSortEntry<order>>
{
int field;
PoolSortEntry(int f) : field(f){};
PoolSortEntry(Range<capptr::bounds::Alloc>&, int f) : field(f){};
};
template<bool order>

View File

@@ -0,0 +1,94 @@
#include "test/opt.h"
#include "test/setup.h"
#include "test/usage.h"
#include "test/xoroshiro.h"
#include <iostream>
#include <snmalloc/snmalloc.h>
#include <thread>
#include <vector>
using namespace snmalloc;
std::vector<uint64_t> counters{};
template<typename F>
class ParallelTest
{
private:
std::atomic<bool> flag = false;
std::atomic<size_t> ready = 0;
uint64_t start;
uint64_t end;
std::atomic<size_t> complete = 0;
size_t cores;
F f;
void run(size_t id)
{
auto prev = ready.fetch_add(1);
if (prev + 1 == cores)
{
start = Aal::tick();
flag = true;
}
while (!flag)
Aal::pause();
f(id);
prev = complete.fetch_add(1);
if (prev + 1 == cores)
{
end = Aal::tick();
}
}
public:
ParallelTest(F&& f, size_t cores) : cores(cores), f(std::forward<F>(f))
{
std::thread* t = new std::thread[cores];
for (size_t i = 0; i < cores; i++)
{
t[i] = std::thread(&ParallelTest::run, this, i);
}
// Wait for all the threads.
for (size_t i = 0; i < cores; i++)
{
t[i].join();
}
delete[] t;
}
uint64_t time()
{
return end - start;
}
};
int main()
{
counters.resize(std::thread::hardware_concurrency());
ParallelTest test(
[](size_t id) {
auto start = Aal::tick();
auto& alloc = snmalloc::ThreadAlloc::get();
alloc.dealloc(alloc.alloc(1));
auto end = Aal::tick();
counters[id] = end - start;
},
counters.size());
std::cout << "Taken: " << test.time() << std::endl;
std::sort(counters.begin(), counters.end());
uint64_t start = 0;
for (auto counter : counters)
{
std::cout << "Thread time " << counter << " (" << counter - start << ")"
<< std::endl;
start = counter;
}
}