Skip to content

Commit 1c06aa9

Browse files
committed
use the provider's GetCachelineSize() to calculate bucket sizes in DP
1 parent fcd626e commit 1c06aa9

5 files changed

Lines changed: 89 additions & 63 deletions

File tree

include/umf/pools/pool_disjoint.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
*
3-
* Copyright (C) 2023-2025 Intel Corporation
3+
* Copyright (C) 2023-2026 Intel Corporation
44
*
55
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
66
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -82,7 +82,7 @@ umfDisjointPoolParamsSetCapacity(umf_disjoint_pool_params_handle_t hParams,
8282
size_t maxCapacity);
8383

8484
/// @brief Set minimum bucket allocation size.
85-
/// @details Default value for minimum bucket size is 8.
85+
/// @details If not set, the pool uses the provider cache line size.
8686
/// @param hParams handle to the parameters of the disjoint pool.
8787
/// @param minBucketSize minimum bucket size. Must be power of 2.
8888
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.

src/pool/pool_disjoint.c

Lines changed: 58 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2022-2025 Intel Corporation
2+
* Copyright (C) 2022-2026 Intel Corporation
33
*
44
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
55
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -981,24 +981,22 @@ static bool bucket_can_pool(bucket_t *bucket) {
981981
static size_t size_to_idx(disjoint_pool_t *pool, size_t size) {
982982
assert(size <= CutOff && "Unexpected size");
983983
assert(size > 0 && "Unexpected size");
984+
assert(pool->buckets_num > 0 && "Unexpected buckets count");
984985

985-
size_t min_bucket_size = (size_t)1 << pool->min_bucket_size_exp;
986-
if (size < min_bucket_size) {
987-
return 0;
988-
}
986+
size_t left = 0;
987+
size_t right = pool->buckets_num - 1;
989988

990-
// get the position of the leftmost set bit
991-
size_t position = utils_msb64(size);
989+
while (left < right) {
990+
size_t mid = left + (right - left) / 2;
992991

993-
bool is_power_of_2 = IS_POWER_OF_2(size);
994-
bool larger_than_halfway_between_powers_of_2 =
995-
!is_power_of_2 &&
996-
(bool)((size - 1) & ((uint64_t)(1) << (position - 1)));
997-
size_t index = (position - pool->min_bucket_size_exp) * 2 +
998-
(int)(!is_power_of_2) +
999-
(int)larger_than_halfway_between_powers_of_2;
992+
if (pool->buckets[mid]->size < size) {
993+
left = mid + 1;
994+
} else {
995+
right = mid;
996+
}
997+
}
1000998

1001-
return index;
999+
return left;
10021000
}
10031001

10041002
static umf_disjoint_pool_shared_limits_t *
@@ -1120,6 +1118,7 @@ static const umf_disjoint_pool_params_t default_params = {
11201118
.max_poolable_size = 2 * 1024 * 1024, // 2MB default
11211119
.capacity = 4, // default
11221120
.min_bucket_size = 8, // default
1121+
.min_bucket_size_set = false,
11231122
.cur_pool_size = 0,
11241123
.pool_trace = 0,
11251124
.shared_limits = NULL,
@@ -1161,6 +1160,10 @@ umf_result_t disjoint_pool_initialize(umf_memory_provider_handle_t provider,
11611160
umf_result_t disjoint_pool_post_initialize(void *ppPool) {
11621161
disjoint_pool_t *disjoint_pool = (disjoint_pool_t *)ppPool;
11631162

1163+
const size_t max_bucket_num = (size_t)utils_msb64(CutOff) * 2 + 1;
1164+
size_t bucket_sizes[max_bucket_num];
1165+
size_t unique_bucket_sizes[max_bucket_num];
1166+
11641167
disjoint_pool->post_initialized = true;
11651168

11661169
if (disjoint_pool->params_overridden) {
@@ -1191,53 +1194,67 @@ umf_result_t disjoint_pool_post_initialize(void *ppPool) {
11911194
goto err_free_disjoint_pool;
11921195
}
11931196

1197+
if (!disjoint_pool->params.min_bucket_size_set) {
1198+
size_t cache_line_size;
1199+
umf_result_t ret = umfMemoryProviderGetCacheLineSize(
1200+
disjoint_pool->provider, &cache_line_size);
1201+
if (ret == UMF_RESULT_SUCCESS) {
1202+
disjoint_pool->params.min_bucket_size = cache_line_size;
1203+
}
1204+
}
1205+
11941206
// Generate buckets sized such as: 64, 96, 128, 192, ..., CutOff.
11951207
// Powers of 2 and the value halfway between the powers of 2.
1196-
size_t Size1 = disjoint_pool->params.min_bucket_size;
1208+
size_t size1 = disjoint_pool->params.min_bucket_size;
11971209

11981210
// min_bucket_size cannot be larger than CutOff.
1199-
Size1 = utils_min(Size1, CutOff);
1211+
size1 = utils_min(size1, CutOff);
1212+
1213+
// Buckets sized smaller than the bucket default size - 8 aren't needed.
1214+
size1 = utils_max(size1, UMF_DISJOINT_POOL_MIN_BUCKET_DEFAULT_SIZE);
12001215

1201-
// Buckets sized smaller than the bucket default size- 8 aren't needed.
1202-
Size1 = utils_max(Size1, UMF_DISJOINT_POOL_MIN_BUCKET_DEFAULT_SIZE);
1216+
// Calculate the size of the "halfway" bucket
1217+
size_t size2 = size1 + size1 / 2;
12031218

12041219
// Calculate the exponent for min_bucket_size used for finding buckets.
1205-
disjoint_pool->min_bucket_size_exp = (size_t)utils_msb64(Size1);
1220+
disjoint_pool->min_bucket_size_exp = (size_t)utils_msb64(size1);
12061221
if (umfDisjointPoolSharedLimitsCreate(
12071222
SIZE_MAX, &disjoint_pool->default_shared_limits) !=
12081223
UMF_RESULT_SUCCESS) {
12091224
goto err_free_known_slabs;
12101225
}
12111226

1212-
// count number of buckets, start from 1
1213-
disjoint_pool->buckets_num = 1;
1214-
size_t Size2 = Size1 + Size1 / 2;
1215-
size_t ts2 = Size2, ts1 = Size1;
1216-
while (Size2 < CutOff) {
1217-
disjoint_pool->buckets_num += 2;
1218-
Size2 *= 2;
1227+
// Calclate sizes of buckets and store them in the array.
1228+
size_t i = 0;
1229+
for (; size2 < CutOff; size1 *= 2, size2 *= 2, i += 2) {
1230+
bucket_sizes[i] =
1231+
ALIGN_UP_SAFE(size1, disjoint_pool->params.min_bucket_size);
1232+
bucket_sizes[i + 1] =
1233+
ALIGN_UP_SAFE(size2, disjoint_pool->params.min_bucket_size);
1234+
}
1235+
bucket_sizes[i] = CutOff;
1236+
1237+
// After rounding up some sizes may be equal, we need to remove duplicates
1238+
// and count the number of unique sizes.
1239+
size_t unique_count = 0;
1240+
for (size_t j = 0; j <= i; j++) {
1241+
if (j == 0 || bucket_sizes[j] != bucket_sizes[j - 1]) {
1242+
unique_bucket_sizes[unique_count++] = bucket_sizes[j];
1243+
}
12191244
}
1245+
disjoint_pool->buckets_num = unique_count;
12201246

12211247
disjoint_pool->buckets = umf_ba_global_alloc(
12221248
sizeof(*disjoint_pool->buckets) * disjoint_pool->buckets_num);
12231249
if (disjoint_pool->buckets == NULL) {
12241250
goto err_free_shared_limits;
12251251
}
12261252

1227-
size_t i = 0;
1228-
Size1 = ts1;
1229-
Size2 = ts2;
1230-
for (; Size2 < CutOff; Size1 *= 2, Size2 *= 2, i += 2) {
1231-
disjoint_pool->buckets[i] = create_bucket(
1232-
Size1, disjoint_pool, disjoint_pool_get_limits(disjoint_pool));
1233-
disjoint_pool->buckets[i + 1] = create_bucket(
1234-
Size2, disjoint_pool, disjoint_pool_get_limits(disjoint_pool));
1235-
}
1236-
disjoint_pool->buckets[i] = create_bucket(
1237-
CutOff, disjoint_pool, disjoint_pool_get_limits(disjoint_pool));
1238-
1239-
// check if all buckets were created successfully
1253+
// Create buckets for each unique size.
12401254
for (i = 0; i < disjoint_pool->buckets_num; i++) {
1255+
disjoint_pool->buckets[i] =
1256+
create_bucket(unique_bucket_sizes[i], disjoint_pool,
1257+
disjoint_pool_get_limits(disjoint_pool));
12411258
if (disjoint_pool->buckets[i] == NULL) {
12421259
goto err_free_buckets;
12431260
}
@@ -1733,6 +1750,7 @@ umfDisjointPoolParamsSetMinBucketSize(umf_disjoint_pool_params_handle_t hParams,
17331750
}
17341751

17351752
hParams->min_bucket_size = minBucketSize;
1753+
hParams->min_bucket_size_set = true;
17361754
return UMF_RESULT_SUCCESS;
17371755
}
17381756

src/pool/pool_disjoint_internal.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2025 Intel Corporation
2+
* Copyright (C) 2025-2026 Intel Corporation
33
*
44
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
55
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -120,7 +120,8 @@ typedef struct umf_disjoint_pool_params_t {
120120

121121
// Holds the minimum bucket size valid for allocation of a memory type.
122122
// This value must be a power of 2.
123-
size_t min_bucket_size; // Default: 8
123+
size_t min_bucket_size; // Default: provider cache line size
124+
bool min_bucket_size_set;
124125

125126
// Holds size of the pool managed by the allocator.
126127
size_t cur_pool_size; // Default: 0

test/pools/disjoint_pool.cpp

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2023-2025 Intel Corporation
1+
// Copyright (C) 2023-2026 Intel Corporation
22
// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
33
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
44

@@ -44,6 +44,11 @@ TEST_F(test, internals) {
4444
*pageSize = 1024;
4545
return UMF_RESULT_SUCCESS;
4646
}
47+
48+
umf_result_t get_cache_line_size(size_t *size) noexcept {
49+
*size = 128;
50+
return UMF_RESULT_SUCCESS;
51+
}
4752
};
4853
umf_memory_provider_ops_t provider_ops =
4954
umf_test::providerMakeCOps<memory_provider, void>();
@@ -78,22 +83,15 @@ TEST_F(test, internals) {
7883
EXPECT_EQ(pool->provider_min_page_size, (size_t)1024);
7984

8085
// check buckets sizes
81-
size_t expected_size = DEFAULT_DISJOINT_MIN_BUCKET_SIZE;
82-
EXPECT_EQ(pool->buckets[0]->size, expected_size);
86+
EXPECT_EQ(pool->buckets[0]->size, params->min_bucket_size);
8387
EXPECT_EQ(pool->buckets[pool->buckets_num - 1]->size,
8488
(size_t)1 << 31); // 2GB
89+
size_t prev_size = params->min_bucket_size;
8590
for (size_t i = 0; i < pool->buckets_num; i++) {
8691
bucket_t *bucket = pool->buckets[i];
8792
EXPECT_NE(bucket, nullptr);
88-
EXPECT_EQ(bucket->size, expected_size);
89-
90-
// assuming DEFAULT_DISJOINT_MIN_BUCKET_SIZE = 64, expected bucket
91-
// sizes are: 64, 96, 128, 192, 256, ..., 2GB
92-
if (i % 2 == 0) {
93-
expected_size += expected_size / 2;
94-
} else {
95-
expected_size = DEFAULT_DISJOINT_MIN_BUCKET_SIZE << ((i + 1) / 2);
96-
}
93+
EXPECT_GE(bucket->size, prev_size);
94+
prev_size = bucket->size;
9795
}
9896

9997
// test small allocations

test/pools/disjoint_pool_ctl.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2025 Intel Corporation
1+
// Copyright (C) 2025-2026 Intel Corporation
22
// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
33
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exceptiongi
44

@@ -614,19 +614,28 @@ TEST_F(test, disjointCtlBucketStats) {
614614
sizeof(count), poolWrapper.get()));
615615
EXPECT_GE(count, 0ull);
616616

617-
auto expected_bucket_size = [](size_t i) -> size_t {
618-
// Even indexes: 8 << (i/2) => 8,16,32,64,...
619-
// Odd indexes: 12 << (i/2) => 12,24,48,96,...
620-
return (i % 2 == 0) ? (size_t(8) << (i / 2)) : (size_t(12) << (i / 2));
621-
};
617+
size_t min_bucket_size = 0;
618+
ASSERT_SUCCESS(umfCtlGet("umf.pool.by_handle.{}.params.min_bucket_size",
619+
&min_bucket_size, sizeof(min_bucket_size),
620+
poolWrapper.get()));
622621

622+
// Check bucket sizes
623+
size_t prev_size = 0;
623624
for (size_t i = 0; i < count; i++) {
624625
ASSERT_SUCCESS(umfCtlGet("umf.pool.by_handle.{}.buckets.{}.size", &arg,
625626
sizeof(arg), poolWrapper.get(), i));
626-
EXPECT_EQ(arg, expected_bucket_size(i)) << "Failed for bucket: " << i;
627+
628+
// Each bucket size should be:
629+
// * greater than the previous one for >= minimum bucket size
630+
// * size aligned to the minimum bucket size
631+
EXPECT_GE(arg, prev_size);
632+
EXPECT_EQ(arg % min_bucket_size, 0ull);
633+
627634
if (arg >= alloc_size && used_bucket == SIZE_MAX) {
628635
used_bucket = i; // Find the bucket that matches alloc_size
629636
}
637+
638+
prev_size = arg;
630639
}
631640

632641
std::unordered_map<std::string, size_t> stats = {

0 commit comments

Comments
 (0)