Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for pool from pointer to poolFixtures.hpp #1136

Closed
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
131 changes: 104 additions & 27 deletions src/provider/provider_tracking.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,68 +37,143 @@ struct umf_memory_tracker_t {
typedef struct tracker_alloc_info_t {
umf_memory_pool_handle_t pool;
size_t size;
// list of previous entries with the same address (LIFO)
struct tracker_alloc_info_t *prev;
} tracker_alloc_info_t;

static umf_result_t umfMemoryTrackerAdd(umf_memory_tracker_handle_t hTracker,
umf_memory_pool_handle_t pool,
const void *ptr, size_t size) {
static umf_result_t
umfMemoryTrackerAddValue(umf_memory_tracker_handle_t hTracker, const void *ptr,
tracker_alloc_info_t *new_value) {
assert(ptr);
assert(new_value);

tracker_alloc_info_t *value = umf_ba_alloc(hTracker->alloc_info_allocator);
if (value == NULL) {
LOG_ERR("failed to allocate tracker value, ptr=%p, size=%zu", ptr,
size);
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}

value->pool = pool;
value->size = size;

int ret =
critnib_insert(hTracker->alloc_segments_map, (uintptr_t)ptr, value, 0);
umf_result_t umf_result = UMF_RESULT_ERROR_UNKNOWN;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this declaration to be sticked to this if:

    if (ret != EEXIST) {

Similarly to the int ret = ...


int ret = critnib_insert(hTracker->alloc_segments_map, (uintptr_t)ptr,
new_value, 0);
if (ret == 0) {
LOG_DEBUG(
"memory region is added, tracker=%p, ptr=%p, pool=%p, size=%zu",
(void *)hTracker, ptr, (void *)pool, size);
"memory region added to the tracker=%p, ptr=%p, pool=%p, size=%zu",
(void *)hTracker, ptr, (void *)new_value->pool, new_value->size);
return UMF_RESULT_SUCCESS;
}

LOG_ERR("failed to insert tracker value, ret=%d, ptr=%p, pool=%p, size=%zu",
ret, ptr, (void *)pool, size);
// failed to insert to the tracker a new value

umf_ba_free(hTracker->alloc_info_allocator, value);
if (ret != EEXIST) {
if (ret == ENOMEM) {
umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}
goto err_message;
}

// there already is an entry with the same address in the tracker

ret = utils_mutex_lock(&hTracker->splitMergeMutex);
if (ret) {
goto err_message;
}

tracker_alloc_info_t *prev_value = (tracker_alloc_info_t *)critnib_get(
hTracker->alloc_segments_map, (uintptr_t)ptr);
if (!prev_value) {
LOG_ERR("the previous entry not found in the tracker");
goto err_unlock;
}
if (new_value->pool == prev_value->pool) {
LOG_ERR("cannot add the next entry with the same address for the same "
"pool");
goto err_unlock;
}

new_value->prev = prev_value;

ret = critnib_insert(hTracker->alloc_segments_map, (uintptr_t)ptr,
new_value, 1); // update existing entry
if (ret) {
goto err_unlock;
}

utils_mutex_unlock(&hTracker->splitMergeMutex);

LOG_DEBUG(
"memory region added to the tracker=%p, ptr=%p, pool=%p, size=%zu",
(void *)hTracker, ptr, (void *)new_value->pool, new_value->size);

if (ret == ENOMEM) {
return UMF_RESULT_SUCCESS;

err_unlock:
utils_mutex_unlock(&hTracker->splitMergeMutex);

err_message:
LOG_ERR("failed to insert a new value to the tracker, ret=%d, ptr=%p, "
"pool=%p, size=%zu",
ret, ptr, (void *)new_value->pool, new_value->size);

return umf_result;
}

static umf_result_t umfMemoryTrackerAdd(umf_memory_tracker_handle_t hTracker,
umf_memory_pool_handle_t pool,
const void *ptr, size_t size) {
assert(ptr);

tracker_alloc_info_t *new_value =
umf_ba_alloc(hTracker->alloc_info_allocator);
if (new_value == NULL) {
LOG_ERR("failed to allocate a tracker value, ptr=%p, size=%zu", ptr,
size);
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}

return UMF_RESULT_ERROR_UNKNOWN;
new_value->pool = pool;
new_value->size = size;
new_value->prev = NULL;

umf_result_t umf_result =
umfMemoryTrackerAddValue(hTracker, ptr, new_value);
if (umf_result != UMF_RESULT_SUCCESS) {
umf_ba_free(hTracker->alloc_info_allocator, new_value);
return umf_result;
}

return UMF_RESULT_SUCCESS;
}

static umf_result_t umfMemoryTrackerRemove(umf_memory_tracker_handle_t hTracker,
const void *ptr) {
assert(ptr);

umf_result_t umf_result = UMF_RESULT_SUCCESS;

// TODO: there is no support for removing partial ranges (or multiple entries
// in a single remove call) yet.
// Every umfMemoryTrackerAdd(..., ptr, ...) should have a corresponding
// umfMemoryTrackerRemove call with the same ptr value.

void *value = critnib_remove(hTracker->alloc_segments_map, (uintptr_t)ptr);
tracker_alloc_info_t *value =
critnib_remove(hTracker->alloc_segments_map, (uintptr_t)ptr);
if (!value) {
LOG_ERR("pointer %p not found in the alloc_segments_map", ptr);
return UMF_RESULT_ERROR_UNKNOWN;
}

tracker_alloc_info_t *v = value;

LOG_DEBUG("memory region removed: tracker=%p, ptr=%p, size=%zu",
(void *)hTracker, ptr, v->size);
(void *)hTracker, ptr, value->size);

if (value->prev) {
tracker_alloc_info_t *prev_value = value->prev;
umf_result = umfMemoryTrackerAddValue(hTracker, ptr, prev_value);
if (umf_result != UMF_RESULT_SUCCESS) {
LOG_ERR("failed to add the previous entry to the tracker, ptr = "
"%p, size = %zu, umf_result = %d",
ptr, prev_value->size, umf_result);
}
}

umf_ba_free(hTracker->alloc_info_allocator, value);

return UMF_RESULT_SUCCESS;
return umf_result;
}

umf_memory_pool_handle_t umfMemoryTrackerGetPool(const void *ptr) {
Expand Down Expand Up @@ -247,6 +322,7 @@ static umf_result_t trackingAllocationSplit(void *hProvider, void *ptr,
goto err;
}

splitValue->prev = value->prev;
int cret =
critnib_insert(provider->hTracker->alloc_segments_map, (uintptr_t)ptr,
(void *)splitValue, 1 /* update */);
Expand Down Expand Up @@ -322,6 +398,7 @@ static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr,

// We'll have a duplicate entry for the range [highPtr, highValue->size] but this is fine,
// the value is the same anyway and we forbid removing that range concurrently
mergedValue->prev = lowValue->prev;
int cret =
critnib_insert(provider->hTracker->alloc_segments_map,
(uintptr_t)lowPtr, (void *)mergedValue, 1 /* update */);
Expand Down
156 changes: 151 additions & 5 deletions test/poolFixtures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@
#ifndef UMF_TEST_POOL_FIXTURES_HPP
#define UMF_TEST_POOL_FIXTURES_HPP 1

#include "pool.hpp"
#include "provider.hpp"
#include "umf/providers/provider_devdax_memory.h"
#include "utils/utils_sanitizers.h"

#include <array>
#include <cstring>
#include <functional>
#include <random>
#include <string>
#include <thread>

#include <umf/pools/pool_proxy.h>
#include <umf/providers/provider_devdax_memory.h>
#include <umf/providers/provider_fixed_memory.h>

#include "../malloc_compliance_tests.hpp"
#include "pool.hpp"
#include "provider.hpp"
#include "utils/utils_sanitizers.h"

typedef void *(*pfnPoolParamsCreate)();
typedef umf_result_t (*pfnPoolParamsDestroy)(void *);
Expand Down Expand Up @@ -474,4 +476,148 @@ TEST_P(umfPoolTest, mallocUsableSize) {
#endif
}

TEST_P(umfPoolTest, umfPoolAlignedMalloc) {
#ifdef _WIN32
// umfPoolAlignedMalloc() is not supported on Windows
// TODO: implement support for windows
GTEST_SKIP();
#else /* !_WIN32 */
umf_result_t umf_result;
size_t size_of_first_alloc;
void *ptr_for_pool = nullptr;

umf_memory_pool_handle_t pool_get = pool.get();
size_of_first_alloc = 2 * 1024 * 1024; // 2MB

if (!umf_test::isAlignedAllocSupported(pool_get)) {
GTEST_SKIP();
}

ptr_for_pool = umfPoolAlignedMalloc(pool_get, size_of_first_alloc,
utils_get_page_size());
ASSERT_NE(ptr_for_pool, nullptr);

umf_result = umfPoolFree(pool_get, ptr_for_pool);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
#endif /* !_WIN32 */
}

TEST_P(umfPoolTest, pool_from_ptr_whole_size_success) {
#ifdef _WIN32
// umfPoolAlignedMalloc() is not supported on Windows
// TODO: implement support for windows
GTEST_SKIP();
#else /* !_WIN32 */
umf_result_t umf_result;
size_t size_of_first_alloc;
size_t size_of_pool_from_ptr;
void *ptr_for_pool = nullptr;
void *ptr = nullptr;

umf_memory_pool_handle_t pool_get = pool.get();
size_of_first_alloc = 2 * 1024 * 1024; // 2MB

if (!umf_test::isAlignedAllocSupported(pool_get)) {
GTEST_SKIP();
}

ptr_for_pool = umfPoolAlignedMalloc(pool_get, size_of_first_alloc,
utils_get_page_size());
ASSERT_NE(ptr_for_pool, nullptr);

// Create provider parameters
size_of_pool_from_ptr = size_of_first_alloc; // whole size
umf_fixed_memory_provider_params_handle_t params = nullptr;
umf_result = umfFixedMemoryProviderParamsCreate(&params, ptr_for_pool,
size_of_pool_from_ptr);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
ASSERT_NE(params, nullptr);

umf_memory_provider_handle_t providerFromPtr = nullptr;
umf_result = umfMemoryProviderCreate(umfFixedMemoryProviderOps(), params,
&providerFromPtr);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
ASSERT_NE(providerFromPtr, nullptr);

umf_memory_pool_handle_t poolFromPtr = nullptr;
umf_result = umfPoolCreate(umfProxyPoolOps(), providerFromPtr, nullptr, 0,
&poolFromPtr);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);

ptr = umfPoolMalloc(poolFromPtr, size_of_pool_from_ptr);
ASSERT_NE(ptr, nullptr);

memset(ptr, 0xFF, size_of_pool_from_ptr);

umf_result = umfPoolFree(poolFromPtr, ptr);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);

umfPoolDestroy(poolFromPtr);
umfMemoryProviderDestroy(providerFromPtr);
umfFixedMemoryProviderParamsDestroy(params);

umf_result = umfPoolFree(pool_get, ptr_for_pool);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
#endif /* !_WIN32 */
}

TEST_P(umfPoolTest, pool_from_ptr_half_size_success) {
#ifdef _WIN32
// umfPoolAlignedMalloc() is not supported on Windows
// TODO: implement support for windows
GTEST_SKIP();
#else /* !_WIN32 */
umf_result_t umf_result;
size_t size_of_first_alloc;
size_t size_of_pool_from_ptr;
void *ptr_for_pool = nullptr;
void *ptr = nullptr;

umf_memory_pool_handle_t pool_get = pool.get();
size_of_first_alloc = 2 * 1024 * 1024; // 2MB

if (!umf_test::isAlignedAllocSupported(pool_get)) {
GTEST_SKIP();
}

ptr_for_pool = umfPoolAlignedMalloc(pool_get, size_of_first_alloc,
utils_get_page_size());
ASSERT_NE(ptr_for_pool, nullptr);

// Create provider parameters
size_of_pool_from_ptr = size_of_first_alloc / 2; // half size
umf_fixed_memory_provider_params_handle_t params = nullptr;
umf_result = umfFixedMemoryProviderParamsCreate(&params, ptr_for_pool,
size_of_pool_from_ptr);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
ASSERT_NE(params, nullptr);

umf_memory_provider_handle_t providerFromPtr = nullptr;
umf_result = umfMemoryProviderCreate(umfFixedMemoryProviderOps(), params,
&providerFromPtr);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
ASSERT_NE(providerFromPtr, nullptr);

umf_memory_pool_handle_t poolFromPtr = nullptr;
umf_result = umfPoolCreate(umfProxyPoolOps(), providerFromPtr, nullptr, 0,
&poolFromPtr);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);

ptr = umfPoolMalloc(poolFromPtr, size_of_pool_from_ptr);
ASSERT_NE(ptr, nullptr);

memset(ptr, 0xFF, size_of_pool_from_ptr);

umf_result = umfPoolFree(poolFromPtr, ptr);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);

umfPoolDestroy(poolFromPtr);
umfMemoryProviderDestroy(providerFromPtr);
umfFixedMemoryProviderParamsDestroy(params);

umf_result = umfPoolFree(pool_get, ptr_for_pool);
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
#endif /* !_WIN32 */
}

#endif /* UMF_TEST_POOL_FIXTURES_HPP */
Loading
Loading