Skip to content

Commit 02813ef

Browse files
committed
Implement split()/merge() API of the Coarse provider
Signed-off-by: Lukasz Dorau <[email protected]>
1 parent 589991c commit 02813ef

File tree

2 files changed

+347
-3
lines changed

2 files changed

+347
-3
lines changed

src/provider/provider_coarse.c

Lines changed: 255 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,261 @@ coarse_memory_provider_get_stats(void *provider,
13901390
return UMF_RESULT_SUCCESS;
13911391
}
13921392

1393+
static umf_result_t coarse_memory_provider_purge_lazy(void *provider, void *ptr,
1394+
size_t size) {
1395+
if (provider == NULL || ptr == NULL) {
1396+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1397+
}
1398+
1399+
coarse_memory_provider_t *coarse_provider =
1400+
(struct coarse_memory_provider_t *)provider;
1401+
if (coarse_provider->upstream_memory_provider == NULL) {
1402+
LOG_ERR("no upstream memory provider given");
1403+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1404+
}
1405+
1406+
return umfMemoryProviderPurgeLazy(coarse_provider->upstream_memory_provider,
1407+
ptr, size);
1408+
}
1409+
1410+
static umf_result_t coarse_memory_provider_purge_force(void *provider,
1411+
void *ptr, size_t size) {
1412+
if (provider == NULL || ptr == NULL) {
1413+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1414+
}
1415+
1416+
coarse_memory_provider_t *coarse_provider =
1417+
(struct coarse_memory_provider_t *)provider;
1418+
if (coarse_provider->upstream_memory_provider == NULL) {
1419+
LOG_ERR("no upstream memory provider given");
1420+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1421+
}
1422+
1423+
return umfMemoryProviderPurgeForce(
1424+
coarse_provider->upstream_memory_provider, ptr, size);
1425+
}
1426+
1427+
static umf_result_t coarse_memory_provider_allocation_split(void *provider,
1428+
void *ptr,
1429+
size_t totalSize,
1430+
size_t firstSize) {
1431+
if (provider == NULL || ptr == NULL || (firstSize >= totalSize) ||
1432+
firstSize == 0) {
1433+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1434+
}
1435+
1436+
umf_result_t umf_result;
1437+
1438+
coarse_memory_provider_t *coarse_provider =
1439+
(struct coarse_memory_provider_t *)provider;
1440+
1441+
if (utils_mutex_lock(&coarse_provider->lock) != 0) {
1442+
LOG_ERR("lockng the lock failed");
1443+
return UMF_RESULT_ERROR_UNKNOWN;
1444+
}
1445+
1446+
assert(debug_check(coarse_provider));
1447+
1448+
block_t *block = coarse_ravl_find(coarse_provider->all_blocks, ptr);
1449+
if (block == NULL) {
1450+
LOG_ERR("memory block not found");
1451+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1452+
goto err_mutex_unlock;
1453+
}
1454+
1455+
if (block->size != totalSize) {
1456+
LOG_ERR("wrong totalSize");
1457+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1458+
goto err_mutex_unlock;
1459+
}
1460+
1461+
if (!block->used) {
1462+
LOG_ERR("block is not allocated");
1463+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1464+
goto err_mutex_unlock;
1465+
}
1466+
1467+
block_t *new_block =
1468+
coarse_ravl_add_new(coarse_provider->all_blocks,
1469+
block->data + firstSize, block->size - firstSize);
1470+
if (new_block == NULL) {
1471+
umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
1472+
goto err_mutex_unlock;
1473+
}
1474+
1475+
block->size = firstSize;
1476+
new_block->used = true;
1477+
1478+
assert(new_block->size == (totalSize - firstSize));
1479+
1480+
assert(debug_check(coarse_provider));
1481+
1482+
if (utils_mutex_unlock(&coarse_provider->lock) != 0) {
1483+
LOG_ERR("unlockng the lock failed");
1484+
return UMF_RESULT_ERROR_UNKNOWN;
1485+
}
1486+
1487+
return UMF_RESULT_SUCCESS;
1488+
1489+
err_mutex_unlock:
1490+
assert(debug_check(coarse_provider));
1491+
utils_mutex_unlock(&coarse_provider->lock);
1492+
return umf_result;
1493+
}
1494+
1495+
static umf_result_t coarse_memory_provider_allocation_merge(void *provider,
1496+
void *lowPtr,
1497+
void *highPtr,
1498+
size_t totalSize) {
1499+
if (provider == NULL || lowPtr == NULL || highPtr == NULL ||
1500+
((uintptr_t)highPtr <= (uintptr_t)lowPtr) ||
1501+
((uintptr_t)highPtr - (uintptr_t)lowPtr >= totalSize)) {
1502+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1503+
}
1504+
1505+
umf_result_t umf_result;
1506+
1507+
coarse_memory_provider_t *coarse_provider =
1508+
(struct coarse_memory_provider_t *)provider;
1509+
1510+
if (utils_mutex_lock(&coarse_provider->lock) != 0) {
1511+
LOG_ERR("lockng the lock failed");
1512+
return UMF_RESULT_ERROR_UNKNOWN;
1513+
}
1514+
1515+
assert(debug_check(coarse_provider));
1516+
1517+
block_t *low_block = coarse_ravl_find(coarse_provider->all_blocks, lowPtr);
1518+
if (low_block == NULL) {
1519+
LOG_ERR("the lowPtr memory block not found");
1520+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1521+
goto err_mutex_unlock;
1522+
}
1523+
1524+
if (!low_block->used) {
1525+
LOG_ERR("the lowPtr block is not allocated");
1526+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1527+
goto err_mutex_unlock;
1528+
}
1529+
1530+
block_t *high_block =
1531+
coarse_ravl_find(coarse_provider->all_blocks, highPtr);
1532+
if (high_block == NULL) {
1533+
LOG_ERR("the highPtr memory block not found");
1534+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1535+
goto err_mutex_unlock;
1536+
}
1537+
1538+
if (!high_block->used) {
1539+
LOG_ERR("the highPtr block is not allocated");
1540+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1541+
goto err_mutex_unlock;
1542+
}
1543+
1544+
if (low_block->size + high_block->size != totalSize) {
1545+
LOG_ERR("wrong totalSize");
1546+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1547+
goto err_mutex_unlock;
1548+
}
1549+
1550+
if ((uintptr_t)highPtr != ((uintptr_t)lowPtr + low_block->size)) {
1551+
LOG_ERR("given pointers cannot be merged");
1552+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1553+
goto err_mutex_unlock;
1554+
}
1555+
1556+
if (get_block_next(coarse_provider->all_blocks, low_block) != high_block) {
1557+
LOG_ERR("given pointers cannot be merged");
1558+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1559+
goto err_mutex_unlock;
1560+
}
1561+
1562+
if (get_block_prev(coarse_provider->all_blocks, high_block) != low_block) {
1563+
LOG_ERR("given pointers cannot be merged");
1564+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1565+
goto err_mutex_unlock;
1566+
}
1567+
1568+
block_t *merged_block = NULL;
1569+
1570+
umf_result = block_merge_with_prev(
1571+
coarse_provider->upstream_memory_provider, coarse_provider->all_blocks,
1572+
NULL, high_block, true, &merged_block);
1573+
if (umf_result != UMF_RESULT_SUCCESS) {
1574+
LOG_ERR("merging failed");
1575+
goto err_mutex_unlock;
1576+
}
1577+
1578+
assert(merged_block == low_block);
1579+
assert(low_block->size == totalSize);
1580+
1581+
assert(debug_check(coarse_provider));
1582+
1583+
if (utils_mutex_unlock(&coarse_provider->lock) != 0) {
1584+
LOG_ERR("unlockng the lock failed");
1585+
return UMF_RESULT_ERROR_UNKNOWN;
1586+
}
1587+
1588+
return UMF_RESULT_SUCCESS;
1589+
1590+
err_mutex_unlock:
1591+
assert(debug_check(coarse_provider));
1592+
utils_mutex_unlock(&coarse_provider->lock);
1593+
return umf_result;
1594+
}
1595+
1596+
static umf_result_t coarse_memory_provider_get_ipc_handle_size(void *provider,
1597+
size_t *size) {
1598+
if (provider == NULL || size == NULL) {
1599+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1600+
}
1601+
1602+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1603+
}
1604+
1605+
static umf_result_t
1606+
coarse_memory_provider_get_ipc_handle(void *provider, const void *ptr,
1607+
size_t size, void *providerIpcData) {
1608+
if (provider == NULL || ptr == NULL || providerIpcData == NULL) {
1609+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1610+
}
1611+
1612+
(void)size; // unused
1613+
1614+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1615+
}
1616+
1617+
static umf_result_t
1618+
coarse_memory_provider_put_ipc_handle(void *provider, void *providerIpcData) {
1619+
if (provider == NULL || providerIpcData == NULL) {
1620+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1621+
}
1622+
1623+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1624+
}
1625+
1626+
static umf_result_t
1627+
coarse_memory_provider_open_ipc_handle(void *provider, void *providerIpcData,
1628+
void **ptr) {
1629+
if (provider == NULL || providerIpcData == NULL || ptr == NULL) {
1630+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1631+
}
1632+
1633+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1634+
}
1635+
1636+
static umf_result_t coarse_memory_provider_close_ipc_handle(void *provider,
1637+
void *ptr,
1638+
size_t size) {
1639+
if (provider == NULL || ptr == NULL) {
1640+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1641+
}
1642+
1643+
(void)size; // unused
1644+
1645+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1646+
}
1647+
13931648
umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = {
13941649
.version = UMF_VERSION_CURRENT,
13951650
.initialize = coarse_memory_provider_initialize,
@@ -1401,8 +1656,6 @@ umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = {
14011656
coarse_memory_provider_get_recommended_page_size,
14021657
.get_min_page_size = coarse_memory_provider_get_min_page_size,
14031658
.get_name = coarse_memory_provider_get_name,
1404-
// TODO
1405-
/*
14061659
.ext.purge_lazy = coarse_memory_provider_purge_lazy,
14071660
.ext.purge_force = coarse_memory_provider_purge_force,
14081661
.ext.allocation_merge = coarse_memory_provider_allocation_merge,
@@ -1412,7 +1665,6 @@ umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = {
14121665
.ipc.put_ipc_handle = coarse_memory_provider_put_ipc_handle,
14131666
.ipc.open_ipc_handle = coarse_memory_provider_open_ipc_handle,
14141667
.ipc.close_ipc_handle = coarse_memory_provider_close_ipc_handle,
1415-
*/
14161668
};
14171669

14181670
umf_memory_provider_ops_t *umfCoarseMemoryProviderOps(void) {

test/disjointCoarseMallocPool.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,3 +701,95 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_wrong_params_4) {
701701

702702
umfMemoryProviderDestroy(malloc_memory_provider);
703703
}
704+
705+
TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_split_merge) {
706+
umf_memory_provider_handle_t malloc_memory_provider;
707+
umf_result_t umf_result;
708+
709+
umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL,
710+
&malloc_memory_provider);
711+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
712+
ASSERT_NE(malloc_memory_provider, nullptr);
713+
714+
const size_t init_buffer_size = 20 * MB;
715+
716+
coarse_memory_provider_params_t coarse_memory_provider_params;
717+
// make sure there are no undefined members - prevent a UB
718+
memset(&coarse_memory_provider_params, 0,
719+
sizeof(coarse_memory_provider_params));
720+
coarse_memory_provider_params.upstream_memory_provider =
721+
malloc_memory_provider;
722+
coarse_memory_provider_params.immediate_init_from_upstream = true;
723+
coarse_memory_provider_params.init_buffer = NULL;
724+
coarse_memory_provider_params.init_buffer_size = init_buffer_size;
725+
726+
umf_memory_provider_handle_t coarse_memory_provider;
727+
umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(),
728+
&coarse_memory_provider_params,
729+
&coarse_memory_provider);
730+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
731+
ASSERT_NE(coarse_memory_provider, nullptr);
732+
733+
umf_memory_provider_handle_t cp = coarse_memory_provider;
734+
char *ptr = nullptr;
735+
736+
ASSERT_EQ(GetStats(cp).used_size, 0 * MB);
737+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
738+
ASSERT_EQ(GetStats(cp).num_all_blocks, 1);
739+
740+
/* test umfMemoryProviderAllocationSplit */
741+
umf_result = umfMemoryProviderAlloc(cp, 2 * MB, 0, (void **)&ptr);
742+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
743+
ASSERT_NE(ptr, nullptr);
744+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
745+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
746+
ASSERT_EQ(GetStats(cp).num_all_blocks, 2);
747+
748+
umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 2 * MB, 1 * MB);
749+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
750+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
751+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
752+
ASSERT_EQ(GetStats(cp).num_all_blocks, 3);
753+
754+
umf_result = umfMemoryProviderFree(cp, (ptr + 1 * MB), 1 * MB);
755+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
756+
ASSERT_EQ(GetStats(cp).used_size, 1 * MB);
757+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
758+
ASSERT_EQ(GetStats(cp).num_all_blocks, 2);
759+
760+
umf_result = umfMemoryProviderFree(cp, ptr, 1 * MB);
761+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
762+
ASSERT_EQ(GetStats(cp).used_size, 0);
763+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
764+
ASSERT_EQ(GetStats(cp).num_all_blocks, 1);
765+
766+
/* test umfMemoryProviderAllocationMerge */
767+
umf_result = umfMemoryProviderAlloc(cp, 2 * MB, 0, (void **)&ptr);
768+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
769+
ASSERT_NE(ptr, nullptr);
770+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
771+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
772+
ASSERT_EQ(GetStats(cp).num_all_blocks, 2);
773+
774+
umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 2 * MB, 1 * MB);
775+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
776+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
777+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
778+
ASSERT_EQ(GetStats(cp).num_all_blocks, 3);
779+
780+
umf_result =
781+
umfMemoryProviderAllocationMerge(cp, ptr, (ptr + 1 * MB), 2 * MB);
782+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
783+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
784+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
785+
ASSERT_EQ(GetStats(cp).num_all_blocks, 2);
786+
787+
umf_result = umfMemoryProviderFree(cp, ptr, 2 * MB);
788+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
789+
ASSERT_EQ(GetStats(cp).used_size, 0);
790+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
791+
ASSERT_EQ(GetStats(cp).num_all_blocks, 1);
792+
793+
umfMemoryProviderDestroy(coarse_memory_provider);
794+
umfMemoryProviderDestroy(malloc_memory_provider);
795+
}

0 commit comments

Comments
 (0)