Skip to content

Commit a1ec340

Browse files
author
Damian Duy
committed
[UMA] add more tests for allocations
1 parent ba27e7d commit a1ec340

File tree

4 files changed

+223
-10
lines changed

4 files changed

+223
-10
lines changed

source/common/unified_malloc_framework/include/umf/memory_pool.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ enum umf_result_t umfFree(void *ptr);
129129
enum umf_result_t umfPoolGetLastAllocationError(umf_memory_pool_handle_t hPool);
130130

131131
///
132-
/// \brief Retrieve memory pool associated with a given ptr.
132+
/// \brief Retrieve memory pool associated with a given ptr. Only memory allocated
133+
/// with the usage of a memory provider is being tracked.
133134
/// \param ptr pointer to memory belonging to a memory pool
134135
/// \return Handle to a memory pool that contains ptr or NULL if pointer does not belong to any UMF pool.
135136
umf_memory_pool_handle_t umfPoolByPtr(const void *ptr);

test/unified_malloc_framework/common/pool.hpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,46 @@ auto wrapPoolUnique(umf_memory_pool_handle_t hPool) {
3131
return umf::pool_unique_handle_t(hPool, &umfPoolDestroy);
3232
}
3333

34+
bool isReallocSupported(umf_memory_pool_handle_t hPool) {
35+
static constexpr size_t allocSize = 1;
36+
bool supported;
37+
auto *ptr = umfPoolMalloc(hPool, allocSize);
38+
auto *new_ptr = umfPoolRealloc(hPool, ptr, allocSize * 2);
39+
40+
if (new_ptr) {
41+
supported = true;
42+
} else if (umfPoolGetLastAllocationError(hPool) ==
43+
UMF_RESULT_ERROR_NOT_SUPPORTED) {
44+
supported = false;
45+
} else {
46+
throw std::runtime_error("realloc failed with unexpected error");
47+
}
48+
49+
umfPoolFree(hPool, new_ptr);
50+
51+
return supported;
52+
}
53+
54+
bool isCallocSupported(umf_memory_pool_handle_t hPool) {
55+
static constexpr size_t num = 1;
56+
static constexpr size_t size = sizeof(int);
57+
bool supported;
58+
auto *ptr = umfPoolCalloc(hPool, num, size);
59+
60+
if (ptr) {
61+
supported = true;
62+
} else if (umfPoolGetLastAllocationError(hPool) ==
63+
UMF_RESULT_ERROR_NOT_SUPPORTED) {
64+
supported = false;
65+
} else {
66+
throw std::runtime_error("calloc failed with unexpected error");
67+
}
68+
69+
umfPoolFree(hPool, ptr);
70+
71+
return supported;
72+
}
73+
3474
struct pool_base {
3575
umf_result_t initialize(umf_memory_provider_handle_t *, size_t) noexcept {
3676
return UMF_RESULT_SUCCESS;
@@ -97,6 +137,8 @@ struct proxy_pool : public pool_base {
97137
}
98138
void *realloc(void *ptr, size_t size) noexcept {
99139
// TODO: not supported
140+
umf::getPoolLastStatusRef<proxy_pool>() =
141+
UMF_RESULT_ERROR_NOT_SUPPORTED;
100142
return nullptr;
101143
}
102144
void *aligned_malloc(size_t size, size_t alignment) noexcept {
@@ -116,6 +158,9 @@ struct proxy_pool : public pool_base {
116158
EXPECT_EQ_NOEXCEPT(ret, UMF_RESULT_SUCCESS);
117159
return ret;
118160
}
161+
enum umf_result_t get_last_allocation_error() {
162+
return umf::getPoolLastStatusRef<proxy_pool>();
163+
}
119164
umf_memory_provider_handle_t provider;
120165
};
121166

test/unified_malloc_framework/memoryPool.hpp

Lines changed: 175 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55

66
#include "pool.hpp"
77

8+
#include <array>
89
#include <cstring>
910
#include <functional>
1011
#include <random>
12+
#include <string>
13+
#include <thread>
1114

1215
#ifndef UMF_TEST_MEMORY_POOL_OPS_HPP
1316
#define UMF_TEST_MEMORY_POOL_OPS_HPP
@@ -30,6 +33,7 @@ struct umfPoolTest : umf_test::test,
3033
}
3134

3235
umf::pool_unique_handle_t pool;
36+
static constexpr int NTHREADS = 5;
3337
};
3438

3539
struct umfMultiPoolTest : umfPoolTest {
@@ -57,33 +61,196 @@ TEST_P(umfPoolTest, allocFree) {
5761
umfPoolFree(pool.get(), ptr);
5862
}
5963

60-
TEST_P(umfPoolTest, pow2AlignedAlloc) {
61-
#ifdef _WIN32
62-
// TODO: implement support for windows
63-
GTEST_SKIP();
64-
#endif
64+
TEST_P(umfPoolTest, reallocFree) {
65+
if (!umf_test::isReallocSupported(pool.get())) {
66+
GTEST_SKIP();
67+
}
68+
static constexpr size_t allocSize = 64;
69+
static constexpr size_t multiplier = 3;
70+
auto *ptr = umfPoolMalloc(pool.get(), allocSize);
71+
ASSERT_NE(ptr, nullptr);
72+
auto *new_ptr = umfPoolRealloc(pool.get(), ptr, allocSize * multiplier);
73+
ASSERT_NE(new_ptr, nullptr);
74+
std::memset(new_ptr, 0, allocSize * multiplier);
75+
umfPoolFree(pool.get(), new_ptr);
76+
}
6577

78+
TEST_P(umfPoolTest, callocFree) {
79+
if (!umf_test::isCallocSupported(pool.get())) {
80+
GTEST_SKIP();
81+
}
82+
static constexpr size_t num = 10;
83+
static constexpr size_t size = sizeof(int);
84+
auto *ptr = umfPoolCalloc(pool.get(), num, size);
85+
ASSERT_NE(ptr, nullptr);
86+
for (size_t i = 0; i < num; ++i) {
87+
ASSERT_EQ(((int *)ptr)[i], 0);
88+
}
89+
umfPoolFree(pool.get(), ptr);
90+
}
91+
92+
void pow2AlignedAllocHelper(umf_memory_pool_handle_t pool) {
6693
static constexpr size_t maxAlignment = (1u << 22);
6794
static constexpr size_t numAllocs = 4;
68-
6995
for (size_t alignment = 1; alignment <= maxAlignment; alignment <<= 1) {
7096
std::cout << alignment << std::endl;
7197
std::vector<void *> allocs;
7298

7399
for (size_t alloc = 0; alloc < numAllocs; alloc++) {
74-
auto *ptr = umfPoolAlignedMalloc(pool.get(), alignment, alignment);
100+
auto *ptr = umfPoolAlignedMalloc(pool, alignment, alignment);
75101
ASSERT_NE(ptr, nullptr);
76102
ASSERT_TRUE(reinterpret_cast<uintptr_t>(ptr) % alignment == 0);
77103
std::memset(ptr, 0, alignment);
78104
allocs.push_back(ptr);
79105
}
80106

81107
for (auto &ptr : allocs) {
82-
umfPoolFree(pool.get(), ptr);
108+
umfPoolFree(pool, ptr);
83109
}
84110
}
85111
}
86112

113+
TEST_P(umfPoolTest, pow2AlignedAlloc) {
114+
#ifdef _WIN32
115+
// TODO: implement support for windows
116+
GTEST_SKIP();
117+
#endif
118+
pow2AlignedAllocHelper(pool.get());
119+
}
120+
121+
TEST_P(umfPoolTest, freeNullptr) {
122+
void *ptr = nullptr;
123+
auto ret = umfPoolFree(pool.get(), ptr);
124+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
125+
}
126+
127+
TEST_P(umfPoolTest, multiThreadedMallocFree) {
128+
static constexpr size_t allocSize = 64;
129+
auto poolMalloc = [](size_t allocSize, umf_memory_pool_handle_t pool) {
130+
std::vector<void *> allocations;
131+
for (size_t i = 0; i <= 10; ++i) {
132+
allocations.emplace_back(umfPoolMalloc(pool, allocSize));
133+
ASSERT_NE(allocations.back(), nullptr);
134+
}
135+
136+
for (auto allocation : allocations) {
137+
umfPoolFree(pool, allocation);
138+
}
139+
};
140+
141+
std::vector<std::thread> threads;
142+
for (int i = 0; i < NTHREADS; i++) {
143+
threads.emplace_back(poolMalloc, allocSize, pool.get());
144+
;
145+
}
146+
147+
for (auto &thread : threads) {
148+
thread.join();
149+
}
150+
}
151+
152+
TEST_P(umfPoolTest, multiThreadedpow2AlignedAlloc) {
153+
#ifdef _WIN32
154+
// TODO: implement support for windows
155+
GTEST_SKIP();
156+
#endif
157+
158+
auto poolpow2AlignedAlloc = [](umf_memory_pool_handle_t pool) {
159+
pow2AlignedAllocHelper(pool);
160+
};
161+
162+
std::vector<std::thread> threads;
163+
for (int i = 0; i < NTHREADS; i++) {
164+
threads.emplace_back(poolpow2AlignedAlloc, pool.get());
165+
}
166+
167+
for (auto &thread : threads) {
168+
thread.join();
169+
}
170+
}
171+
172+
TEST_P(umfPoolTest, multiThreadedReallocFree) {
173+
if (!umf_test::isReallocSupported(pool.get())) {
174+
GTEST_SKIP();
175+
}
176+
static constexpr size_t allocSize = 64;
177+
static constexpr size_t multiplier = 3;
178+
auto poolRealloc = [](size_t allocSize, size_t multiplier,
179+
umf_memory_pool_handle_t pool) {
180+
std::vector<void *> allocations;
181+
for (size_t i = 0; i <= 10; ++i) {
182+
allocations.emplace_back(umfPoolMalloc(pool, allocSize));
183+
ASSERT_NE(allocations.back(), nullptr);
184+
}
185+
186+
for (auto allocation : allocations) {
187+
auto *ptr =
188+
umfPoolRealloc(pool, allocation, allocSize * multiplier);
189+
umfPoolFree(pool, ptr);
190+
}
191+
};
192+
193+
std::vector<std::thread> threads;
194+
for (int i = 0; i < NTHREADS; i++) {
195+
threads.emplace_back(poolRealloc, allocSize, multiplier, pool.get());
196+
}
197+
198+
for (auto &thread : threads) {
199+
thread.join();
200+
}
201+
}
202+
203+
TEST_P(umfPoolTest, multiThreadedCallocFree) {
204+
if (!umf_test::isCallocSupported(pool.get())) {
205+
GTEST_SKIP();
206+
}
207+
static constexpr size_t num = 10;
208+
auto poolCalloc = [](size_t num, size_t size,
209+
umf_memory_pool_handle_t pool) {
210+
std::vector<void *> allocations;
211+
for (size_t i = 0; i <= 10; ++i) {
212+
allocations.emplace_back(umfPoolCalloc(pool, num, size));
213+
ASSERT_NE(allocations.back(), nullptr);
214+
}
215+
216+
for (auto allocation : allocations) {
217+
umfPoolFree(pool, allocation);
218+
}
219+
};
220+
221+
std::vector<std::thread> threads;
222+
for (int i = 0; i < NTHREADS; i++) {
223+
threads.emplace_back(poolCalloc, num, sizeof(int), pool.get());
224+
}
225+
226+
for (auto &thread : threads) {
227+
thread.join();
228+
}
229+
}
230+
231+
TEST_P(umfPoolTest, multiThreadedMallocFreeRandomSizes) {
232+
auto poolMalloc = [](size_t allocSize, umf_memory_pool_handle_t pool) {
233+
std::vector<void *> allocations;
234+
for (size_t i = 0; i <= 10; ++i) {
235+
allocations.emplace_back(umfPoolMalloc(pool, allocSize));
236+
ASSERT_NE(allocations.back(), nullptr);
237+
}
238+
239+
for (auto allocation : allocations) {
240+
umfPoolFree(pool, allocation);
241+
}
242+
};
243+
244+
std::vector<std::thread> threads;
245+
for (int i = 0; i < NTHREADS; i++) {
246+
threads.emplace_back(poolMalloc, rand() % 64 + 1, pool.get());
247+
}
248+
249+
for (auto &thread : threads) {
250+
thread.join();
251+
}
252+
}
253+
87254
// TODO: add similar tests for realloc/aligned_alloc, etc.
88255
// TODO: add multithreaded tests
89256
TEST_P(umfMultiPoolTest, memoryTracking) {

test/unified_malloc_framework/memoryPoolAPI.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ TEST_F(test, memoryPoolTrace) {
8282
ASSERT_EQ(providerCalls.size(), provider_call_count);
8383

8484
ret = umfPoolGetLastAllocationError(tracingPool.get());
85-
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
85+
ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED);
8686
ASSERT_EQ(poolCalls["get_last_native_error"], 1);
8787
ASSERT_EQ(poolCalls.size(), ++pool_call_count);
8888

0 commit comments

Comments
 (0)