From 989666ae0cfbd4fa59a37938e7369d3d92632313 Mon Sep 17 00:00:00 2001 From: Damian Duy Date: Tue, 23 May 2023 12:25:15 +0200 Subject: [PATCH] [UMA] add more tests for allocations --- .../include/uma/memory_pool.h | 3 +- test/unified_memory_allocation/memoryPool.hpp | 220 ++++++++++++++++++ 2 files changed, 222 insertions(+), 1 deletion(-) diff --git a/source/common/unified_memory_allocation/include/uma/memory_pool.h b/source/common/unified_memory_allocation/include/uma/memory_pool.h index d2cc044a58..603928140c 100644 --- a/source/common/unified_memory_allocation/include/uma/memory_pool.h +++ b/source/common/unified_memory_allocation/include/uma/memory_pool.h @@ -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); diff --git a/test/unified_memory_allocation/memoryPool.hpp b/test/unified_memory_allocation/memoryPool.hpp index c242419ba1..ff5dbe1229 100644 --- a/test/unified_memory_allocation/memoryPool.hpp +++ b/test/unified_memory_allocation/memoryPool.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #ifndef UMA_TEST_MEMORY_POOL_OPS_HPP #define UMA_TEST_MEMORY_POOL_OPS_HPP @@ -29,6 +30,7 @@ struct umaPoolTest : uma_test::test, return pool; } + static constexpr int NTHREADS = 5; uma::pool_unique_handle_t pool; }; @@ -57,6 +59,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 @@ -84,6 +105,205 @@ 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 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 allocations; + + for (size_t i = 0; i <= maxAllocs; ++i) { + allocations.emplace_back(umaPoolMalloc(pool.get(), allocSize)); + ASSERT_NE(allocations.back(), nullptr); + } + + // they are both failing + 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 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 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 allocs; + + for (size_t alloc = 0; alloc < numAllocs; alloc++) { + auto *ptr = umaPoolAlignedMalloc(pool, alignment, alignment); + ASSERT_NE(ptr, nullptr); + ASSERT_TRUE(reinterpret_cast(ptr) % alignment == 0); + std::memset(ptr, 0, alignment); + allocs.push_back(ptr); + } + + for (auto &ptr : allocs) { + umaPoolFree(pool, ptr); + } + } + }; + + std::vector 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 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 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 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 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 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 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) {