diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 655545d1e2..df4fe6e5d5 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -6,161 +6,29 @@ * */ -#include -#include -#ifdef UMF_POOL_SCALABLE_ENABLED -#include -#endif -#include - -#ifdef UMF_POOL_DISJOINT_ENABLED -#include -#endif - -#ifdef UMF_POOL_JEMALLOC_ENABLED -#include -#endif - #include "benchmark.hpp" -struct glibc_malloc : public allocator_interface { - unsigned SetUp([[maybe_unused]] ::benchmark::State &state, - unsigned argPos) override { - return argPos; - } - void TearDown([[maybe_unused]] ::benchmark::State &state) override{}; - void *benchAlloc(size_t size) override { return malloc(size); } - void benchFree(void *ptr, [[maybe_unused]] size_t size) override { - free(ptr); +#define UMF_BENCHMARK_TEMPLATE_DEFINE(BaseClass, Method, ...) \ + BENCHMARK_TEMPLATE_DEFINE_F(BaseClass, Method, __VA_ARGS__) \ + (benchmark::State & state) { \ + for (auto _ : state) { \ + bench(state); \ + } \ } - static std::string name() { return "glibc"; } -}; - -struct os_provider : public provider_interface { - 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}; - } - - umf_memory_provider_ops_t * - getOps([[maybe_unused]] ::benchmark::State &state) override { - return umfOsMemoryProviderOps(); - } - static std::string name() { return "os_provider"; } -}; - -template -struct proxy_pool : public pool_interface { - umf_memory_pool_ops_t * - getOps([[maybe_unused]] ::benchmark::State &state) override { - return umfProxyPoolOps(); - } - - static std::string name() { return "proxy_pool<" + Provider::name() + ">"; } -}; -#ifdef UMF_POOL_DISJOINT_ENABLED -template -struct disjoint_pool : public pool_interface { - umf_memory_pool_ops_t * - getOps([[maybe_unused]] ::benchmark::State &state) override { - return umfDisjointPoolOps(); - } - - 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) { - state.SkipWithError("Failed to create disjoint pool params"); - return {nullptr, [](void *) {}}; - } - - typename pool_interface::params_ptr params( - raw_params, [](void *p) { - umfDisjointPoolParamsDestroy( - static_cast(p)); - }); - - ret = umfDisjointPoolParamsSetSlabMinSize(raw_params, 4096); - if (ret != UMF_RESULT_SUCCESS) { - state.SkipWithError("Failed to set slab min size"); - return {nullptr, [](void *) {}}; - } - - ret = umfDisjointPoolParamsSetCapacity(raw_params, 4); - if (ret != UMF_RESULT_SUCCESS) { - state.SkipWithError("Failed to set capacity"); - return {nullptr, [](void *) {}}; - } - - ret = umfDisjointPoolParamsSetMinBucketSize(raw_params, 4096); - if (ret != UMF_RESULT_SUCCESS) { - state.SkipWithError("Failed to set min bucket size"); - return {nullptr, [](void *) {}}; - } - - ret = umfDisjointPoolParamsSetMaxPoolableSize(raw_params, 4096 * 16); - if (ret != UMF_RESULT_SUCCESS) { - state.SkipWithError("Failed to set max poolable size"); - return {nullptr, [](void *) {}}; - } - - return params; - } - - static std::string name() { - return "disjoint_pool<" + Provider::name() + ">"; - } -}; -#endif - -#ifdef UMF_POOL_JEMALLOC_ENABLED -template -struct jemalloc_pool : public pool_interface { - umf_memory_pool_ops_t * - getOps([[maybe_unused]] ::benchmark::State &state) override { - return umfJemallocPoolOps(); - } - - static std::string name() { - return "jemalloc_pool<" + Provider::name() + ">"; - } -}; -#endif - -#ifdef UMF_POOL_SCALABLE_ENABLED -template -struct scalable_pool : public pool_interface { - virtual umf_memory_pool_ops_t * - getOps([[maybe_unused]] ::benchmark::State &state) override { - return umfScalablePoolOps(); - } - - static std::string name() { - return "scalable_pool<" + Provider::name() + ">"; - } -}; -#endif -// Benchmarks scenarios: +#define UMF_BENCHMARK_REGISTER_F(BaseClass, Method) \ + BENCHMARK_REGISTER_F(BaseClass, Method) \ + ->ArgNames( \ + BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::argsName()) \ + ->Name(BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::name()) \ + ->Iterations( \ + BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::iterations()) UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, glibc_fix, fixed_alloc_size, glibc_malloc); +// Benchmarks scenarios: + // The benchmark arguments specified in Args() are, in order: // benchmark arguments, allocator arguments, size generator arguments. // The exact meaning of each argument depends on the benchmark, allocator, and size components used. diff --git a/benchmark/benchmark.hpp b/benchmark/benchmark.hpp index 6ac7a4dfa5..df5d6a5927 100644 --- a/benchmark/benchmark.hpp +++ b/benchmark/benchmark.hpp @@ -75,70 +75,97 @@ #include #include -#include "benchmark_interfaces.hpp" +#include "benchmark_size.hpp" +#include "benchmark_umf.hpp" struct alloc_data { void *ptr; size_t size; }; -#define UMF_BENCHMARK_TEMPLATE_DEFINE(BaseClass, Method, ...) \ - BENCHMARK_TEMPLATE_DEFINE_F(BaseClass, Method, __VA_ARGS__) \ - (benchmark::State & state) { \ - for (auto _ : state) { \ - bench(state); \ - } \ +template ::value>> +class provider_allocator : public allocator_interface { + public: + unsigned SetUp(::benchmark::State &state, unsigned r) override { + provider.SetUp(state); + return r; } -#define UMF_BENCHMARK_REGISTER_F(BaseClass, Method) \ - BENCHMARK_REGISTER_F(BaseClass, Method) \ - ->ArgNames( \ - BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::argsName()) \ - ->Name(BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::name()) \ - ->Iterations( \ - BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::iterations()) + void TearDown(::benchmark::State &state) override { + provider.TearDown(state); + } -class fixed_alloc_size : public alloc_size_interface { - public: - unsigned SetUp(::benchmark::State &state, unsigned argPos) override { - size = state.range(argPos); - return argPos + 1; + void *benchAlloc(size_t size) override { + void *ptr; + if (umfMemoryProviderAlloc(provider.provider, size, 0, &ptr) != + UMF_RESULT_SUCCESS) { + return NULL; + } + return ptr; + } + + void benchFree(void *ptr, size_t size) override { + umfMemoryProviderFree(provider.provider, ptr, size); } - void TearDown([[maybe_unused]] ::benchmark::State &state) override {} - size_t nextSize() override { return size; }; - static std::vector argsName() { return {"size"}; } + + static std::string name() { return Provider::name(); } private: - size_t size; + Provider provider; }; -class uniform_alloc_size : public alloc_size_interface { - using distribution = std::uniform_int_distribution; - +// TODO: assert Pool to be a pool_interface. +template class pool_allocator : public allocator_interface { public: - unsigned SetUp(::benchmark::State &state, unsigned argPos) override { - auto min = state.range(argPos++); - auto max = state.range(argPos++); - auto gran = state.range(argPos++); - if (min % gran != 0 && max % gran != 0) { - state.SkipWithError("min and max must be divisible by granularity"); - return argPos; - } + unsigned SetUp(::benchmark::State &state, unsigned r) override { + pool.SetUp(state); + return r; + } + + void TearDown(::benchmark::State &state) override { pool.TearDown(state); } - dist.param(distribution::param_type(min / gran, max / gran)); - multiplier = gran; - return argPos; + virtual void *benchAlloc(size_t size) override { + return umfPoolMalloc(pool.pool, size); } - void TearDown([[maybe_unused]] ::benchmark::State &state) override {} - size_t nextSize() override { return dist(generator) * multiplier; } - static std::vector argsName() { - return {"min size", "max size", "granularity"}; + + virtual void benchFree(void *ptr, [[maybe_unused]] size_t size) override { + umfPoolFree(pool.pool, ptr); } + static std::string name() { return Pool::name(); } + private: - std::default_random_engine generator; - distribution dist; - size_t multiplier; + Pool pool; +}; + +template +struct benchmark_interface : public benchmark::Fixture { + void SetUp(::benchmark::State &state) { + int argPos = alloc_size.SetUp(state, 0); + allocator.SetUp(state, argPos); + } + + void TearDown(::benchmark::State &state) { + alloc_size.TearDown(state); + allocator.TearDown(state); + } + + virtual void bench(::benchmark::State &state) = 0; + + static std::vector argsName() { + auto s = Size::argsName(); + auto a = Allocator::argsName(); + std::vector res = {}; + res.insert(res.end(), s.begin(), s.end()); + 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; + Allocator allocator; }; // This class benchmarks speed of alloc() operations. @@ -335,59 +362,3 @@ class multiple_malloc_free_benchmark : public alloc_benchmark { std::default_random_engine generator; distribution dist; }; - -template ::value>> -class provider_allocator : public allocator_interface { - public: - unsigned SetUp(::benchmark::State &state, unsigned r) override { - provider.SetUp(state); - return r; - } - - void TearDown(::benchmark::State &state) override { - provider.TearDown(state); - } - - void *benchAlloc(size_t size) override { - void *ptr; - if (umfMemoryProviderAlloc(provider.provider, size, 0, &ptr) != - UMF_RESULT_SUCCESS) { - return NULL; - } - return ptr; - } - - void benchFree(void *ptr, size_t size) override { - umfMemoryProviderFree(provider.provider, ptr, size); - } - - static std::string name() { return Provider::name(); } - - private: - Provider provider; -}; - -// TODO: assert Pool to be a pool_interface. -template class pool_allocator : public allocator_interface { - public: - unsigned SetUp(::benchmark::State &state, unsigned r) override { - pool.SetUp(state); - return r; - } - - void TearDown(::benchmark::State &state) override { pool.TearDown(state); } - - 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); - } - - static std::string name() { return Pool::name(); } - - private: - Pool pool; -}; diff --git a/benchmark/benchmark_interfaces.hpp b/benchmark/benchmark_interfaces.hpp deleted file mode 100644 index 516a20b697..0000000000 --- a/benchmark/benchmark_interfaces.hpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2024 Intel Corporation - * - * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - * - */ - -#include -#include -#include -#include - -#include -#include -#include - -class alloc_size_interface { - public: - virtual unsigned SetUp([[maybe_unused]] ::benchmark::State &state, - [[maybe_unused]] unsigned argPos) = 0; - virtual void TearDown([[maybe_unused]] ::benchmark::State &state) = 0; - virtual size_t nextSize() = 0; - static std::vector argsName() { return {""}; }; -}; - -class allocator_interface { - public: - virtual unsigned SetUp([[maybe_unused]] ::benchmark::State &state, - [[maybe_unused]] unsigned argPos) = 0; - virtual void TearDown([[maybe_unused]] ::benchmark::State &state) = 0; - virtual void *benchAlloc(size_t size) = 0; - virtual void benchFree(void *ptr, [[maybe_unused]] size_t size) = 0; - static std::vector argsName() { return {}; } -}; - -template -struct benchmark_interface : public benchmark::Fixture { - void SetUp(::benchmark::State &state) { - int argPos = alloc_size.SetUp(state, 0); - allocator.SetUp(state, argPos); - } - - void TearDown(::benchmark::State &state) { - alloc_size.TearDown(state); - allocator.TearDown(state); - } - - virtual void bench(::benchmark::State &state) = 0; - - static std::vector argsName() { - auto s = Size::argsName(); - auto a = Allocator::argsName(); - std::vector res = {}; - res.insert(res.end(), s.begin(), s.end()); - 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; - Allocator allocator; -}; - -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(state), params.get(), &provider); - if (umf_result != UMF_RESULT_SUCCESS) { - state.SkipWithError("umfMemoryProviderCreate() failed"); - } - } - - virtual void TearDown([[maybe_unused]] ::benchmark::State &state) { - if (state.thread_index() != 0) { - return; - } - - if (provider) { - umfMemoryProviderDestroy(provider); - } - } - - 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, - params.get(), 0, &pool); - if (umf_result != UMF_RESULT_SUCCESS) { - state.SkipWithError("umfPoolCreate() failed"); - } - } - virtual void TearDown([[maybe_unused]] ::benchmark::State &state) { - if (state.thread_index() != 0) { - return; - } - // TODO: The scalable pool destruction process can race with other threads - // performing TLS (Thread-Local Storage) destruction. - // As a temporary workaround, we introduce a delay (sleep) - // to ensure the pool is destroyed only after all threads have completed. - // Issue: #933 - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - if (pool) { - umfPoolDestroy(pool); - } - }; - - virtual umf_memory_pool_ops_t * - getOps([[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; -}; diff --git a/benchmark/benchmark_size.hpp b/benchmark/benchmark_size.hpp new file mode 100644 index 0000000000..d17a6b2869 --- /dev/null +++ b/benchmark/benchmark_size.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +#include +#include +#include + +class alloc_size_interface { + public: + virtual unsigned SetUp([[maybe_unused]] ::benchmark::State &state, + [[maybe_unused]] unsigned argPos) = 0; + virtual void TearDown([[maybe_unused]] ::benchmark::State &state) = 0; + virtual size_t nextSize() = 0; + static std::vector argsName() { return {""}; }; +}; + +class fixed_alloc_size : public alloc_size_interface { + public: + unsigned SetUp(::benchmark::State &state, unsigned argPos) override { + size = state.range(argPos); + return argPos + 1; + } + void TearDown([[maybe_unused]] ::benchmark::State &state) override {} + size_t nextSize() override { return size; }; + static std::vector argsName() { return {"size"}; } + + private: + size_t size; +}; + +class uniform_alloc_size : public alloc_size_interface { + using distribution = std::uniform_int_distribution; + + public: + unsigned SetUp(::benchmark::State &state, unsigned argPos) override { + auto min = state.range(argPos++); + auto max = state.range(argPos++); + auto gran = state.range(argPos++); + if (min % gran != 0 && max % gran != 0) { + state.SkipWithError("min and max must be divisible by granularity"); + return argPos; + } + + dist.param(distribution::param_type(min / gran, max / gran)); + multiplier = gran; + return argPos; + } + void TearDown([[maybe_unused]] ::benchmark::State &state) override {} + size_t nextSize() override { return dist(generator) * multiplier; } + static std::vector argsName() { + return {"min size", "max size", "granularity"}; + } + + private: + std::default_random_engine generator; + distribution dist; + size_t multiplier; +}; diff --git a/benchmark/benchmark_umf.hpp b/benchmark/benchmark_umf.hpp new file mode 100644 index 0000000000..389c224ed1 --- /dev/null +++ b/benchmark/benchmark_umf.hpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2024-2025 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ +#include +#include + +#include +#include +#include + +#include +#include +#ifdef UMF_POOL_SCALABLE_ENABLED +#include +#endif +#include + +#ifdef UMF_POOL_DISJOINT_ENABLED +#include +#endif + +#ifdef UMF_POOL_JEMALLOC_ENABLED +#include +#endif + +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(state), params.get(), &provider); + if (umf_result != UMF_RESULT_SUCCESS) { + state.SkipWithError("umfMemoryProviderCreate() failed"); + } + } + + virtual void TearDown([[maybe_unused]] ::benchmark::State &state) { + if (state.thread_index() != 0) { + return; + } + + if (provider) { + umfMemoryProviderDestroy(provider); + } + } + + 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, + params.get(), 0, &pool); + if (umf_result != UMF_RESULT_SUCCESS) { + state.SkipWithError("umfPoolCreate() failed"); + } + } + virtual void TearDown([[maybe_unused]] ::benchmark::State &state) { + if (state.thread_index() != 0) { + return; + } + // TODO: The scalable pool destruction process can race with other threads + // performing TLS (Thread-Local Storage) destruction. + // As a temporary workaround, we introduce a delay (sleep) + // to ensure the pool is destroyed only after all threads have completed. + // Issue: #933 + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + if (pool) { + umfPoolDestroy(pool); + } + }; + + virtual umf_memory_pool_ops_t * + getOps([[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; +}; + +class allocator_interface { + public: + virtual unsigned SetUp([[maybe_unused]] ::benchmark::State &state, + [[maybe_unused]] unsigned argPos) = 0; + virtual void TearDown([[maybe_unused]] ::benchmark::State &state) = 0; + virtual void *benchAlloc(size_t size) = 0; + virtual void benchFree(void *ptr, [[maybe_unused]] size_t size) = 0; + static std::vector argsName() { return {}; } +}; + +struct glibc_malloc : public allocator_interface { + unsigned SetUp([[maybe_unused]] ::benchmark::State &state, + unsigned argPos) override { + return argPos; + } + void TearDown([[maybe_unused]] ::benchmark::State &state) override{}; + void *benchAlloc(size_t size) override { return malloc(size); } + void benchFree(void *ptr, [[maybe_unused]] size_t size) override { + free(ptr); + } + static std::string name() { return "glibc"; } +}; + +struct os_provider : public provider_interface { + 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}; + } + + umf_memory_provider_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfOsMemoryProviderOps(); + } + static std::string name() { return "os_provider"; } +}; + +template +struct proxy_pool : public pool_interface { + umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfProxyPoolOps(); + } + + static std::string name() { return "proxy_pool<" + Provider::name() + ">"; } +}; + +#ifdef UMF_POOL_DISJOINT_ENABLED +template +struct disjoint_pool : public pool_interface { + umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfDisjointPoolOps(); + } + + 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) { + state.SkipWithError("Failed to create disjoint pool params"); + return {nullptr, [](void *) {}}; + } + + typename pool_interface::params_ptr params( + raw_params, [](void *p) { + umfDisjointPoolParamsDestroy( + static_cast(p)); + }); + + ret = umfDisjointPoolParamsSetSlabMinSize(raw_params, 4096); + if (ret != UMF_RESULT_SUCCESS) { + state.SkipWithError("Failed to set slab min size"); + return {nullptr, [](void *) {}}; + } + + ret = umfDisjointPoolParamsSetCapacity(raw_params, 4); + if (ret != UMF_RESULT_SUCCESS) { + state.SkipWithError("Failed to set capacity"); + return {nullptr, [](void *) {}}; + } + + ret = umfDisjointPoolParamsSetMinBucketSize(raw_params, 4096); + if (ret != UMF_RESULT_SUCCESS) { + state.SkipWithError("Failed to set min bucket size"); + return {nullptr, [](void *) {}}; + } + + ret = umfDisjointPoolParamsSetMaxPoolableSize(raw_params, 4096 * 16); + if (ret != UMF_RESULT_SUCCESS) { + state.SkipWithError("Failed to set max poolable size"); + return {nullptr, [](void *) {}}; + } + + return params; + } + + static std::string name() { + return "disjoint_pool<" + Provider::name() + ">"; + } +}; +#endif + +#ifdef UMF_POOL_JEMALLOC_ENABLED +template +struct jemalloc_pool : public pool_interface { + umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfJemallocPoolOps(); + } + + static std::string name() { + return "jemalloc_pool<" + Provider::name() + ">"; + } +}; +#endif + +#ifdef UMF_POOL_SCALABLE_ENABLED +template +struct scalable_pool : public pool_interface { + virtual umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfScalablePoolOps(); + } + + static std::string name() { + return "scalable_pool<" + Provider::name() + ">"; + } +}; +#endif