diff --git a/libcxx/benchmarks/CMakeLists.txt b/libcxx/benchmarks/CMakeLists.txt index 906ffa441427..d80cb1af03a0 100644 --- a/libcxx/benchmarks/CMakeLists.txt +++ b/libcxx/benchmarks/CMakeLists.txt @@ -84,6 +84,7 @@ endif() set(BENCHMARK_TEST_COMPILE_FLAGS ${BENCHMARK_DIALECT_FLAG} -O2 + -fsized-deallocation -I${BENCHMARK_LIBCXX_INSTALL}/include -I${LIBCXX_SOURCE_DIR}/test/support ) @@ -219,3 +220,4 @@ if (LIBCXX_INCLUDE_TESTS) DEPENDS cxx-benchmarks ${LIBCXX_TEST_DEPS} ARGS ${BENCHMARK_LIT_ARGS}) endif() + diff --git a/libcxx/benchmarks/allocation.bench.cpp b/libcxx/benchmarks/allocation.bench.cpp new file mode 100644 index 000000000000..236e74044a56 --- /dev/null +++ b/libcxx/benchmarks/allocation.bench.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "benchmark/benchmark.h" + +#include +#include +#include + +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 +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 +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 +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 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}, + {"BM_New", &BM_AllocateAndDeallocate}, + {"BM_BuiltinNewDelete", BM_AllocateAndDeallocate}, + {"BM_BuiltinSizedNewDelete", BM_AllocateAndDeallocate}, + {"BM_BuiltinNewAllocateOnly", BM_AllocateOnly}, + {"BM_BuiltinNewSizedDeallocateOnly", BM_DeallocateOnly}, + + }; + for (auto TC : TestCases) { + benchmark::RegisterBenchmark(TC.name, TC.func)->Range(16, 4096 * 2); + } + return 0; +} +int Sink = RegisterAllocBenchmarks(); + +BENCHMARK_MAIN();