Skip to content

Commit fd816f5

Browse files
committed
Refactor coarse_alloc()
Refactor coarse_alloc(): move the code responsible for handling the `(curr == NULL)` case just after `curr = find_free_block()`. Add coarse_add_free_block(). Now (before this change) when a user calls `coarse_alloc(1, 2MB)` (allocate 1 byte with 2MB alignment) and there is no suitable blok inside the coarse allocator, a new block is allocated from the provider of size `coarse->page_size` at least, but it is added to the inner lists with the requested size of only 1 byte and the rest of space will not be able to be utilized. After this change, when a user calls `coarse_alloc(1, 2MB)` (allocate 1 byte with 2MB alignment) and there is no suitable blok inside the coarse allocator, a new block is allocated from the provider of size `alignment` (>= `coarse->page_size`) and it is added to the inner lists with the `alignment` size. The new free block will be used as a whole or split and the rest of space can be utilized later. Signed-off-by: Lukasz Dorau <[email protected]>
1 parent 52668c3 commit fd816f5

File tree

1 file changed

+86
-58
lines changed

1 file changed

+86
-58
lines changed

src/coarse/coarse.c

+86-58
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,24 @@ static umf_result_t coarse_add_used_block(coarse_t *coarse, void *addr,
623623
return UMF_RESULT_SUCCESS;
624624
}
625625

626+
static umf_result_t coarse_add_free_block(coarse_t *coarse, void *addr,
627+
size_t size, block_t **free_block) {
628+
*free_block = NULL;
629+
630+
block_t *new_block =
631+
coarse_ravl_add_new(coarse->all_blocks, addr, size, NULL);
632+
if (new_block == NULL) {
633+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
634+
}
635+
636+
new_block->used = false;
637+
coarse->alloc_size += size;
638+
639+
*free_block = new_block;
640+
641+
return UMF_RESULT_SUCCESS;
642+
}
643+
626644
static void coarse_ravl_cb_rm_all_blocks_node(void *data, void *arg) {
627645
assert(data);
628646
assert(arg);
@@ -1053,88 +1071,98 @@ umf_result_t coarse_alloc(coarse_t *coarse, size_t size, size_t alignment,
10531071

10541072
assert(debug_check(coarse));
10551073

1074+
*resultPtr = NULL;
1075+
10561076
// Find a block with greater or equal size using the given memory allocation strategy
10571077
block_t *curr = find_free_block(coarse->free_blocks, size, alignment,
10581078
coarse->allocation_strategy);
1079+
if (curr == NULL) {
1080+
// no suitable block found - try to get more memory from the upstream provider
1081+
umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
10591082

1060-
// If the block that we want to reuse has a greater size, split it.
1061-
// Try to merge the split part with the successor if it is not used.
1062-
enum { ACTION_NONE = 0, ACTION_USE, ACTION_SPLIT } action = ACTION_NONE;
1063-
1064-
if (curr && curr->size > size) {
1065-
action = ACTION_SPLIT;
1066-
} else if (curr && curr->size == size) {
1067-
action = ACTION_USE;
1068-
}
1069-
1070-
if (action) { // ACTION_SPLIT or ACTION_USE
1071-
assert(curr->used == false);
1072-
1073-
// In case of non-zero alignment create an aligned block what would be further used.
1074-
if (alignment > 0) {
1075-
umf_result = create_aligned_block(coarse, size, alignment, &curr);
1076-
if (umf_result != UMF_RESULT_SUCCESS) {
1077-
(void)free_blocks_re_add(coarse, curr);
1078-
goto err_unlock;
1079-
}
1083+
if (!coarse->cb.alloc) {
1084+
LOG_ERR("out of memory");
1085+
goto err_unlock;
10801086
}
10811087

1082-
if (action == ACTION_SPLIT) {
1083-
// Split the current block and put the new block after the one that we use.
1084-
umf_result = split_current_block(coarse, curr, size);
1085-
if (umf_result != UMF_RESULT_SUCCESS) {
1086-
(void)free_blocks_re_add(coarse, curr);
1087-
goto err_unlock;
1088-
}
1088+
size_t size_aligned = ALIGN_UP_SAFE(size, alignment);
1089+
if (size_aligned == 0) {
1090+
// cannot align up (arithmetic overflow)
1091+
size_aligned = size;
1092+
}
10891093

1090-
curr->size = size;
1094+
umf_result = coarse->cb.alloc(coarse->provider, size_aligned, alignment,
1095+
resultPtr);
1096+
if (umf_result != UMF_RESULT_SUCCESS) {
1097+
LOG_ERR("coarse_alloc_cb() failed: out of memory");
1098+
goto err_unlock;
1099+
}
10911100

1092-
LOG_DEBUG("coarse_ALLOC (split_block) %zu used %zu alloc %zu", size,
1093-
coarse->used_size, coarse->alloc_size);
1101+
ASSERT_IS_ALIGNED(((uintptr_t)(*resultPtr)), alignment);
10941102

1095-
} else { // action == ACTION_USE
1096-
LOG_DEBUG("coarse_ALLOC (same_block) %zu used %zu alloc %zu", size,
1097-
coarse->used_size, coarse->alloc_size);
1103+
block_t *new_free_block = NULL;
1104+
umf_result = coarse_add_free_block(coarse, *resultPtr, size_aligned,
1105+
&new_free_block);
1106+
if (umf_result != UMF_RESULT_SUCCESS) {
1107+
if (coarse->cb.free) {
1108+
coarse->cb.free(coarse->provider, *resultPtr, size_aligned);
1109+
}
1110+
goto err_unlock;
10981111
}
10991112

1100-
curr->used = true;
1101-
*resultPtr = curr->data;
1102-
coarse->used_size += size;
1103-
1104-
assert(debug_check(coarse));
1105-
utils_mutex_unlock(&coarse->lock);
1113+
LOG_DEBUG("coarse_ALLOC (memory_provider) %zu used %zu alloc %zu",
1114+
size_aligned, coarse->used_size, coarse->alloc_size);
11061115

1107-
return UMF_RESULT_SUCCESS;
1116+
curr = new_free_block;
11081117
}
11091118

1110-
// no suitable block found - try to get more memory from the upstream provider
1111-
umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
1112-
1113-
*resultPtr = NULL;
1119+
// If the block that we want to reuse has a greater size, split it.
1120+
// Try to merge the split part with the successor if it is not used.
1121+
enum { ACTION_NONE = 0, ACTION_USE, ACTION_SPLIT } action = ACTION_NONE;
11141122

1115-
if (!coarse->cb.alloc) {
1123+
if (curr && curr->size > size) {
1124+
action = ACTION_SPLIT;
1125+
} else if (curr && curr->size == size) {
1126+
action = ACTION_USE;
1127+
} else {
1128+
umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
11161129
LOG_ERR("out of memory");
11171130
goto err_unlock;
11181131
}
11191132

1120-
umf_result = coarse->cb.alloc(coarse->provider, size, alignment, resultPtr);
1121-
if (umf_result != UMF_RESULT_SUCCESS) {
1122-
LOG_ERR("coarse_alloc_cb() failed: out of memory");
1123-
goto err_unlock;
1124-
}
1133+
// ACTION_SPLIT or ACTION_USE
1134+
assert(curr->used == false);
11251135

1126-
ASSERT_IS_ALIGNED(((uintptr_t)(*resultPtr)), alignment);
1136+
// In case of non-zero alignment create an aligned block what would be further used.
1137+
if (alignment > 0) {
1138+
umf_result = create_aligned_block(coarse, size, alignment, &curr);
1139+
if (umf_result != UMF_RESULT_SUCCESS) {
1140+
(void)free_blocks_re_add(coarse, curr);
1141+
goto err_unlock;
1142+
}
1143+
}
11271144

1128-
umf_result = coarse_add_used_block(coarse, *resultPtr, size);
1129-
if (umf_result != UMF_RESULT_SUCCESS) {
1130-
if (coarse->cb.free) {
1131-
coarse->cb.free(coarse->provider, *resultPtr, size);
1145+
if (action == ACTION_SPLIT) {
1146+
// Split the current block and put the new block after the one that we use.
1147+
umf_result = split_current_block(coarse, curr, size);
1148+
if (umf_result != UMF_RESULT_SUCCESS) {
1149+
(void)free_blocks_re_add(coarse, curr);
1150+
goto err_unlock;
11321151
}
1133-
goto err_unlock;
1152+
1153+
curr->size = size;
1154+
1155+
LOG_DEBUG("coarse_ALLOC (split_block) %zu used %zu alloc %zu", size,
1156+
coarse->used_size, coarse->alloc_size);
1157+
1158+
} else { // action == ACTION_USE
1159+
LOG_DEBUG("coarse_ALLOC (same_block) %zu used %zu alloc %zu", size,
1160+
coarse->used_size, coarse->alloc_size);
11341161
}
11351162

1136-
LOG_DEBUG("coarse_ALLOC (memory_provider) %zu used %zu alloc %zu", size,
1137-
coarse->used_size, coarse->alloc_size);
1163+
curr->used = true;
1164+
*resultPtr = curr->data;
1165+
coarse->used_size += size;
11381166

11391167
umf_result = UMF_RESULT_SUCCESS;
11401168

0 commit comments

Comments
 (0)