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 Jun 29, 2023
1 parent 87cf158 commit 669f438
Show file tree
Hide file tree
Showing 2 changed files with 223 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ enum uma_result_t umaPoolGetLastResult(uma_memory_pool_handle_t hPool,
const char **ppMessage);

///
/// \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 UMA pool.
uma_memory_pool_handle_t umaPoolByPtr(const void *ptr);
Expand Down
221 changes: 221 additions & 0 deletions test/unified_memory_allocation/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 UMA_TEST_MEMORY_POOL_OPS_HPP
#define UMA_TEST_MEMORY_POOL_OPS_HPP
Expand All @@ -29,6 +32,7 @@ struct umaPoolTest : uma_test::test,
return pool;
}

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

Expand Down Expand Up @@ -57,6 +61,25 @@ TEST_P(umaPoolTest, allocFree) {
umaPoolFree(pool.get(), ptr);
}

// TEST_P(umaPoolTest, reallocFree) {
// static constexpr size_t allocSize = 64;
// static constexpr size_t multiplier = 3;
// auto *ptr = umaPoolMalloc(pool.get(), allocSize);
// ASSERT_NE(ptr, nullptr);
// auto *new_ptr = umaPoolRealloc(pool.get(), ptr, allocSize * multiplier);
// ASSERT_NE(new_ptr, nullptr);
// std::memset(new_ptr, 0, allocSize * multiplier);
// umaPoolFree(pool.get(), new_ptr);
// }

// TEST_P(umaPoolTest, callocFree) {
// static constexpr size_t num = 10;
// static constexpr size_t size = sizeof(int);
// auto *ptr = umaPoolCalloc(pool.get(), num, size);
// ASSERT_NE(ptr, nullptr);
// umaPoolFree(pool.get(), ptr);
// }

TEST_P(umaPoolTest, pow2AlignedAlloc) {
#ifdef _WIN32
// TODO: implement support for windows
Expand Down Expand Up @@ -84,6 +107,204 @@ TEST_P(umaPoolTest, pow2AlignedAlloc) {
}
}

// TEST_P(umaPoolTest, allocZeroSize) {
// static constexpr size_t allocSize = 0;
// auto *ptr = umaPoolMalloc(pool.get(), allocSize);
// ASSERT_NE(ptr, nullptr);
// umaPoolFree(pool.get(), ptr);
// }

TEST_P(umaPoolTest, freeNullptr) {
void *ptr = nullptr;
umaPoolFree(pool.get(), ptr);
}

TEST_P(umaPoolTest, allocOutOfMem) {
static constexpr size_t numProviders = 1;
size_t numProvidersRet = 0;
std::array<uma_memory_provider_handle_t, numProviders> retProviders;
const char *pName;

auto ret = umaPoolGetMemoryProviders(pool.get(), numProviders,
retProviders.data(), &numProvidersRet);
ASSERT_EQ(ret, UMA_RESULT_SUCCESS);
ASSERT_EQ(numProvidersRet, numProviders);

for (auto provider : retProviders) {
umaMemoryProviderGetName(provider, &pName);
if (std::string(pName) == std::string("null")) {
GTEST_SKIP();
}
}

// test whether memory is kept in a pool accordingly to MaxSize
static constexpr size_t allocSize = 16;
// MaxSize equals 16 * 1024 * 1024;
static constexpr size_t maxAllocs = 1024 * 1024;

// allocate until oom
void *ptr = nullptr;
std::vector<void *> allocations;

for (size_t i = 0; i <= maxAllocs; ++i) {
allocations.emplace_back(umaPoolMalloc(pool.get(), allocSize));
ASSERT_NE(allocations.back(), nullptr);
}

ASSERT_EQ(umaPoolByPtr(allocations.back()), pool.get());

// free some memory
umaPoolFree(pool.get(), allocations.back());

allocations.pop_back();

ptr = umaPoolMalloc(pool.get(), allocSize);
ASSERT_NE(ptr, nullptr);

umaPoolFree(pool.get(), ptr);

for (auto allocation : allocations) {
umaPoolFree(pool.get(), allocation);
}
}

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

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

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

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

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

static constexpr size_t maxAlignment = (1u << 22);
static constexpr size_t numAllocs = 4;
auto poolPow2AlignedAlloc = [](size_t maxAlignment, size_t numAllocs,
uma_memory_pool_handle_t pool) {
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 = umaPoolAlignedMalloc(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) {
umaPoolFree(pool, ptr);
}
}
};

std::vector<std::thread> threads;
for (int i = 0; i < NTHREADS; i++) {
threads.push_back(std::thread(poolPow2AlignedAlloc, maxAlignment,
numAllocs, pool.get()));
}

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

// TEST_P(umaPoolTest, multiThreadedReallocFree) {
// static constexpr size_t allocSize = 64;
// static constexpr multiplier = 3;
// auto poolRealloc = [](size_t allocSize, size_t multiplier, uma_memory_pool_handle_t pool) {
// std::vector<void *> allocations;
// for (size_t i = 0; i <= 10; ++i) {
// allocations.emplace_back(umaPoolMalloc(pool, allocSize));
// ASSERT_NE(allocations.back(), nullptr);
// }

// for (auto allocation : allocations) {
// auto *ptr = umaPoolRealloc(pool, allocation, allocSize * multiplier);
// umaPoolFree(pool, ptr);
// }
// };

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

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

// TEST_P(umaPoolTest, multiThreadedCallocFree) {
// static constexpr size_t num = 10;
// auto poolCalloc = [](size_t num, size_t size,
// uma_memory_pool_handle_t pool) {
// std::vector<void *> allocations;
// for (size_t i = 0; i <= 10; ++i) {
// allocations.emplace_back(umaPoolCalloc(pool, num, size));
// ASSERT_NE(allocations.back(), nullptr);
// }

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

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

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

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

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

std::vector<std::thread> threads;
for (int i = 0; i < NTHREADS; i++) {
threads.push_back(std::thread(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(umaMultiPoolTest, memoryTracking) {
Expand Down

0 comments on commit 669f438

Please sign in to comment.