diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index c10bbda877..655545d1e2 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -37,20 +37,27 @@ struct glibc_malloc : public allocator_interface { }; struct os_provider : public provider_interface { - umf_os_memory_provider_params_handle_t params = NULL; - os_provider() { - umfOsMemoryProviderParamsCreate(¶ms); - return; - } - - ~os_provider() { - if (params != NULL) { - umfOsMemoryProviderParamsDestroy(params); + provider_interface::params_ptr + getParams(::benchmark::State &state) override { + umf_os_memory_provider_params_handle_t raw_params = nullptr; + umfOsMemoryProviderParamsCreate(&raw_params); + if (!raw_params) { + state.SkipWithError("Failed to create os provider params"); + return {nullptr, [](void *) {}}; } + + // Use a lambda as the custom deleter + auto deleter = [](void *p) { + auto handle = + static_cast(p); + umfOsMemoryProviderParamsDestroy(handle); + }; + + return {static_cast(raw_params), deleter}; } - void *getParams() override { return params; } - umf_memory_provider_ops_t *getOps() override { + umf_memory_provider_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { return umfOsMemoryProviderOps(); } static std::string name() { return "os_provider"; } @@ -62,73 +69,60 @@ struct proxy_pool : public pool_interface { getOps([[maybe_unused]] ::benchmark::State &state) override { return umfProxyPoolOps(); } - void *getParams([[maybe_unused]] ::benchmark::State &state) override { - return nullptr; - } + static std::string name() { return "proxy_pool<" + Provider::name() + ">"; } }; #ifdef UMF_POOL_DISJOINT_ENABLED template struct disjoint_pool : public pool_interface { - umf_disjoint_pool_params_handle_t disjoint_memory_pool_params; + umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfDisjointPoolOps(); + } - disjoint_pool() { - disjoint_memory_pool_params = NULL; - auto ret = umfDisjointPoolParamsCreate(&disjoint_memory_pool_params); + typename pool_interface::params_ptr + getParams(::benchmark::State &state) override { + umf_disjoint_pool_params_handle_t raw_params = nullptr; + auto ret = umfDisjointPoolParamsCreate(&raw_params); if (ret != UMF_RESULT_SUCCESS) { - return; + state.SkipWithError("Failed to create disjoint pool params"); + return {nullptr, [](void *) {}}; } - // those function should never fail, so error handling is minimal. - ret = umfDisjointPoolParamsSetSlabMinSize(disjoint_memory_pool_params, - 4096); - if (ret != UMF_RESULT_SUCCESS) { - goto err; - } + typename pool_interface::params_ptr params( + raw_params, [](void *p) { + umfDisjointPoolParamsDestroy( + static_cast(p)); + }); - ret = umfDisjointPoolParamsSetCapacity(disjoint_memory_pool_params, 4); + ret = umfDisjointPoolParamsSetSlabMinSize(raw_params, 4096); if (ret != UMF_RESULT_SUCCESS) { - goto err; + state.SkipWithError("Failed to set slab min size"); + return {nullptr, [](void *) {}}; } - ret = umfDisjointPoolParamsSetMinBucketSize(disjoint_memory_pool_params, - 4096); + ret = umfDisjointPoolParamsSetCapacity(raw_params, 4); if (ret != UMF_RESULT_SUCCESS) { - goto err; + state.SkipWithError("Failed to set capacity"); + return {nullptr, [](void *) {}}; } - ret = umfDisjointPoolParamsSetMaxPoolableSize( - disjoint_memory_pool_params, 4096 * 16); - + ret = umfDisjointPoolParamsSetMinBucketSize(raw_params, 4096); if (ret != UMF_RESULT_SUCCESS) { - goto err; + state.SkipWithError("Failed to set min bucket size"); + return {nullptr, [](void *) {}}; } - return; - err: - umfDisjointPoolParamsDestroy(disjoint_memory_pool_params); - disjoint_memory_pool_params = NULL; - } - - ~disjoint_pool() { - if (disjoint_memory_pool_params != NULL) { - umfDisjointPoolParamsDestroy(disjoint_memory_pool_params); + ret = umfDisjointPoolParamsSetMaxPoolableSize(raw_params, 4096 * 16); + if (ret != UMF_RESULT_SUCCESS) { + state.SkipWithError("Failed to set max poolable size"); + return {nullptr, [](void *) {}}; } - } - umf_memory_pool_ops_t * - getOps([[maybe_unused]] ::benchmark::State &state) override { - return umfDisjointPoolOps(); + return params; } - void *getParams([[maybe_unused]] ::benchmark::State &state) override { - if (disjoint_memory_pool_params == NULL) { - state.SkipWithError("Failed to create disjoint pool params"); - } - - return disjoint_memory_pool_params; - } static std::string name() { return "disjoint_pool<" + Provider::name() + ">"; } @@ -142,9 +136,7 @@ struct jemalloc_pool : public pool_interface { getOps([[maybe_unused]] ::benchmark::State &state) override { return umfJemallocPoolOps(); } - void *getParams([[maybe_unused]] ::benchmark::State &state) override { - return NULL; - } + static std::string name() { return "jemalloc_pool<" + Provider::name() + ">"; } @@ -158,10 +150,7 @@ struct scalable_pool : public pool_interface { getOps([[maybe_unused]] ::benchmark::State &state) override { return umfScalablePoolOps(); } - virtual void * - getParams([[maybe_unused]] ::benchmark::State &state) override { - return NULL; - } + static std::string name() { return "scalable_pool<" + Provider::name() + ">"; } diff --git a/benchmark/benchmark.hpp b/benchmark/benchmark.hpp index ad9ab7cc83..6ac7a4dfa5 100644 --- a/benchmark/benchmark.hpp +++ b/benchmark/benchmark.hpp @@ -232,12 +232,14 @@ class alloc_benchmark : public benchmark_interface { state.ResumeTiming(); } } + static std::vector argsName() { auto n = benchmark_interface::argsName(); std::vector res = {"max_allocs", "pre_allocs"}; res.insert(res.end(), n.begin(), n.end()); return res; } + static std::string name() { return base::name() + "/alloc"; } static int64_t iterations() { return 200000; } @@ -320,13 +322,16 @@ class multiple_malloc_free_benchmark : public alloc_benchmark { static std::string name() { return base::base::name() + "/multiple_malloc_free"; } + static std::vector argsName() { auto n = benchmark_interface::argsName(); std::vector res = {"max_allocs"}; res.insert(res.end(), n.begin(), n.end()); return res; } + static int64_t iterations() { return 2000; } + std::default_random_engine generator; distribution dist; }; @@ -352,9 +357,11 @@ class provider_allocator : public allocator_interface { } return ptr; } + void benchFree(void *ptr, size_t size) override { umfMemoryProviderFree(provider.provider, ptr, size); } + static std::string name() { return Provider::name(); } private: @@ -374,6 +381,7 @@ template class pool_allocator : public allocator_interface { virtual void *benchAlloc(size_t size) override { return umfPoolMalloc(pool.pool, size); } + virtual void benchFree(void *ptr, [[maybe_unused]] size_t size) override { umfPoolFree(pool.pool, ptr); } diff --git a/benchmark/benchmark_interfaces.hpp b/benchmark/benchmark_interfaces.hpp index e25c977710..516a20b697 100644 --- a/benchmark/benchmark_interfaces.hpp +++ b/benchmark/benchmark_interfaces.hpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include @@ -39,6 +40,7 @@ struct benchmark_interface : public benchmark::Fixture { int argPos = alloc_size.SetUp(state, 0); allocator.SetUp(state, argPos); } + void TearDown(::benchmark::State &state) { alloc_size.TearDown(state); allocator.TearDown(state); @@ -54,6 +56,7 @@ struct benchmark_interface : public benchmark::Fixture { res.insert(res.end(), a.begin(), a.end()); return res; } + static std::string name() { return Allocator::name(); } static int64_t iterations() { return 10000; } Size alloc_size; @@ -61,13 +64,16 @@ struct benchmark_interface : public benchmark::Fixture { }; struct provider_interface { + using params_ptr = std::unique_ptr; + umf_memory_provider_handle_t provider = NULL; virtual void SetUp(::benchmark::State &state) { if (state.thread_index() != 0) { return; } + auto params = getParams(state); auto umf_result = - umfMemoryProviderCreate(getOps(), getParams(), &provider); + umfMemoryProviderCreate(getOps(state), params.get(), &provider); if (umf_result != UMF_RESULT_SUCCESS) { state.SkipWithError("umfMemoryProviderCreate() failed"); } @@ -83,21 +89,30 @@ struct provider_interface { } } - virtual umf_memory_provider_ops_t *getOps() { return nullptr; } - virtual void *getParams() { return nullptr; } + virtual umf_memory_provider_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) { + return nullptr; + } + + virtual params_ptr getParams([[maybe_unused]] ::benchmark::State &state) { + return {nullptr, [](void *) {}}; + } }; template ::value>> struct pool_interface { + using params_ptr = std::unique_ptr; + virtual void SetUp(::benchmark::State &state) { provider.SetUp(state); if (state.thread_index() != 0) { return; } + auto params = getParams(state); auto umf_result = umfPoolCreate(getOps(state), provider.provider, - getParams(state), 0, &pool); + params.get(), 0, &pool); if (umf_result != UMF_RESULT_SUCCESS) { state.SkipWithError("umfPoolCreate() failed"); } @@ -121,8 +136,8 @@ struct pool_interface { getOps([[maybe_unused]] ::benchmark::State &state) { return nullptr; } - virtual void *getParams([[maybe_unused]] ::benchmark::State &state) { - return nullptr; + virtual params_ptr getParams([[maybe_unused]] ::benchmark::State &state) { + return {nullptr, [](void *) {}}; } T provider; umf_memory_pool_handle_t pool;