From da78dae973eaa9251b45c90716c6a51b0834ac4c Mon Sep 17 00:00:00 2001 From: Krzysztof Filipek Date: Wed, 28 May 2025 13:19:48 +0200 Subject: [PATCH 1/2] [disjoint] Set default parameters for disjoint pool --- include/umf/pools/pool_disjoint.h | 5 ++ src/pool/pool_disjoint.c | 6 +- src/pool/pool_disjoint_internal.h | 12 +-- test/pools/disjoint_pool.cpp | 134 ++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 9 deletions(-) diff --git a/include/umf/pools/pool_disjoint.h b/include/umf/pools/pool_disjoint.h index e475d1e809..2b43cee939 100644 --- a/include/umf/pools/pool_disjoint.h +++ b/include/umf/pools/pool_disjoint.h @@ -53,6 +53,7 @@ umf_result_t umfDisjointPoolParamsDestroy(umf_disjoint_pool_params_handle_t hParams); /// @brief Set minimum allocation size that will be requested from the memory provider. +/// @details Default value for minimum size of slab's is 64KB. /// @param hParams handle to the parameters of the disjoint pool. /// @param slabMinSize minimum allocation size. /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. @@ -61,6 +62,7 @@ umfDisjointPoolParamsSetSlabMinSize(umf_disjoint_pool_params_handle_t hParams, size_t slabMinSize); /// @brief Set size limit for allocations that are subject to pooling. +/// @details Default value for maximum poolable size is 2MB. /// @param hParams handle to the parameters of the disjoint pool. /// @param maxPoolableSize maximum poolable size. /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. @@ -69,6 +71,7 @@ umf_result_t umfDisjointPoolParamsSetMaxPoolableSize( /// @brief Set maximum capacity of each bucket. Each bucket will hold a /// max of \p maxCapacity unfreed slabs. +/// @details Default value for capacity is 4. /// @param hParams handle to the parameters of the disjoint pool. /// @param maxCapacity maximum capacity of each bucket. /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. @@ -77,6 +80,7 @@ umfDisjointPoolParamsSetCapacity(umf_disjoint_pool_params_handle_t hParams, size_t maxCapacity); /// @brief Set minimum bucket allocation size. +/// @details Default value for minimum bucket size is 8. /// @param hParams handle to the parameters of the disjoint pool. /// @param minBucketSize minimum bucket size. Must be power of 2. /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. @@ -85,6 +89,7 @@ umfDisjointPoolParamsSetMinBucketSize(umf_disjoint_pool_params_handle_t hParams, size_t minBucketSize); /// @brief Set trace level for pool usage statistics. +/// @details Default value for pool trace is 0 (no traces). /// @param hParams handle to the parameters of the disjoint pool. /// @param poolTrace trace level. /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. diff --git a/src/pool/pool_disjoint.c b/src/pool/pool_disjoint.c index 702a30f91a..4a1cb2ba99 100644 --- a/src/pool/pool_disjoint.c +++ b/src/pool/pool_disjoint.c @@ -1102,9 +1102,9 @@ umfDisjointPoolParamsCreate(umf_disjoint_pool_params_handle_t *hParams) { } *params = (umf_disjoint_pool_params_t){ - .slab_min_size = 0, - .max_poolable_size = 0, - .capacity = 0, + .slab_min_size = 64 * 1024, // 64K + .max_poolable_size = 2 * 1024 * 1024, // 2MB + .capacity = 4, .min_bucket_size = UMF_DISJOINT_POOL_MIN_BUCKET_DEFAULT_SIZE, .cur_pool_size = 0, .pool_trace = 0, diff --git a/src/pool/pool_disjoint_internal.h b/src/pool/pool_disjoint_internal.h index 7a63dd72ac..e52a0f4969 100644 --- a/src/pool/pool_disjoint_internal.h +++ b/src/pool/pool_disjoint_internal.h @@ -110,23 +110,23 @@ typedef struct umf_disjoint_pool_shared_limits_t { typedef struct umf_disjoint_pool_params_t { // Minimum allocation size that will be requested from the memory provider. - size_t slab_min_size; + size_t slab_min_size; // Default: 64KB // Allocations up to this limit will be subject to chunking/pooling - size_t max_poolable_size; + size_t max_poolable_size; // Default: 2MB // When pooling, each bucket will hold a max of 'capacity' unfreed slabs - size_t capacity; + size_t capacity; // Default: 4 // Holds the minimum bucket size valid for allocation of a memory type. // This value must be a power of 2. - size_t min_bucket_size; + size_t min_bucket_size; // Default: 8 // Holds size of the pool managed by the allocator. - size_t cur_pool_size; + size_t cur_pool_size; // Default: 0 // Whether to print pool usage statistics - int pool_trace; + int pool_trace; // Default: 0 // Memory limits that can be shared between multiple pool instances, // i.e. if multiple pools use the same shared_limits sum of those pools' diff --git a/test/pools/disjoint_pool.cpp b/test/pools/disjoint_pool.cpp index e1a91a58e3..92ccd0410a 100644 --- a/test/pools/disjoint_pool.cpp +++ b/test/pools/disjoint_pool.cpp @@ -361,6 +361,140 @@ TEST_F(test, disjointPoolName) { umfDisjointPoolParamsDestroy(params); } +TEST_F(test, disjointPoolDefaultParams) { + // Disjoint pool defaults + static constexpr size_t DefaultSlabMinSize = 64 * 1024; // 64K + static constexpr size_t DefaultMaxPoolableSize = 2 * 1024 * 1024; // 2MB + + umf_disjoint_pool_params_handle_t params = nullptr; + umf_memory_pool_handle_t pool = nullptr; + umf_memory_provider_handle_t provider_handle = nullptr; + + // Create disjoint pool parameters with default settings + umf_result_t res = umfDisjointPoolParamsCreate(¶ms); + EXPECT_EQ(res, UMF_RESULT_SUCCESS); + + size_t expected_free_counter = 0; + static size_t free_counter = 0; + static size_t last_requested_size = 0; + struct memory_provider : public umf_test::provider_base_t { + umf_result_t alloc(size_t size, size_t alignment, void **ptr) noexcept { + *ptr = umf_ba_global_aligned_alloc(size, alignment); + last_requested_size = size; + return UMF_RESULT_SUCCESS; + } + + umf_result_t free(void *ptr, [[maybe_unused]] size_t size) noexcept { + // do the actual free only when we expect the success + umf_ba_global_free(ptr); + free_counter++; + return UMF_RESULT_SUCCESS; + } + }; + + umf_memory_provider_ops_t provider_ops = + umf_test::providerMakeCOps(); + + auto providerUnique = + wrapProviderUnique(createProviderChecked(&provider_ops, nullptr)); + provider_handle = providerUnique.get(); + + res = umfDisjointPoolParamsSetTrace(params, 3); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + umf_result_t ret = umfPoolCreate(umfDisjointPoolOps(), provider_handle, + params, UMF_POOL_CREATE_FLAG_NONE, &pool); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + // Test allocation and deallocation + // This will use the default disjoint pool parameters + void *ptr = umfPoolMalloc(pool, DefaultSlabMinSize - 1); // Should use pool + ASSERT_NE(ptr, nullptr); + ASSERT_EQ( + last_requested_size, + DefaultSlabMinSize); // First allocated size should be at least the slab min size + ret = umfPoolFree(pool, ptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(free_counter, expected_free_counter); + + // Test allocation and deallocation with a different size + expected_free_counter = 1; + ptr = + umfPoolMalloc(pool, DefaultMaxPoolableSize + 1); // Fallback to provider + ASSERT_EQ(last_requested_size, DefaultMaxPoolableSize + 1); + ASSERT_NE(ptr, nullptr); + ret = umfPoolFree(pool, ptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(free_counter, expected_free_counter); + + // Cleaning up + umfPoolDestroy(pool); + umfDisjointPoolParamsDestroy(params); + expected_free_counter = 2; + ASSERT_EQ(free_counter, expected_free_counter); +} + +TEST_F(test, disjointPoolDefaultCapacity) { + // Disjoint pool defaults + static constexpr size_t DefaultSlabMinSize = 64 * 1024; // 64K + static constexpr size_t DefaultCapacity = 4; + + static size_t free_counter = 0; + static size_t last_requested_size = 0; + + struct memory_provider : public umf_test::provider_base_t { + umf_result_t alloc(size_t size, size_t alignment, void **ptr) noexcept { + *ptr = umf_ba_global_aligned_alloc(size, alignment); + last_requested_size = size; + return UMF_RESULT_SUCCESS; + } + umf_result_t free(void *ptr, [[maybe_unused]] size_t size) noexcept { + // do the actual free only when we expect the success + umf_ba_global_free(ptr); + free_counter++; + return UMF_RESULT_SUCCESS; + } + }; + umf_memory_provider_ops_t provider_ops = + umf_test::providerMakeCOps(); + auto providerUnique = + wrapProviderUnique(createProviderChecked(&provider_ops, nullptr)); + umf_memory_provider_handle_t provider_handle = providerUnique.get(); + umf_disjoint_pool_params_handle_t params = nullptr; + umf_result_t ret = umfDisjointPoolParamsCreate(¶ms); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + umf_memory_pool_handle_t pool = nullptr; + ret = umfPoolCreate(umfDisjointPoolOps(), provider_handle, params, + UMF_POOL_CREATE_FLAG_NONE, &pool); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + // Test capacity + void *ptrs[DefaultCapacity + 1]; + for (size_t i = 0; i < DefaultCapacity + 1; ++i) { + ptrs[i] = + umfPoolMalloc(pool, DefaultSlabMinSize - 1); // Should use pool + ASSERT_NE(ptrs[i], nullptr); + ASSERT_EQ(last_requested_size, DefaultSlabMinSize); + } + + size_t i; + for (i = 0; i < DefaultCapacity + 1; ++i) { + ret = umfPoolFree(pool, ptrs[i]); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + ASSERT_EQ( + free_counter, + i - DefaultCapacity); // only the last allocation exceeds the capacity + + // Cleaning up + umfPoolDestroy(pool); + umfDisjointPoolParamsDestroy(params); + ASSERT_EQ(free_counter, + DefaultCapacity + + 1); // +1 for the last allocation that exceeded the capacity +} + INSTANTIATE_TEST_SUITE_P(disjointPoolTests, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfDisjointPoolOps(), defaultDisjointPoolConfig, From b350c055f9f04b14e15925f8ee263eab533dd2b0 Mon Sep 17 00:00:00 2001 From: Krzysztof Filipek Date: Tue, 1 Jul 2025 16:32:38 +0200 Subject: [PATCH 2/2] [examples] Set default value for ipc level zero test --- examples/ipc_level_zero/ipc_level_zero.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/ipc_level_zero/ipc_level_zero.c b/examples/ipc_level_zero/ipc_level_zero.c index a7901cb093..df0f26c45d 100644 --- a/examples/ipc_level_zero/ipc_level_zero.c +++ b/examples/ipc_level_zero/ipc_level_zero.c @@ -76,6 +76,13 @@ int create_level_zero_pool(ze_context_handle_t context, goto provider_destroy; } + // Set max poolable size to 0 + umf_result = umfDisjointPoolParamsSetMaxPoolableSize(disjoint_params, 0); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: Failed to set max poolable size!\n"); + goto provider_destroy; + } + // create pool umf_pool_create_flags_t flags = UMF_POOL_CREATE_FLAG_OWN_PROVIDER; umf_result = umfPoolCreate(umfDisjointPoolOps(), provider, disjoint_params,