Skip to content

Commit 0b11d42

Browse files
authored
Merge pull request #885 from vinser52/svinogra_scalable_config
Introduce config params for scalable pool
2 parents d28cb6b + e0ef5d2 commit 0b11d42

File tree

7 files changed

+283
-6
lines changed

7 files changed

+283
-6
lines changed

include/umf/pools/pool_scalable.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,47 @@
1414
extern "C" {
1515
#endif
1616

17+
#include <stdbool.h>
18+
1719
#include <umf/memory_pool.h>
1820
#include <umf/memory_provider.h>
1921

22+
struct umf_scalable_pool_params_t;
23+
24+
/// @brief handle to the parameters of the scalable pool.
25+
typedef struct umf_scalable_pool_params_t *umf_scalable_pool_params_handle_t;
26+
27+
/// @brief Create a struct to store parameters of scalable pool.
28+
/// @param hParams [out] handle to the newly created parameters struct.
29+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
30+
umf_result_t
31+
umfScalablePoolParamsCreate(umf_scalable_pool_params_handle_t *hParams);
32+
33+
/// @brief Destroy parameters struct.
34+
/// @param hParams handle to the parameters of the scalable pool.
35+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
36+
umf_result_t
37+
umfScalablePoolParamsDestroy(umf_scalable_pool_params_handle_t hParams);
38+
39+
/// @brief Set granularity of allocations that scalable pool requests from a memory provider.
40+
/// @param hParams handle to the parameters of the scalable pool.
41+
/// @param granularity granularity in bytes.
42+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
43+
umf_result_t
44+
umfScalablePoolParamsSetGranularity(umf_scalable_pool_params_handle_t hParams,
45+
size_t granularity);
46+
47+
/// @brief Set if scalable pool should keep all memory allocated from memory provider till destruction.
48+
/// @param hParams handle to the parameters of the scalable pool.
49+
/// @param keepAllMemory \p true if the scalable pool should not call
50+
/// \p umfMemoryProviderFree until it is destroyed, \p false otherwise.
51+
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
52+
umf_result_t
53+
umfScalablePoolParamsSetKeepAllMemory(umf_scalable_pool_params_handle_t hParams,
54+
bool keepAllMemory);
55+
56+
/// @brief Return \p ops structure containing pointers to the scalable pool implementation.
57+
/// @return pointer to the \p umf_memory_pool_ops_t struct.
2058
umf_memory_pool_ops_t *umfScalablePoolOps(void);
2159

2260
#ifdef __cplusplus

src/cpp_helpers.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ template <typename T> umf_memory_pool_ops_t poolOpsBase() {
7979
return ops;
8080
}
8181

82-
template <typename T> umf_memory_provider_ops_t providerOpsBase() {
82+
template <typename T> constexpr umf_memory_provider_ops_t providerOpsBase() {
8383
umf_memory_provider_ops_t ops{};
8484
ops.version = UMF_VERSION_CURRENT;
8585
ops.finalize = [](void *obj) { delete reinterpret_cast<T *>(obj); };
@@ -134,7 +134,7 @@ template <typename T, typename ParamType> umf_memory_pool_ops_t poolMakeCOps() {
134134
// C API. 'params' from ops.initialize will be casted to 'ParamType*'
135135
// and passed to T::initialize() function.
136136
template <typename T, typename ParamType>
137-
umf_memory_provider_ops_t providerMakeCOps() {
137+
constexpr umf_memory_provider_ops_t providerMakeCOps() {
138138
umf_memory_provider_ops_t ops = detail::providerOpsBase<T>();
139139

140140
ops.initialize = []([[maybe_unused]] void *params, void **obj) {

src/libumf.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,7 @@ EXPORTS
8282
umfProxyPoolOps
8383
umfPutIPCHandle
8484
umfScalablePoolOps
85+
umfScalablePoolParamsCreate
86+
umfScalablePoolParamsDestroy
87+
umfScalablePoolParamsSetGranularity
88+
umfScalablePoolParamsSetKeepAllMemory

src/libumf.map

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ UMF_1.0 {
7676
umfProxyPoolOps;
7777
umfPutIPCHandle;
7878
umfScalablePoolOps;
79+
umfScalablePoolParamsCreate;
80+
umfScalablePoolParamsDestroy;
81+
umfScalablePoolParamsSetGranularity;
82+
umfScalablePoolParamsSetKeepAllMemory;
7983
local:
8084
*;
8185
};

src/pool/pool_scalable.c

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ typedef void (*raw_free_tbb_type)(intptr_t, void *, size_t);
3131
static __TLS umf_result_t TLS_last_allocation_error;
3232
static __TLS umf_result_t TLS_last_free_error;
3333

34+
static const size_t DEFAULT_GRANULARITY = 2 * 1024 * 1024; // 2MB
3435
typedef struct tbb_mem_pool_policy_t {
3536
raw_alloc_tbb_type pAlloc;
3637
raw_free_tbb_type pFree;
@@ -39,6 +40,11 @@ typedef struct tbb_mem_pool_policy_t {
3940
unsigned fixed_pool : 1, keep_all_memory : 1, reserved : 30;
4041
} tbb_mem_pool_policy_t;
4142

43+
typedef struct umf_scalable_pool_params_t {
44+
size_t granularity;
45+
bool keep_all_memory;
46+
} umf_scalable_pool_params_t;
47+
4248
typedef struct tbb_callbacks_t {
4349
void *(*pool_malloc)(void *, size_t);
4450
void *(*pool_realloc)(void *, void *, size_t);
@@ -167,19 +173,88 @@ static void tbb_raw_free_wrapper(intptr_t pool_id, void *ptr, size_t bytes) {
167173
}
168174
}
169175

176+
umf_result_t
177+
umfScalablePoolParamsCreate(umf_scalable_pool_params_handle_t *params) {
178+
if (!params) {
179+
LOG_ERR("scalable pool params handle is NULL");
180+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
181+
}
182+
183+
umf_scalable_pool_params_t *params_data =
184+
umf_ba_global_alloc(sizeof(umf_scalable_pool_params_t));
185+
if (!params_data) {
186+
LOG_ERR("cannot allocate memory for scalable poolparams");
187+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
188+
}
189+
190+
params_data->granularity = DEFAULT_GRANULARITY;
191+
params_data->keep_all_memory = false;
192+
193+
*params = (umf_scalable_pool_params_handle_t)params_data;
194+
195+
return UMF_RESULT_SUCCESS;
196+
}
197+
198+
umf_result_t
199+
umfScalablePoolParamsDestroy(umf_scalable_pool_params_handle_t params) {
200+
if (!params) {
201+
LOG_ERR("params is NULL");
202+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
203+
}
204+
205+
umf_ba_global_free(params);
206+
207+
return UMF_RESULT_SUCCESS;
208+
}
209+
210+
umf_result_t
211+
umfScalablePoolParamsSetGranularity(umf_scalable_pool_params_handle_t params,
212+
size_t granularity) {
213+
if (!params) {
214+
LOG_ERR("params is NULL");
215+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
216+
}
217+
218+
if (granularity == 0) {
219+
LOG_ERR("granularity cannot be 0");
220+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
221+
}
222+
223+
params->granularity = granularity;
224+
225+
return UMF_RESULT_SUCCESS;
226+
}
227+
228+
umf_result_t
229+
umfScalablePoolParamsSetKeepAllMemory(umf_scalable_pool_params_handle_t params,
230+
bool keep_all_memory) {
231+
if (!params) {
232+
LOG_ERR("params is NULL");
233+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
234+
}
235+
236+
params->keep_all_memory = keep_all_memory;
237+
238+
return UMF_RESULT_SUCCESS;
239+
}
240+
170241
static umf_result_t tbb_pool_initialize(umf_memory_provider_handle_t provider,
171242
void *params, void **pool) {
172-
(void)params; // unused
173-
174-
const size_t GRANULARITY = 2 * 1024 * 1024;
175243
tbb_mem_pool_policy_t policy = {.pAlloc = tbb_raw_alloc_wrapper,
176244
.pFree = tbb_raw_free_wrapper,
177-
.granularity = GRANULARITY,
245+
.granularity = DEFAULT_GRANULARITY,
178246
.version = 1,
179247
.fixed_pool = false,
180248
.keep_all_memory = false,
181249
.reserved = 0};
182250

251+
if (params) {
252+
umf_scalable_pool_params_handle_t scalable_params =
253+
(umf_scalable_pool_params_handle_t)params;
254+
policy.granularity = scalable_params->granularity;
255+
policy.keep_all_memory = scalable_params->keep_all_memory;
256+
}
257+
183258
tbb_memory_pool_t *pool_data =
184259
umf_ba_global_alloc(sizeof(tbb_memory_pool_t));
185260
if (!pool_data) {

test/pools/scalable_pool.cpp

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,148 @@
77

88
#include "pool.hpp"
99
#include "poolFixtures.hpp"
10+
#include "provider.hpp"
1011

1112
auto defaultParams = umfOsMemoryProviderParamsDefault();
1213
INSTANTIATE_TEST_SUITE_P(scalablePoolTest, umfPoolTest,
1314
::testing::Values(poolCreateExtParams{
1415
umfScalablePoolOps(), nullptr,
1516
umfOsMemoryProviderOps(), &defaultParams,
1617
nullptr}));
18+
19+
using scalablePoolParams = std::tuple<size_t, bool>;
20+
struct umfScalablePoolParamsTest
21+
: umf_test::test,
22+
::testing::WithParamInterface<scalablePoolParams> {
23+
24+
struct validation_params_t {
25+
size_t granularity;
26+
bool keep_all_memory;
27+
};
28+
29+
struct provider_validator : public umf_test::provider_ba_global {
30+
using base_provider = umf_test::provider_ba_global;
31+
32+
umf_result_t initialize(validation_params_t *params) noexcept {
33+
EXPECT_NE(params, nullptr);
34+
expected_params = params;
35+
return UMF_RESULT_SUCCESS;
36+
}
37+
umf_result_t alloc(size_t size, size_t align, void **ptr) noexcept {
38+
EXPECT_EQ(size, expected_params->granularity);
39+
return base_provider::alloc(size, align, ptr);
40+
}
41+
umf_result_t free(void *ptr, size_t size) noexcept {
42+
EXPECT_EQ(expected_params->keep_all_memory, false);
43+
return base_provider::free(ptr, size);
44+
}
45+
46+
validation_params_t *expected_params;
47+
};
48+
49+
static constexpr umf_memory_provider_ops_t VALIDATOR_PROVIDER_OPS =
50+
umf::providerMakeCOps<provider_validator, validation_params_t>();
51+
52+
umfScalablePoolParamsTest() {}
53+
void SetUp() override {
54+
test::SetUp();
55+
auto [granularity, keep_all_memory] = this->GetParam();
56+
expected_params.granularity = granularity;
57+
expected_params.keep_all_memory = keep_all_memory;
58+
umf_result_t ret = umfScalablePoolParamsCreate(&params);
59+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
60+
ret = umfScalablePoolParamsSetGranularity(params, granularity);
61+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
62+
ret = umfScalablePoolParamsSetKeepAllMemory(params, keep_all_memory);
63+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
64+
}
65+
66+
void TearDown() override {
67+
umfScalablePoolParamsDestroy(params);
68+
test::TearDown();
69+
}
70+
71+
umf::pool_unique_handle_t makePool() {
72+
umf_memory_provider_handle_t hProvider = nullptr;
73+
umf_memory_pool_handle_t hPool = nullptr;
74+
75+
auto ret = umfMemoryProviderCreate(&VALIDATOR_PROVIDER_OPS,
76+
&expected_params, &hProvider);
77+
EXPECT_EQ(ret, UMF_RESULT_SUCCESS);
78+
79+
ret = umfPoolCreate(umfScalablePoolOps(), hProvider, params,
80+
UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &hPool);
81+
EXPECT_EQ(ret, UMF_RESULT_SUCCESS);
82+
83+
return umf::pool_unique_handle_t(hPool, &umfPoolDestroy);
84+
}
85+
86+
void allocFreeFlow() {
87+
static const size_t ALLOC_SIZE = 128;
88+
static const size_t NUM_ALLOCATIONS =
89+
expected_params.granularity / ALLOC_SIZE * 20;
90+
std::vector<void *> ptrs;
91+
92+
auto pool = makePool();
93+
ASSERT_NE(pool, nullptr);
94+
95+
for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) {
96+
auto *ptr = umfPoolMalloc(pool.get(), ALLOC_SIZE);
97+
ASSERT_NE(ptr, nullptr);
98+
ptrs.push_back(ptr);
99+
}
100+
101+
for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) {
102+
auto ret = umfPoolFree(pool.get(), ptrs[i]);
103+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
104+
}
105+
106+
// Now pool can call free during pool destruction
107+
expected_params.keep_all_memory = false;
108+
}
109+
110+
validation_params_t expected_params;
111+
umf_scalable_pool_params_handle_t params;
112+
};
113+
114+
TEST_P(umfScalablePoolParamsTest, allocFree) { allocFreeFlow(); }
115+
116+
TEST_P(umfScalablePoolParamsTest, updateParams) {
117+
expected_params.granularity *= 2;
118+
umf_result_t ret = umfScalablePoolParamsSetGranularity(
119+
params, expected_params.granularity);
120+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
121+
122+
expected_params.keep_all_memory = !expected_params.keep_all_memory;
123+
ret = umfScalablePoolParamsSetKeepAllMemory(
124+
params, expected_params.keep_all_memory);
125+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
126+
127+
allocFreeFlow();
128+
}
129+
130+
TEST_P(umfScalablePoolParamsTest, invalidParams) {
131+
umf_result_t ret = umfScalablePoolParamsCreate(nullptr);
132+
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
133+
134+
ret = umfScalablePoolParamsSetGranularity(nullptr, 2 * 1024 * 1024);
135+
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
136+
137+
ret = umfScalablePoolParamsSetGranularity(params, 0);
138+
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
139+
140+
ret = umfScalablePoolParamsSetKeepAllMemory(nullptr, true);
141+
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
142+
143+
ret = umfScalablePoolParamsSetKeepAllMemory(nullptr, false);
144+
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
145+
146+
ret = umfScalablePoolParamsDestroy(nullptr);
147+
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
148+
}
149+
150+
INSTANTIATE_TEST_SUITE_P(
151+
scalablePoolTest, umfScalablePoolParamsTest,
152+
testing::Combine(testing::Values(2 * 1024 * 1024, 3 * 1024 * 1024,
153+
4 * 1024 * 1024, 5 * 1024 * 1024),
154+
testing::Values(false, true)));
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
Conditional jump or move depends on uninitialised value(s) - internal issue of libtbbmalloc.so
3+
Memcheck:Cond
4+
fun:_ZN3rml9pool_freeEPNS_10MemoryPoolEPv
5+
fun:tbb_free
6+
fun:umfPoolFree
7+
...
8+
}
9+
10+
{
11+
Conditional jump or move depends on uninitialised value(s) - internal issue of libtbbmalloc.so
12+
Memcheck:Cond
13+
obj:*libtbbmalloc.so*
14+
fun:_ZN3rml9pool_freeEPNS_10MemoryPoolEPv
15+
fun:tbb_free
16+
fun:umfPoolFree
17+
...
18+
}

0 commit comments

Comments
 (0)