Skip to content

Commit 353f9bc

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

File tree

2 files changed

+346
-3
lines changed

2 files changed

+346
-3
lines changed

src/provider/provider_coarse.c

Lines changed: 254 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,260 @@ coarse_memory_provider_get_stats(void *provider,
15441544
return UMF_RESULT_SUCCESS;
15451545
}
15461546

1547+
static umf_result_t coarse_memory_provider_purge_lazy(void *provider, void *ptr,
1548+
size_t size) {
1549+
if (provider == NULL || ptr == NULL) {
1550+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1551+
}
1552+
1553+
coarse_memory_provider_t *coarse_provider =
1554+
(struct coarse_memory_provider_t *)provider;
1555+
if (coarse_provider->upstream_memory_provider == NULL) {
1556+
LOG_ERR("no upstream memory provider given");
1557+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1558+
}
1559+
1560+
return umfMemoryProviderPurgeLazy(coarse_provider->upstream_memory_provider,
1561+
ptr, size);
1562+
}
1563+
1564+
static umf_result_t coarse_memory_provider_purge_force(void *provider,
1565+
void *ptr, size_t size) {
1566+
if (provider == NULL || ptr == NULL) {
1567+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1568+
}
1569+
1570+
coarse_memory_provider_t *coarse_provider =
1571+
(struct coarse_memory_provider_t *)provider;
1572+
if (coarse_provider->upstream_memory_provider == NULL) {
1573+
LOG_ERR("no upstream memory provider given");
1574+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1575+
}
1576+
1577+
return umfMemoryProviderPurgeForce(
1578+
coarse_provider->upstream_memory_provider, ptr, size);
1579+
}
1580+
1581+
static umf_result_t coarse_memory_provider_allocation_split(void *provider,
1582+
void *ptr,
1583+
size_t totalSize,
1584+
size_t firstSize) {
1585+
if (provider == NULL || ptr == NULL || (firstSize >= totalSize) ||
1586+
firstSize == 0) {
1587+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1588+
}
1589+
1590+
umf_result_t umf_result;
1591+
1592+
coarse_memory_provider_t *coarse_provider =
1593+
(struct coarse_memory_provider_t *)provider;
1594+
1595+
if (utils_mutex_lock(&coarse_provider->lock) != 0) {
1596+
LOG_ERR("lockng the lock failed");
1597+
return UMF_RESULT_ERROR_UNKNOWN;
1598+
}
1599+
1600+
assert(debug_check(coarse_provider));
1601+
1602+
block_t *block = coarse_ravl_find(coarse_provider->all_blocks, ptr);
1603+
if (block == NULL) {
1604+
LOG_ERR("memory block not found");
1605+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1606+
goto err_mutex_unlock;
1607+
}
1608+
1609+
if (block->size != totalSize) {
1610+
LOG_ERR("wrong totalSize");
1611+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1612+
goto err_mutex_unlock;
1613+
}
1614+
1615+
if (!block->used) {
1616+
LOG_ERR("block is not allocated");
1617+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1618+
goto err_mutex_unlock;
1619+
}
1620+
1621+
block_t *new_block =
1622+
coarse_ravl_add_new(coarse_provider->all_blocks,
1623+
block->data + firstSize, block->size - firstSize);
1624+
if (new_block == NULL) {
1625+
umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
1626+
goto err_mutex_unlock;
1627+
}
1628+
1629+
block->size = firstSize;
1630+
new_block->used = true;
1631+
1632+
assert(new_block->size == (totalSize - firstSize));
1633+
1634+
assert(debug_check(coarse_provider));
1635+
1636+
if (utils_mutex_unlock(&coarse_provider->lock) != 0) {
1637+
LOG_ERR("unlockng the lock failed");
1638+
return UMF_RESULT_ERROR_UNKNOWN;
1639+
}
1640+
1641+
return UMF_RESULT_SUCCESS;
1642+
1643+
err_mutex_unlock:
1644+
assert(debug_check(coarse_provider));
1645+
utils_mutex_unlock(&coarse_provider->lock);
1646+
return umf_result;
1647+
}
1648+
1649+
static umf_result_t coarse_memory_provider_allocation_merge(void *provider,
1650+
void *lowPtr,
1651+
void *highPtr,
1652+
size_t totalSize) {
1653+
if (provider == NULL || lowPtr == NULL || highPtr == NULL ||
1654+
((uintptr_t)highPtr <= (uintptr_t)lowPtr) ||
1655+
((uintptr_t)highPtr - (uintptr_t)lowPtr >= totalSize)) {
1656+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1657+
}
1658+
1659+
umf_result_t umf_result;
1660+
1661+
coarse_memory_provider_t *coarse_provider =
1662+
(struct coarse_memory_provider_t *)provider;
1663+
1664+
if (utils_mutex_lock(&coarse_provider->lock) != 0) {
1665+
LOG_ERR("lockng the lock failed");
1666+
return UMF_RESULT_ERROR_UNKNOWN;
1667+
}
1668+
1669+
assert(debug_check(coarse_provider));
1670+
1671+
block_t *low_block = coarse_ravl_find(coarse_provider->all_blocks, lowPtr);
1672+
if (low_block == NULL) {
1673+
LOG_ERR("the lowPtr memory block not found");
1674+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1675+
goto err_mutex_unlock;
1676+
}
1677+
1678+
if (!low_block->used) {
1679+
LOG_ERR("the lowPtr block is not allocated");
1680+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1681+
goto err_mutex_unlock;
1682+
}
1683+
1684+
block_t *high_block =
1685+
coarse_ravl_find(coarse_provider->all_blocks, highPtr);
1686+
if (high_block == NULL) {
1687+
LOG_ERR("the highPtr memory block not found");
1688+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1689+
goto err_mutex_unlock;
1690+
}
1691+
1692+
if (!high_block->used) {
1693+
LOG_ERR("the highPtr block is not allocated");
1694+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1695+
goto err_mutex_unlock;
1696+
}
1697+
1698+
if (low_block->size + high_block->size != totalSize) {
1699+
LOG_ERR("wrong totalSize");
1700+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1701+
goto err_mutex_unlock;
1702+
}
1703+
1704+
if ((uintptr_t)highPtr != ((uintptr_t)lowPtr + low_block->size)) {
1705+
LOG_ERR("given pointers cannot be merged");
1706+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1707+
goto err_mutex_unlock;
1708+
}
1709+
1710+
if (get_block_next(coarse_provider->all_blocks, low_block) != high_block) {
1711+
LOG_ERR("given pointers cannot be merged");
1712+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1713+
goto err_mutex_unlock;
1714+
}
1715+
1716+
if (get_block_prev(coarse_provider->all_blocks, high_block) != low_block) {
1717+
LOG_ERR("given pointers cannot be merged");
1718+
umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT;
1719+
goto err_mutex_unlock;
1720+
}
1721+
1722+
block_t *merged_block = NULL;
1723+
1724+
umf_result =
1725+
block_merge_with_prev(coarse_provider, high_block, true, &merged_block);
1726+
if (umf_result != UMF_RESULT_SUCCESS) {
1727+
LOG_ERR("merging failed");
1728+
goto err_mutex_unlock;
1729+
}
1730+
1731+
assert(merged_block == low_block);
1732+
assert(low_block->size == totalSize);
1733+
1734+
assert(debug_check(coarse_provider));
1735+
1736+
if (utils_mutex_unlock(&coarse_provider->lock) != 0) {
1737+
LOG_ERR("unlockng the lock failed");
1738+
return UMF_RESULT_ERROR_UNKNOWN;
1739+
}
1740+
1741+
return UMF_RESULT_SUCCESS;
1742+
1743+
err_mutex_unlock:
1744+
assert(debug_check(coarse_provider));
1745+
utils_mutex_unlock(&coarse_provider->lock);
1746+
return umf_result;
1747+
}
1748+
1749+
static umf_result_t coarse_memory_provider_get_ipc_handle_size(void *provider,
1750+
size_t *size) {
1751+
if (provider == NULL || size == NULL) {
1752+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1753+
}
1754+
1755+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1756+
}
1757+
1758+
static umf_result_t
1759+
coarse_memory_provider_get_ipc_handle(void *provider, const void *ptr,
1760+
size_t size, void *providerIpcData) {
1761+
if (provider == NULL || ptr == NULL || providerIpcData == NULL) {
1762+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1763+
}
1764+
1765+
(void)size; // unused
1766+
1767+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1768+
}
1769+
1770+
static umf_result_t
1771+
coarse_memory_provider_put_ipc_handle(void *provider, void *providerIpcData) {
1772+
if (provider == NULL || providerIpcData == NULL) {
1773+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1774+
}
1775+
1776+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1777+
}
1778+
1779+
static umf_result_t
1780+
coarse_memory_provider_open_ipc_handle(void *provider, void *providerIpcData,
1781+
void **ptr) {
1782+
if (provider == NULL || providerIpcData == NULL || ptr == NULL) {
1783+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1784+
}
1785+
1786+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1787+
}
1788+
1789+
static umf_result_t coarse_memory_provider_close_ipc_handle(void *provider,
1790+
void *ptr,
1791+
size_t size) {
1792+
if (provider == NULL || ptr == NULL) {
1793+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
1794+
}
1795+
1796+
(void)size; // unused
1797+
1798+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
1799+
}
1800+
15471801
umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = {
15481802
.version = UMF_VERSION_CURRENT,
15491803
.initialize = coarse_memory_provider_initialize,
@@ -1555,8 +1809,6 @@ umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = {
15551809
coarse_memory_provider_get_recommended_page_size,
15561810
.get_min_page_size = coarse_memory_provider_get_min_page_size,
15571811
.get_name = coarse_memory_provider_get_name,
1558-
// TODO
1559-
/*
15601812
.ext.purge_lazy = coarse_memory_provider_purge_lazy,
15611813
.ext.purge_force = coarse_memory_provider_purge_force,
15621814
.ext.allocation_merge = coarse_memory_provider_allocation_merge,
@@ -1566,7 +1818,6 @@ umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = {
15661818
.ipc.put_ipc_handle = coarse_memory_provider_put_ipc_handle,
15671819
.ipc.open_ipc_handle = coarse_memory_provider_open_ipc_handle,
15681820
.ipc.close_ipc_handle = coarse_memory_provider_close_ipc_handle,
1569-
*/
15701821
};
15711822

15721823
umf_memory_provider_ops_t *umfCoarseMemoryProviderOps(void) {

test/disjointCoarseMallocPool.cpp

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

760760
umfMemoryProviderDestroy(malloc_memory_provider);
761761
}
762+
763+
TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_split_merge) {
764+
umf_memory_provider_handle_t malloc_memory_provider;
765+
umf_result_t umf_result;
766+
767+
umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL,
768+
&malloc_memory_provider);
769+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
770+
ASSERT_NE(malloc_memory_provider, nullptr);
771+
772+
const size_t init_buffer_size = 20 * MB;
773+
774+
coarse_memory_provider_params_t coarse_memory_provider_params;
775+
// make sure there are no undefined members - prevent a UB
776+
memset(&coarse_memory_provider_params, 0,
777+
sizeof(coarse_memory_provider_params));
778+
coarse_memory_provider_params.upstream_memory_provider =
779+
malloc_memory_provider;
780+
coarse_memory_provider_params.immediate_init_from_upstream = true;
781+
coarse_memory_provider_params.init_buffer = NULL;
782+
coarse_memory_provider_params.init_buffer_size = init_buffer_size;
783+
784+
umf_memory_provider_handle_t coarse_memory_provider;
785+
umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(),
786+
&coarse_memory_provider_params,
787+
&coarse_memory_provider);
788+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
789+
ASSERT_NE(coarse_memory_provider, nullptr);
790+
791+
umf_memory_provider_handle_t cp = coarse_memory_provider;
792+
char *ptr = nullptr;
793+
794+
ASSERT_EQ(GetStats(cp).used_size, 0 * MB);
795+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
796+
ASSERT_EQ(GetStats(cp).num_all_blocks, 1);
797+
798+
/* test umfMemoryProviderAllocationSplit */
799+
umf_result = umfMemoryProviderAlloc(cp, 2 * MB, 0, (void **)&ptr);
800+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
801+
ASSERT_NE(ptr, nullptr);
802+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
803+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
804+
ASSERT_EQ(GetStats(cp).num_all_blocks, 2);
805+
806+
umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 2 * MB, 1 * MB);
807+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
808+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
809+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
810+
ASSERT_EQ(GetStats(cp).num_all_blocks, 3);
811+
812+
umf_result = umfMemoryProviderFree(cp, (ptr + 1 * MB), 1 * MB);
813+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
814+
ASSERT_EQ(GetStats(cp).used_size, 1 * MB);
815+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
816+
ASSERT_EQ(GetStats(cp).num_all_blocks, 2);
817+
818+
umf_result = umfMemoryProviderFree(cp, ptr, 1 * MB);
819+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
820+
ASSERT_EQ(GetStats(cp).used_size, 0);
821+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
822+
ASSERT_EQ(GetStats(cp).num_all_blocks, 1);
823+
824+
/* test umfMemoryProviderAllocationMerge */
825+
umf_result = umfMemoryProviderAlloc(cp, 2 * MB, 0, (void **)&ptr);
826+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
827+
ASSERT_NE(ptr, nullptr);
828+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
829+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
830+
ASSERT_EQ(GetStats(cp).num_all_blocks, 2);
831+
832+
umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 2 * MB, 1 * MB);
833+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
834+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
835+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
836+
ASSERT_EQ(GetStats(cp).num_all_blocks, 3);
837+
838+
umf_result =
839+
umfMemoryProviderAllocationMerge(cp, ptr, (ptr + 1 * MB), 2 * MB);
840+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
841+
ASSERT_EQ(GetStats(cp).used_size, 2 * MB);
842+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
843+
ASSERT_EQ(GetStats(cp).num_all_blocks, 2);
844+
845+
umf_result = umfMemoryProviderFree(cp, ptr, 2 * MB);
846+
ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
847+
ASSERT_EQ(GetStats(cp).used_size, 0);
848+
ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size);
849+
ASSERT_EQ(GetStats(cp).num_all_blocks, 1);
850+
851+
umfMemoryProviderDestroy(coarse_memory_provider);
852+
umfMemoryProviderDestroy(malloc_memory_provider);
853+
}

0 commit comments

Comments
 (0)