diff --git a/src/cpp_helpers.hpp b/src/cpp_helpers.hpp index aafc7c4db..6316ccbc7 100644 --- a/src/cpp_helpers.hpp +++ b/src/cpp_helpers.hpp @@ -79,7 +79,7 @@ template umf_memory_pool_ops_t poolOpsBase() { return ops; } -template umf_memory_provider_ops_t providerOpsBase() { +template constexpr umf_memory_provider_ops_t providerOpsBase() { umf_memory_provider_ops_t ops{}; ops.version = UMF_VERSION_CURRENT; ops.finalize = [](void *obj) { delete reinterpret_cast(obj); }; @@ -134,7 +134,7 @@ template umf_memory_pool_ops_t poolMakeCOps() { // C API. 'params' from ops.initialize will be casted to 'ParamType*' // and passed to T::initialize() function. template -umf_memory_provider_ops_t providerMakeCOps() { +constexpr umf_memory_provider_ops_t providerMakeCOps() { umf_memory_provider_ops_t ops = detail::providerOpsBase(); ops.initialize = []([[maybe_unused]] void *params, void **obj) { diff --git a/test/pools/scalable_pool.cpp b/test/pools/scalable_pool.cpp index 2be29eb9d..027d7ea60 100644 --- a/test/pools/scalable_pool.cpp +++ b/test/pools/scalable_pool.cpp @@ -7,6 +7,7 @@ #include "pool.hpp" #include "poolFixtures.hpp" +#include "provider.hpp" auto defaultParams = umfOsMemoryProviderParamsDefault(); INSTANTIATE_TEST_SUITE_P(scalablePoolTest, umfPoolTest, @@ -14,3 +15,140 @@ INSTANTIATE_TEST_SUITE_P(scalablePoolTest, umfPoolTest, umfScalablePoolOps(), nullptr, umfOsMemoryProviderOps(), &defaultParams, nullptr})); + +using scalablePoolParams = std::tuple; +struct umfScalablePoolParamsTest + : umf_test::test, + ::testing::WithParamInterface { + + struct validation_params_t { + size_t granularity; + bool keep_all_memory; + }; + + struct provider_validator : public umf_test::provider_ba_global { + using base_provider = umf_test::provider_ba_global; + + umf_result_t initialize(validation_params_t *params) noexcept { + EXPECT_NE(params, nullptr); + expected_params = params; + return UMF_RESULT_SUCCESS; + } + umf_result_t alloc(size_t size, size_t align, void **ptr) noexcept { + EXPECT_EQ(size, expected_params->granularity); + return base_provider::alloc(size, align, ptr); + } + umf_result_t free(void *ptr, size_t size) noexcept { + EXPECT_EQ(expected_params->keep_all_memory, false); + return base_provider::free(ptr, size); + } + + validation_params_t *expected_params; + }; + + static constexpr umf_memory_provider_ops_t VALIDATOR_PROVIDER_OPS = + umf::providerMakeCOps(); + + umfScalablePoolParamsTest() {} + void SetUp() override { + test::SetUp(); + auto [granularity, keep_all_memory] = this->GetParam(); + expected_params.granularity = granularity; + expected_params.keep_all_memory = keep_all_memory; + umf_result_t ret = umfScalablePoolParamsCreate(¶ms); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ret = umfScalablePoolParamsSetGranularity(params, granularity); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ret = umfScalablePoolParamsSetKeepAllMemory(params, keep_all_memory); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + void TearDown() override { + umfScalablePoolParamsDestroy(params); + test::TearDown(); + } + + umf::pool_unique_handle_t makePool() { + umf_memory_provider_handle_t hProvider = NULL; + umf_memory_pool_handle_t hPool = NULL; + + auto ret = umfMemoryProviderCreate(&VALIDATOR_PROVIDER_OPS, + &expected_params, &hProvider); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolCreate(umfScalablePoolOps(), hProvider, params, + UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &hPool); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + return umf::pool_unique_handle_t(hPool, &umfPoolDestroy); + } + + void allocFreeFlow() { + static const size_t ALLOC_SIZE = 128; + static const size_t NUM_ALLOCATIONS = + expected_params.granularity / ALLOC_SIZE * 20; + std::vector ptrs; + + auto pool = makePool(); + ASSERT_NE(pool, nullptr); + + for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) { + auto *ptr = umfPoolMalloc(pool.get(), ALLOC_SIZE); + ASSERT_NE(ptr, nullptr); + ptrs.push_back(ptr); + } + + for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) { + auto ret = umfPoolFree(pool.get(), ptrs[i]); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + // Now pool can call free during pool destruction + expected_params.keep_all_memory = false; + } + + validation_params_t expected_params; + umf_scalable_pool_params_handle_t params; +}; + +TEST_P(umfScalablePoolParamsTest, allocFree) { allocFreeFlow(); } + +TEST_P(umfScalablePoolParamsTest, updateParams) { + expected_params.granularity *= 2; + umf_result_t ret = umfScalablePoolParamsSetGranularity( + params, expected_params.granularity); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + expected_params.keep_all_memory = !expected_params.keep_all_memory; + ret = umfScalablePoolParamsSetKeepAllMemory( + params, expected_params.keep_all_memory); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + allocFreeFlow(); +} + +TEST_P(umfScalablePoolParamsTest, invalidParams) { + umf_result_t ret = umfScalablePoolParamsCreate(nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsSetGranularity(nullptr, 2 * 1024 * 1024); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsSetGranularity(params, 0); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsSetKeepAllMemory(NULL, true); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsSetKeepAllMemory(NULL, false); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsDestroy(nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +INSTANTIATE_TEST_SUITE_P( + scalablePoolTest, umfScalablePoolParamsTest, + testing::Combine(testing::Values(2 * 1024 * 1024, 3 * 1024 * 1024, + 4 * 1024 * 1024, 5 * 1024 * 1024), + testing::Values(false, true))); diff --git a/test/supp/memcheck-umf_test-scalable_pool.supp b/test/supp/memcheck-umf_test-scalable_pool.supp new file mode 100644 index 000000000..114dfb236 --- /dev/null +++ b/test/supp/memcheck-umf_test-scalable_pool.supp @@ -0,0 +1,18 @@ +{ + Conditional jump or move depends on uninitialised value(s) - internal issue of libtbbmalloc.so + Memcheck:Cond + fun:_ZN3rml9pool_freeEPNS_10MemoryPoolEPv + fun:tbb_free + fun:umfPoolFree + ... +} + +{ + Conditional jump or move depends on uninitialised value(s) - internal issue of libtbbmalloc.so + Memcheck:Cond + obj:*libtbbmalloc.so* + fun:_ZN3rml9pool_freeEPNS_10MemoryPoolEPv + fun:tbb_free + fun:umfPoolFree + ... +}