Skip to content

Commit

Permalink
[UMA] add more tests for allocations
Browse files Browse the repository at this point in the history
  • Loading branch information
Damian Duy committed Jul 25, 2023
1 parent ba27e7d commit a1ec340
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ enum umf_result_t umfFree(void *ptr);
enum umf_result_t umfPoolGetLastAllocationError(umf_memory_pool_handle_t hPool);

///
/// \brief Retrieve memory pool associated with a given ptr.
/// \brief Retrieve memory pool associated with a given ptr. Only memory allocated
/// with the usage of a memory provider is being tracked.
/// \param ptr pointer to memory belonging to a memory pool
/// \return Handle to a memory pool that contains ptr or NULL if pointer does not belong to any UMF pool.
umf_memory_pool_handle_t umfPoolByPtr(const void *ptr);
Expand Down
45 changes: 45 additions & 0 deletions test/unified_malloc_framework/common/pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,46 @@ auto wrapPoolUnique(umf_memory_pool_handle_t hPool) {
return umf::pool_unique_handle_t(hPool, &umfPoolDestroy);
}

bool isReallocSupported(umf_memory_pool_handle_t hPool) {
static constexpr size_t allocSize = 1;
bool supported;
auto *ptr = umfPoolMalloc(hPool, allocSize);
auto *new_ptr = umfPoolRealloc(hPool, ptr, allocSize * 2);

if (new_ptr) {
supported = true;
} else if (umfPoolGetLastAllocationError(hPool) ==
UMF_RESULT_ERROR_NOT_SUPPORTED) {
supported = false;
} else {
throw std::runtime_error("realloc failed with unexpected error");
}

umfPoolFree(hPool, new_ptr);

return supported;
}

bool isCallocSupported(umf_memory_pool_handle_t hPool) {
static constexpr size_t num = 1;
static constexpr size_t size = sizeof(int);
bool supported;
auto *ptr = umfPoolCalloc(hPool, num, size);

if (ptr) {
supported = true;
} else if (umfPoolGetLastAllocationError(hPool) ==
UMF_RESULT_ERROR_NOT_SUPPORTED) {
supported = false;
} else {
throw std::runtime_error("calloc failed with unexpected error");
}

umfPoolFree(hPool, ptr);

return supported;
}

struct pool_base {
umf_result_t initialize(umf_memory_provider_handle_t *, size_t) noexcept {
return UMF_RESULT_SUCCESS;
Expand Down Expand Up @@ -97,6 +137,8 @@ struct proxy_pool : public pool_base {
}
void *realloc(void *ptr, size_t size) noexcept {
// TODO: not supported
umf::getPoolLastStatusRef<proxy_pool>() =
UMF_RESULT_ERROR_NOT_SUPPORTED;
return nullptr;
}
void *aligned_malloc(size_t size, size_t alignment) noexcept {
Expand All @@ -116,6 +158,9 @@ struct proxy_pool : public pool_base {
EXPECT_EQ_NOEXCEPT(ret, UMF_RESULT_SUCCESS);
return ret;
}
enum umf_result_t get_last_allocation_error() {
return umf::getPoolLastStatusRef<proxy_pool>();
}
umf_memory_provider_handle_t provider;
};

Expand Down
183 changes: 175 additions & 8 deletions test/unified_malloc_framework/memoryPool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@

#include "pool.hpp"

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

#ifndef UMF_TEST_MEMORY_POOL_OPS_HPP
#define UMF_TEST_MEMORY_POOL_OPS_HPP
Expand All @@ -30,6 +33,7 @@ struct umfPoolTest : umf_test::test,
}

umf::pool_unique_handle_t pool;
static constexpr int NTHREADS = 5;
};

struct umfMultiPoolTest : umfPoolTest {
Expand Down Expand Up @@ -57,33 +61,196 @@ TEST_P(umfPoolTest, allocFree) {
umfPoolFree(pool.get(), ptr);
}

TEST_P(umfPoolTest, pow2AlignedAlloc) {
#ifdef _WIN32
// TODO: implement support for windows
GTEST_SKIP();
#endif
TEST_P(umfPoolTest, reallocFree) {
if (!umf_test::isReallocSupported(pool.get())) {
GTEST_SKIP();
}
static constexpr size_t allocSize = 64;
static constexpr size_t multiplier = 3;
auto *ptr = umfPoolMalloc(pool.get(), allocSize);
ASSERT_NE(ptr, nullptr);
auto *new_ptr = umfPoolRealloc(pool.get(), ptr, allocSize * multiplier);
ASSERT_NE(new_ptr, nullptr);
std::memset(new_ptr, 0, allocSize * multiplier);
umfPoolFree(pool.get(), new_ptr);
}

TEST_P(umfPoolTest, callocFree) {
if (!umf_test::isCallocSupported(pool.get())) {
GTEST_SKIP();
}
static constexpr size_t num = 10;
static constexpr size_t size = sizeof(int);
auto *ptr = umfPoolCalloc(pool.get(), num, size);
ASSERT_NE(ptr, nullptr);
for (size_t i = 0; i < num; ++i) {
ASSERT_EQ(((int *)ptr)[i], 0);
}
umfPoolFree(pool.get(), ptr);
}

void pow2AlignedAllocHelper(umf_memory_pool_handle_t pool) {
static constexpr size_t maxAlignment = (1u << 22);
static constexpr size_t numAllocs = 4;

for (size_t alignment = 1; alignment <= maxAlignment; alignment <<= 1) {
std::cout << alignment << std::endl;
std::vector<void *> allocs;

for (size_t alloc = 0; alloc < numAllocs; alloc++) {
auto *ptr = umfPoolAlignedMalloc(pool.get(), alignment, alignment);
auto *ptr = umfPoolAlignedMalloc(pool, alignment, alignment);
ASSERT_NE(ptr, nullptr);
ASSERT_TRUE(reinterpret_cast<uintptr_t>(ptr) % alignment == 0);
std::memset(ptr, 0, alignment);
allocs.push_back(ptr);
}

for (auto &ptr : allocs) {
umfPoolFree(pool.get(), ptr);
umfPoolFree(pool, ptr);
}
}
}

TEST_P(umfPoolTest, pow2AlignedAlloc) {
#ifdef _WIN32
// TODO: implement support for windows
GTEST_SKIP();
#endif
pow2AlignedAllocHelper(pool.get());
}

TEST_P(umfPoolTest, freeNullptr) {
void *ptr = nullptr;
auto ret = umfPoolFree(pool.get(), ptr);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
}

TEST_P(umfPoolTest, multiThreadedMallocFree) {
static constexpr size_t allocSize = 64;
auto poolMalloc = [](size_t allocSize, umf_memory_pool_handle_t pool) {
std::vector<void *> allocations;
for (size_t i = 0; i <= 10; ++i) {
allocations.emplace_back(umfPoolMalloc(pool, allocSize));
ASSERT_NE(allocations.back(), nullptr);
}

for (auto allocation : allocations) {
umfPoolFree(pool, allocation);
}
};

std::vector<std::thread> threads;
for (int i = 0; i < NTHREADS; i++) {
threads.emplace_back(poolMalloc, allocSize, pool.get());
;
}

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

TEST_P(umfPoolTest, multiThreadedpow2AlignedAlloc) {
#ifdef _WIN32
// TODO: implement support for windows
GTEST_SKIP();
#endif

auto poolpow2AlignedAlloc = [](umf_memory_pool_handle_t pool) {
pow2AlignedAllocHelper(pool);
};

std::vector<std::thread> threads;
for (int i = 0; i < NTHREADS; i++) {
threads.emplace_back(poolpow2AlignedAlloc, pool.get());
}

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

TEST_P(umfPoolTest, multiThreadedReallocFree) {
if (!umf_test::isReallocSupported(pool.get())) {
GTEST_SKIP();
}
static constexpr size_t allocSize = 64;
static constexpr size_t multiplier = 3;
auto poolRealloc = [](size_t allocSize, size_t multiplier,
umf_memory_pool_handle_t pool) {
std::vector<void *> allocations;
for (size_t i = 0; i <= 10; ++i) {
allocations.emplace_back(umfPoolMalloc(pool, allocSize));
ASSERT_NE(allocations.back(), nullptr);
}

for (auto allocation : allocations) {
auto *ptr =
umfPoolRealloc(pool, allocation, allocSize * multiplier);
umfPoolFree(pool, ptr);
}
};

std::vector<std::thread> threads;
for (int i = 0; i < NTHREADS; i++) {
threads.emplace_back(poolRealloc, allocSize, multiplier, pool.get());
}

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

TEST_P(umfPoolTest, multiThreadedCallocFree) {
if (!umf_test::isCallocSupported(pool.get())) {
GTEST_SKIP();
}
static constexpr size_t num = 10;
auto poolCalloc = [](size_t num, size_t size,
umf_memory_pool_handle_t pool) {
std::vector<void *> allocations;
for (size_t i = 0; i <= 10; ++i) {
allocations.emplace_back(umfPoolCalloc(pool, num, size));
ASSERT_NE(allocations.back(), nullptr);
}

for (auto allocation : allocations) {
umfPoolFree(pool, allocation);
}
};

std::vector<std::thread> threads;
for (int i = 0; i < NTHREADS; i++) {
threads.emplace_back(poolCalloc, num, sizeof(int), pool.get());
}

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

TEST_P(umfPoolTest, multiThreadedMallocFreeRandomSizes) {
auto poolMalloc = [](size_t allocSize, umf_memory_pool_handle_t pool) {
std::vector<void *> allocations;
for (size_t i = 0; i <= 10; ++i) {
allocations.emplace_back(umfPoolMalloc(pool, allocSize));
ASSERT_NE(allocations.back(), nullptr);
}

for (auto allocation : allocations) {
umfPoolFree(pool, allocation);
}
};

std::vector<std::thread> threads;
for (int i = 0; i < NTHREADS; i++) {
threads.emplace_back(poolMalloc, rand() % 64 + 1, pool.get());
}

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

// TODO: add similar tests for realloc/aligned_alloc, etc.
// TODO: add multithreaded tests
TEST_P(umfMultiPoolTest, memoryTracking) {
Expand Down
2 changes: 1 addition & 1 deletion test/unified_malloc_framework/memoryPoolAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ TEST_F(test, memoryPoolTrace) {
ASSERT_EQ(providerCalls.size(), provider_call_count);

ret = umfPoolGetLastAllocationError(tracingPool.get());
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED);
ASSERT_EQ(poolCalls["get_last_native_error"], 1);
ASSERT_EQ(poolCalls.size(), ++pool_call_count);

Expand Down

0 comments on commit a1ec340

Please sign in to comment.