Skip to content
Merged
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
36 changes: 26 additions & 10 deletions src/coarse/coarse.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,12 +744,18 @@ static block_t *find_free_block(struct ravl *free_blocks, size_t size,
size_t alignment,
coarse_strategy_t allocation_strategy) {
block_t *block;
size_t new_size = size + alignment;

switch (allocation_strategy) {
case UMF_COARSE_MEMORY_STRATEGY_FASTEST:
// Always allocate a free block of the (size + alignment) size
// and later cut out the properly aligned part leaving two remaining parts.
return free_blocks_rm_ge(free_blocks, size + alignment, 0,
if (new_size < size) {
LOG_ERR("arithmetic overflow (size + alignment)");
return NULL;
}

return free_blocks_rm_ge(free_blocks, new_size, 0,
CHECK_ONLY_THE_FIRST_BLOCK);

case UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE:
Expand All @@ -760,8 +766,13 @@ static block_t *find_free_block(struct ravl *free_blocks, size_t size,
return block;
}

if (new_size < size) {
LOG_ERR("arithmetic overflow (size + alignment)");
return NULL;
}

// If not, use the `UMF_COARSE_MEMORY_STRATEGY_FASTEST` strategy.
return free_blocks_rm_ge(free_blocks, size + alignment, 0,
return free_blocks_rm_ge(free_blocks, new_size, 0,
CHECK_ONLY_THE_FIRST_BLOCK);

case UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE:
Expand All @@ -773,9 +784,14 @@ static block_t *find_free_block(struct ravl *free_blocks, size_t size,
return block;
}

if (new_size < size) {
LOG_ERR("arithmetic overflow (size + alignment)");
return NULL;
}

// If none of them had the correct alignment,
// use the `UMF_COARSE_MEMORY_STRATEGY_FASTEST` strategy.
return free_blocks_rm_ge(free_blocks, size + alignment, 0,
return free_blocks_rm_ge(free_blocks, new_size, 0,
CHECK_ONLY_THE_FIRST_BLOCK);
}

Expand Down Expand Up @@ -1017,17 +1033,17 @@ umf_result_t coarse_alloc(coarse_t *coarse, size_t size, size_t alignment,
}

// alignment must be a power of two and a multiple or a divider of the page size
if (alignment &&
((alignment & (alignment - 1)) || ((alignment % coarse->page_size) &&
(coarse->page_size % alignment)))) {
if (alignment == 0) {
alignment = coarse->page_size;
} else if ((alignment & (alignment - 1)) ||
((alignment % coarse->page_size) &&
(coarse->page_size % alignment))) {
LOG_ERR("wrong alignment: %zu (not a power of 2 or a multiple or a "
"divider of the page size (%zu))",
alignment, coarse->page_size);
return UMF_RESULT_ERROR_INVALID_ALIGNMENT;
}

if (IS_NOT_ALIGNED(alignment, coarse->page_size)) {
alignment = ALIGN_UP(alignment, coarse->page_size);
} else if (IS_NOT_ALIGNED(alignment, coarse->page_size)) {
alignment = ALIGN_UP_SAFE(alignment, coarse->page_size);
}

if (utils_mutex_lock(&coarse->lock) != 0) {
Expand Down
10 changes: 5 additions & 5 deletions src/coarse/coarse.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ typedef struct coarse_callbacks_t {

// coarse library allocation strategy
typedef enum coarse_strategy_t {
// Check if the first free block of the 'size' size has the correct alignment.
// If not, use the `UMF_COARSE_MEMORY_STRATEGY_FASTEST` strategy.
UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE = 0,

// Always allocate a free block of the (size + alignment) size
// and cut out the properly aligned part leaving two remaining parts.
// It is the fastest strategy but causes memory fragmentation
// when alignment is greater than 0.
// It is the best strategy when alignment always equals 0.
UMF_COARSE_MEMORY_STRATEGY_FASTEST = 0,

// Check if the first free block of the 'size' size has the correct alignment.
// If not, use the `UMF_COARSE_MEMORY_STRATEGY_FASTEST` strategy.
UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE,
UMF_COARSE_MEMORY_STRATEGY_FASTEST,

// Look through all free blocks of the 'size' size
// and choose the first one with the correct alignment.
Expand Down
1 change: 0 additions & 1 deletion src/utils/utils_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ void utils_align_ptr_up_size_down(void **ptr, size_t *size, size_t alignment) {
}

ASSERT(IS_ALIGNED(p, alignment));
ASSERT(IS_ALIGNED(s, alignment));

*ptr = (void *)p;
*size = s;
Expand Down
52 changes: 42 additions & 10 deletions test/coarse_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,10 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseTest_basic_provider) {

TEST_P(CoarseWithMemoryStrategyTest, coarseTest_basic_fixed_memory) {
// preallocate some memory and initialize the vector with zeros
const size_t buff_size = 20 * MB;
const size_t buff_size = 20 * MB + coarse_params.page_size;
std::vector<char> buffer(buff_size, 0);
void *buf = (void *)buffer.data();
void *buf = (void *)ALIGN_UP_SAFE((uintptr_t)buffer.data(),
coarse_params.page_size);
ASSERT_NE(buf, nullptr);

coarse_params.cb.alloc = NULL;
Expand Down Expand Up @@ -206,9 +207,10 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseTest_basic_fixed_memory) {

TEST_P(CoarseWithMemoryStrategyTest, coarseTest_fixed_memory_various) {
// preallocate some memory and initialize the vector with zeros
const size_t buff_size = 20 * MB;
const size_t buff_size = 20 * MB + coarse_params.page_size;
std::vector<char> buffer(buff_size, 0);
void *buf = (void *)buffer.data();
void *buf = (void *)ALIGN_UP_SAFE((uintptr_t)buffer.data(),
coarse_params.page_size);
ASSERT_NE(buf, nullptr);

coarse_params.cb.alloc = NULL;
Expand Down Expand Up @@ -627,6 +629,15 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseTest_basic_free_cb_fails) {
}

TEST_P(CoarseWithMemoryStrategyTest, coarseTest_split_cb_fails) {
if (coarse_params.allocation_strategy ==
UMF_COARSE_MEMORY_STRATEGY_FASTEST) {
// This test is designed for the UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE
// and UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE strategies,
// because the UMF_COARSE_MEMORY_STRATEGY_FASTEST strategy
// looks always for a block of size greater by the page size.
return;
}

umf_memory_provider_handle_t malloc_memory_provider;
umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL,
&malloc_memory_provider);
Expand Down Expand Up @@ -702,9 +713,10 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseTest_split_cb_fails) {

TEST_P(CoarseWithMemoryStrategyTest, coarseTest_merge_cb_fails) {
// preallocate some memory and initialize the vector with zeros
const size_t buff_size = 10 * MB;
const size_t buff_size = 10 * MB + coarse_params.page_size;
std::vector<char> buffer(buff_size, 0);
void *buf = (void *)buffer.data();
void *buf = (void *)ALIGN_UP_SAFE((uintptr_t)buffer.data(),
coarse_params.page_size);
ASSERT_NE(buf, nullptr);

coarse_params.cb.alloc = NULL;
Expand Down Expand Up @@ -901,6 +913,15 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseTest_provider_alloc_not_set) {
}

TEST_P(CoarseWithMemoryStrategyTest, coarseTest_basic) {
if (coarse_params.allocation_strategy ==
UMF_COARSE_MEMORY_STRATEGY_FASTEST) {
// This test is designed for the UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE
// and UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE strategies,
// because the UMF_COARSE_MEMORY_STRATEGY_FASTEST strategy
// looks always for a block of size greater by the page size.
return;
}

umf_memory_provider_handle_t malloc_memory_provider;
umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL,
&malloc_memory_provider);
Expand Down Expand Up @@ -1065,6 +1086,15 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseTest_basic) {
}

TEST_P(CoarseWithMemoryStrategyTest, coarseTest_simple1) {
if (coarse_params.allocation_strategy ==
UMF_COARSE_MEMORY_STRATEGY_FASTEST) {
// This test is designed for the UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE
// and UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE strategies,
// because the UMF_COARSE_MEMORY_STRATEGY_FASTEST strategy
// looks always for a block of size greater by the page size.
return;
}

umf_memory_provider_handle_t malloc_memory_provider;
umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL,
&malloc_memory_provider);
Expand Down Expand Up @@ -1106,8 +1136,9 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseTest_simple1) {
ASSERT_NE(t[i], nullptr);
}

if (max_alloc_size == 0) {
max_alloc_size = coarse_get_stats(ch).alloc_size;
size_t alloc_size = coarse_get_stats(ch).alloc_size;
if (alloc_size > max_alloc_size) {
max_alloc_size = alloc_size;
}

for (int i = 0; i < nptrs; i++) {
Expand Down Expand Up @@ -1253,9 +1284,10 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseTest_alignment_provider) {

TEST_P(CoarseWithMemoryStrategyTest, coarseTest_alignment_fixed_memory) {
// preallocate some memory and initialize the vector with zeros
const size_t alloc_size = 40 * MB;
const size_t alloc_size = 40 * MB + coarse_params.page_size;
std::vector<char> buffer(alloc_size, 0);
void *buf = (void *)buffer.data();
void *buf = (void *)ALIGN_UP_SAFE((uintptr_t)buffer.data(),
coarse_params.page_size);
ASSERT_NE(buf, nullptr);

coarse_params.cb.alloc = NULL;
Expand Down
7 changes: 7 additions & 0 deletions test/provider_devdax_memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,13 @@ TEST_P(umfProviderTest, purge_force) {
test_alloc_free_success(provider.get(), page_size, 0, PURGE_FORCE);
}

TEST_P(umfProviderTest, purge_force_unalligned_alloc) {
void *ptr;
auto ret = umfMemoryProviderAlloc(provider.get(), page_plus_64, 0, &ptr);
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
test_alloc_free_success(provider.get(), page_size, 0, PURGE_FORCE);
umfMemoryProviderFree(provider.get(), ptr, page_plus_64);
}
// negative tests using test_alloc_failure

TEST_P(umfProviderTest, alloc_page64_align_page_minus_1_WRONG_ALIGNMENT_1) {
Expand Down
Loading