Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions examples/ipc_level_zero/ipc_level_zero.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions include/umf/pools/pool_disjoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions src/pool/pool_disjoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
12 changes: 6 additions & 6 deletions src/pool/pool_disjoint_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
134 changes: 134 additions & 0 deletions test/pools/disjoint_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(&params);
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<memory_provider, void>();

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<memory_provider, void>();
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(&params);
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,
Expand Down
Loading