Skip to content

Commit

Permalink
Merge pull request #962 from igchor/poolTags
Browse files Browse the repository at this point in the history
Implement umfPool[Set/Get]Tag
  • Loading branch information
lukaszstolarczuk authored Dec 6, 2024
2 parents 109f4b2 + 86d2341 commit 9bf1316
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 0 deletions.
16 changes: 16 additions & 0 deletions include/umf/memory_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,22 @@ umf_memory_pool_handle_t umfPoolByPtr(const void *ptr);
umf_result_t umfPoolGetMemoryProvider(umf_memory_pool_handle_t hPool,
umf_memory_provider_handle_t *hProvider);

///
/// @brief Set a custom tag on the memory pool that can be later retrieved using umfPoolGetTag.
/// @param hPool specified memory pool
/// @param tag tag to be set
/// @param oldTag [out][optional] previous tag set on the memory pool
/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
umf_result_t umfPoolSetTag(umf_memory_pool_handle_t hPool, void *tag,
void **oldTag);

///
/// @brief Retrieve the tag associated with the memory pool or NULL if no tag is set.
/// @param hPool specified memory pool
/// @param tag [out] tag associated with the memory pool
/// @return UMF_RESULT_SUCCESS on success.
umf_result_t umfPoolGetTag(umf_memory_pool_handle_t hPool, void **tag);

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 2 additions & 0 deletions src/libumf.def
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,12 @@ EXPORTS
umfPoolFree
umfPoolGetIPCHandleSize
umfPoolGetLastAllocationError
umfPoolGetTag
umfPoolGetMemoryProvider
umfPoolMalloc
umfPoolMallocUsableSize
umfPoolRealloc
umfPoolSetTag
umfProxyPoolOps
umfPutIPCHandle
umfScalablePoolOps
Expand Down
2 changes: 2 additions & 0 deletions src/libumf.map
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,11 @@ UMF_1.0 {
umfPoolGetIPCHandleSize;
umfPoolGetLastAllocationError;
umfPoolGetMemoryProvider;
umfPoolGetTag;
umfPoolMalloc;
umfPoolMallocUsableSize;
umfPoolRealloc;
umfPoolSetTag;
umfProxyPoolOps;
umfPutIPCHandle;
umfScalablePoolOps;
Expand Down
32 changes: 32 additions & 0 deletions src/memory_pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,

pool->flags = flags;
pool->ops = *ops;
pool->tag = NULL;

if (NULL == utils_mutex_init(&pool->lock)) {
LOG_ERR("Failed to initialize mutex for pool");
ret = UMF_RESULT_ERROR_UNKNOWN;
goto err_lock_init;
}

ret = ops->initialize(pool->provider, params, &pool->pool_priv);
if (ret != UMF_RESULT_SUCCESS) {
Expand All @@ -63,6 +70,8 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
return UMF_RESULT_SUCCESS;

err_pool_init:
utils_mutex_destroy_not_free(&pool->lock);
err_lock_init:
if (!(flags & UMF_POOL_CREATE_FLAG_DISABLE_TRACKING)) {
umfMemoryProviderDestroy(pool->provider);
}
Expand All @@ -87,6 +96,8 @@ void umfPoolDestroy(umf_memory_pool_handle_t hPool) {
umfMemoryProviderDestroy(hUpstreamProvider);
}

utils_mutex_destroy_not_free(&hPool->lock);

LOG_INFO("Memory pool destroyed: %p", (void *)hPool);

// TODO: this free keeps memory in base allocator, so it can lead to OOM in some scenarios (it should be optimized)
Expand Down Expand Up @@ -172,3 +183,24 @@ umf_result_t umfPoolGetLastAllocationError(umf_memory_pool_handle_t hPool) {
UMF_CHECK((hPool != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
return hPool->ops.get_last_allocation_error(hPool->pool_priv);
}

umf_result_t umfPoolSetTag(umf_memory_pool_handle_t hPool, void *tag,
void **oldTag) {
UMF_CHECK((hPool != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
utils_mutex_lock(&hPool->lock);
if (oldTag) {
*oldTag = hPool->tag;
}
hPool->tag = tag;
utils_mutex_unlock(&hPool->lock);
return UMF_RESULT_SUCCESS;
}

umf_result_t umfPoolGetTag(umf_memory_pool_handle_t hPool, void **tag) {
UMF_CHECK((hPool != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
UMF_CHECK((tag != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT);
utils_mutex_lock(&hPool->lock);
*tag = hPool->tag;
utils_mutex_unlock(&hPool->lock);
return UMF_RESULT_SUCCESS;
}
4 changes: 4 additions & 0 deletions src/memory_pool_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extern "C" {
#endif

#include "base_alloc.h"
#include "utils_concurrency.h"

typedef struct umf_memory_pool_t {
void *pool_priv;
Expand All @@ -30,6 +31,9 @@ typedef struct umf_memory_pool_t {

// Memory provider used by the pool.
umf_memory_provider_handle_t provider;

utils_mutex_t lock;
void *tag;
} umf_memory_pool_t;

#ifdef __cplusplus
Expand Down
115 changes: 115 additions & 0 deletions test/memoryPoolAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,121 @@ TEST_F(test, BasicPoolByPtrTest) {
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
}

struct tagTest : umf_test::test {
void SetUp() override {
test::SetUp();
provider = umf_test::wrapProviderUnique(nullProviderCreate());
pool = umf_test::wrapPoolUnique(
createPoolChecked(umfProxyPoolOps(), provider.get(), nullptr));
}

umf::provider_unique_handle_t provider;
umf::pool_unique_handle_t pool;
};

TEST_F(tagTest, SetAndGet) {
umf_result_t ret = umfPoolSetTag(pool.get(), (void *)0x99, nullptr);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);

void *tag;
ret = umfPoolGetTag(pool.get(), &tag);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
ASSERT_EQ(tag, (void *)0x99);

void *oldTag;
ret = umfPoolSetTag(pool.get(), (void *)0x100, &oldTag);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
ASSERT_EQ(oldTag, (void *)0x99);

ret = umfPoolGetTag(pool.get(), &tag);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
ASSERT_EQ(tag, (void *)0x100);
}

TEST_F(tagTest, SetAndGetNull) {
umf_result_t ret = umfPoolSetTag(pool.get(), nullptr, nullptr);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);

void *tag;
ret = umfPoolGetTag(pool.get(), &tag);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
ASSERT_EQ(tag, nullptr);
}

TEST_F(tagTest, NoSetAndGet) {
void *tag;
umf_result_t ret = umfPoolGetTag(pool.get(), &tag);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
ASSERT_EQ(tag, nullptr);
}

TEST_F(tagTest, SetAndGetMt) {
static constexpr size_t NUM_THREADS = 8;
static constexpr size_t NUM_OPS_PER_THREAD = 16;

std::vector<std::thread> threads;

auto encodeTag = [](size_t thread, size_t op) -> void * {
return reinterpret_cast<void *>(thread * NUM_OPS_PER_THREAD + op);
};

auto decodeTag = [](void *tag) -> std::pair<size_t, size_t> {
auto op = reinterpret_cast<size_t>(tag) & (NUM_OPS_PER_THREAD - 1);
auto thread = reinterpret_cast<size_t>(tag) / NUM_OPS_PER_THREAD;
return {thread, op};
};

for (size_t i = 0; i < NUM_THREADS; i++) {
threads.emplace_back([this, i, encodeTag, decodeTag] {
for (size_t j = 0; j < NUM_OPS_PER_THREAD; j++) {
void *oldTag;
umf_result_t ret =
umfPoolSetTag(pool.get(), encodeTag(i, j), &oldTag);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);

void *queriedTag;
ret = umfPoolGetTag(pool.get(), &queriedTag);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);

auto [t1, op1] = decodeTag(oldTag);
auto [t2, op2] = decodeTag(queriedTag);
// if the tag was set by the same thread, the op part should be the same or higher
ASSERT_TRUE(t1 != t2 || op2 >= op1);
}
});
}

for (auto &thread : threads) {
thread.join();
}

void *tag;
auto ret = umfPoolGetTag(pool.get(), &tag);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);

auto [t, op] = decodeTag(tag);
ASSERT_TRUE(t < NUM_THREADS);
ASSERT_TRUE(op == NUM_OPS_PER_THREAD - 1);
}

TEST_F(tagTest, SetAndGetInvalidPtr) {
umf_result_t ret = umfPoolSetTag(pool.get(), nullptr, nullptr);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);

ret = umfPoolGetTag(pool.get(), nullptr);
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
}

TEST_F(tagTest, SetAndGetInvalidPool) {
umf_result_t ret =
umfPoolSetTag(nullptr, reinterpret_cast<void *>(0x1), nullptr);
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);

void *tag;
ret = umfPoolGetTag(nullptr, &tag);
ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
}

INSTANTIATE_TEST_SUITE_P(
mallocPoolTest, umfPoolTest,
::testing::Values(poolCreateExtParams{&MALLOC_POOL_OPS, nullptr,
Expand Down

0 comments on commit 9bf1316

Please sign in to comment.