| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "benchmark/benchmark.h" |
| |
|
| | #include <new> |
| | #include <vector> |
| | #include <cassert> |
| |
|
| | struct PointerList { |
| | PointerList* Next = nullptr; |
| | }; |
| |
|
| | struct MallocWrapper { |
| | __attribute__((always_inline)) |
| | static void* Allocate(size_t N) { |
| | return std::malloc(N); |
| | } |
| | __attribute__((always_inline)) |
| | static void Deallocate(void* P, size_t) { |
| | std::free(P); |
| | } |
| | }; |
| |
|
| | struct NewWrapper { |
| | __attribute__((always_inline)) |
| | static void* Allocate(size_t N) { |
| | return ::operator new(N); |
| | } |
| | __attribute__((always_inline)) |
| | static void Deallocate(void* P, size_t) { |
| | ::operator delete(P); |
| | } |
| | }; |
| |
|
| | struct BuiltinNewWrapper { |
| | __attribute__((always_inline)) |
| | static void* Allocate(size_t N) { |
| | return __builtin_operator_new(N); |
| | } |
| | __attribute__((always_inline)) |
| | static void Deallocate(void* P, size_t) { |
| | __builtin_operator_delete(P); |
| | } |
| | }; |
| |
|
| | struct BuiltinSizedNewWrapper { |
| | __attribute__((always_inline)) |
| | static void* Allocate(size_t N) { |
| | return __builtin_operator_new(N); |
| | } |
| | __attribute__((always_inline)) |
| | static void Deallocate(void* P, size_t N) { |
| | __builtin_operator_delete(P, N); |
| | } |
| | }; |
| |
|
| |
|
| | template <class AllocWrapper> |
| | static void BM_AllocateAndDeallocate(benchmark::State& st) { |
| | const size_t alloc_size = st.range(0); |
| | while (st.KeepRunning()) { |
| | void* p = AllocWrapper::Allocate(alloc_size); |
| | benchmark::DoNotOptimize(p); |
| | AllocWrapper::Deallocate(p, alloc_size); |
| | } |
| | } |
| |
|
| |
|
| | template <class AllocWrapper> |
| | static void BM_AllocateOnly(benchmark::State& st) { |
| | const size_t alloc_size = st.range(0); |
| | PointerList *Start = nullptr; |
| |
|
| | while (st.KeepRunning()) { |
| | PointerList* p = (PointerList*)AllocWrapper::Allocate(alloc_size); |
| | benchmark::DoNotOptimize(p); |
| | p->Next = Start; |
| | Start = p; |
| | } |
| |
|
| | PointerList *Next = Start; |
| | while (Next) { |
| | PointerList *Tmp = Next; |
| | Next = Tmp->Next; |
| | AllocWrapper::Deallocate(Tmp, alloc_size); |
| | } |
| | } |
| |
|
| | template <class AllocWrapper> |
| | static void BM_DeallocateOnly(benchmark::State& st) { |
| | const size_t alloc_size = st.range(0); |
| | const auto NumAllocs = st.max_iterations; |
| |
|
| | using PtrT = void*; |
| | std::vector<void*> Pointers(NumAllocs); |
| | for (auto& p : Pointers) { |
| | p = AllocWrapper::Allocate(alloc_size); |
| | } |
| |
|
| | void** Data = Pointers.data(); |
| | void** const End = Pointers.data() + Pointers.size(); |
| | while (st.KeepRunning()) { |
| | AllocWrapper::Deallocate(*Data, alloc_size); |
| | Data += 1; |
| | } |
| | assert(Data == End); |
| | } |
| |
|
| | static int RegisterAllocBenchmarks() { |
| | using FnType = void(*)(benchmark::State&); |
| | struct { |
| | const char* name; |
| | FnType func; |
| | } TestCases[] = { |
| | {"BM_Malloc", &BM_AllocateAndDeallocate<MallocWrapper>}, |
| | {"BM_New", &BM_AllocateAndDeallocate<NewWrapper>}, |
| | {"BM_BuiltinNewDelete", BM_AllocateAndDeallocate<BuiltinNewWrapper>}, |
| | {"BM_BuiltinSizedNewDelete", BM_AllocateAndDeallocate<BuiltinSizedNewWrapper>}, |
| | {"BM_BuiltinNewAllocateOnly", BM_AllocateOnly<BuiltinSizedNewWrapper>}, |
| | {"BM_BuiltinNewSizedDeallocateOnly", BM_DeallocateOnly<BuiltinSizedNewWrapper>}, |
| |
|
| | }; |
| | for (auto TC : TestCases) { |
| | benchmark::RegisterBenchmark(TC.name, TC.func)->Range(16, 4096 * 2); |
| | } |
| | return 0; |
| | } |
| | int Sink = RegisterAllocBenchmarks(); |
| |
|
| | BENCHMARK_MAIN(); |
| |
|