diff --git a/.github/workflows/reusable_compatibility.yml b/.github/workflows/reusable_compatibility.yml index 5503a8110..98eb223bb 100644 --- a/.github/workflows/reusable_compatibility.yml +++ b/.github/workflows/reusable_compatibility.yml @@ -95,10 +95,21 @@ jobs: - name: Run "tag" UMF tests with latest UMF libs (warnings enabled) working-directory: ${{github.workspace}}/tag_version/build + # Exclude the test_jemalloc_pool test - + # TODO: add fix for that in v1.0.1 run: > UMF_LOG="level:warning;flush:debug;output:stderr;pid:no" LD_LIBRARY_PATH=${{github.workspace}}/latest_version/build/lib/ - ctest --verbose + ctest --verbose -E test_jemalloc_pool + + - name: Run EXCLUDED tests with filters + working-directory: ${{github.workspace}}/tag_version/build + # Exclude the jemallocPoolName test case of the test_jemalloc_pool test + # TODO: add fix for that in v1.0.1 + run: > + UMF_LOG="level:warning;flush:debug;output:stderr;pid:no" + LD_LIBRARY_PATH=${{github.workspace}}/latest_version/build/lib/ + ./test/test_jemalloc_pool --gtest_filter="-*jemallocPoolName*" # Browse all folders in the examples directory, build them using the # latest UMF version, and run them, excluding those in the exclude list. @@ -220,10 +231,22 @@ jobs: - name: Run "tag" UMF tests with latest UMF libs (warnings enabled) working-directory: ${{github.workspace}}/tag_version/build + # Exclude the test_jemalloc_pool test - + # TODO: add fix for that in v1.0.1 run: | - $env:UMF_LOG="level:warning;flush:debug;output:stderr;pid:no" + $env:UMF_LOG="level:warning;flush:debug;output:stderr;pid:no" cp ${{github.workspace}}/latest_version/build/bin/Debug/umf.dll ${{github.workspace}}/tag_version/build/bin/Debug/umf.dll - ctest -C Debug --verbose + ctest -C Debug --verbose -E test_jemalloc_pool + + - name: Run EXCLUDED tests with filters + working-directory: ${{github.workspace}}/tag_version/build/ + # Exclude the jemallocPoolName test case of the test_jemalloc_pool test + # TODO: add fix for that in v1.0.1 + run: | + $env:UMF_LOG="level:warning;flush:debug;output:stderr;pid:no" + $env:Path = "${{github.workspace}}/tag_version/build/bin/Debug;${{env.VCPKG_BIN_PATH}};$env:Path" + cp ${{github.workspace}}/latest_version/build/bin/Debug/umf.dll ${{github.workspace}}/tag_version/build/bin/Debug/umf.dll + test/Debug/test_jemalloc_pool.exe --gtest_filter="-*jemallocPoolName*" # Browse all folders in the examples directory, build them using the # latest UMF version, and run them, excluding those in the exclude list. @@ -361,10 +384,21 @@ jobs: - name: Run "tag" UMF tests with latest UMF libs (warnings enabled) working-directory: ${{github.workspace}}/tag_version/build + # Exclude the test_jemalloc_pool test - + # TODO: add fix for that in v1.0.1 + run: > + UMF_LOG="level:warning;flush:debug;output:stderr;pid:no" + LD_LIBRARY_PATH=${{github.workspace}}/latest_version/build/lib/ + ctest --verbose -E test_jemalloc_pool + + - name: Run EXCLUDED tests with filters + working-directory: ${{github.workspace}}/tag_version/build + # Exclude the jemallocPoolName test case of the test_jemalloc_pool test + # TODO: add fix for that in v1.0.1 run: > UMF_LOG="level:warning;flush:debug;output:stderr;pid:no" LD_LIBRARY_PATH=${{github.workspace}}/latest_version/build/lib/ - ctest --verbose + ./test/test_jemalloc_pool --gtest_filter="-*jemallocPoolName*" # Browse all folders in the examples directory, build them using the # latest UMF version, and run them, excluding those in the exclude list. diff --git a/src/pool/pool_jemalloc.c b/src/pool/pool_jemalloc.c index abbf50d2b..343b30a28 100644 --- a/src/pool/pool_jemalloc.c +++ b/src/pool/pool_jemalloc.c @@ -12,6 +12,8 @@ #include #include "base_alloc_global.h" +#include "memory_provider_internal.h" +#include "provider_tracking.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" @@ -272,8 +274,15 @@ static bool arena_extent_split(extent_hooks_t *extent_hooks, void *addr, jemalloc_memory_pool_t *pool = get_pool_by_arena_index(arena_ind); assert(pool); - return umfMemoryProviderAllocationSplit(pool->provider, addr, size, - size_a) != UMF_RESULT_SUCCESS; + + umf_result_t ret = + umfMemoryProviderAllocationSplit(pool->provider, addr, size, size_a); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("memory provider failed to split a memory region, while " + "jemalloc requires that"); + } + + return ret != UMF_RESULT_SUCCESS; } // arena_extent_merge - an extent merge function conforms to the extent_merge_t type and optionally @@ -424,11 +433,45 @@ static void *op_aligned_alloc(void *pool, size_t size, size_t alignment) { return ptr; } +// Verify if the memory provider supports the split() operation, +// because jemalloc pool requires that. +static umf_result_t verify_split(umf_memory_provider_handle_t provider) { + // Retrieve the upstream memory provider + umf_memory_provider_handle_t upstream_provider = NULL; + umfTrackingMemoryProviderGetUpstreamProvider( + umfMemoryProviderGetPriv(provider), &upstream_provider); + + size_t page_size = 0; + umf_result_t ret = + umfMemoryProviderGetMinPageSize(upstream_provider, NULL, &page_size); + if (ret != UMF_RESULT_SUCCESS) { + return ret; + } + + size_t size = 2 * page_size; // use double the page size for the split test + if (UMF_RESULT_ERROR_NOT_SUPPORTED == + umfMemoryProviderAllocationSplit(upstream_provider, (void *)size, size, + page_size)) { + LOG_ERR("memory provider does not support the split operation, while " + "jemalloc pool requires that"); + return UMF_RESULT_ERROR_NOT_SUPPORTED; + } + + return UMF_RESULT_SUCCESS; +} + static umf_result_t op_initialize(umf_memory_provider_handle_t provider, const void *params, void **out_pool) { assert(provider); assert(out_pool); + // Verify if the memory provider supports the split() operation, + // because jemalloc pool requires that. + umf_result_t ret = verify_split(provider); + if (ret != UMF_RESULT_SUCCESS) { + return ret; + } + extent_hooks_t *pHooks = &arena_extent_hooks; size_t unsigned_size = sizeof(unsigned); int n_arenas_set_from_params = 0; diff --git a/test/common/provider.hpp b/test/common/provider.hpp index 6d42c59f2..e52dd614a 100644 --- a/test/common/provider.hpp +++ b/test/common/provider.hpp @@ -36,23 +36,23 @@ auto wrapProviderUnique(umf_memory_provider_handle_t hProvider) { typedef struct provider_base_t { umf_result_t initialize() noexcept { return UMF_RESULT_SUCCESS; }; umf_result_t alloc(size_t, size_t, void **) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t free([[maybe_unused]] void *ptr, [[maybe_unused]] size_t size) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t get_last_native_error(const char **, int32_t *) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t get_recommended_page_size([[maybe_unused]] size_t size, [[maybe_unused]] size_t *pageSize) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t get_min_page_size([[maybe_unused]] const void *ptr, [[maybe_unused]] size_t *pageSize) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t get_name(const char **name) noexcept { *name = "base"; @@ -60,45 +60,45 @@ typedef struct provider_base_t { } umf_result_t ext_purge_lazy([[maybe_unused]] void *ptr, [[maybe_unused]] size_t size) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t ext_purge_force([[maybe_unused]] void *ptr, [[maybe_unused]] size_t size) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t ext_allocation_merge([[maybe_unused]] void *lowPtr, [[maybe_unused]] void *highPtr, [[maybe_unused]] size_t totalSize) { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t ext_allocation_split([[maybe_unused]] void *ptr, [[maybe_unused]] size_t totalSize, [[maybe_unused]] size_t firstSize) { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t ext_get_ipc_handle_size([[maybe_unused]] size_t *size) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t ext_get_ipc_handle([[maybe_unused]] const void *ptr, [[maybe_unused]] size_t size, [[maybe_unused]] void *providerIpcData) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t ext_put_ipc_handle([[maybe_unused]] void *providerIpcData) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t ext_open_ipc_handle([[maybe_unused]] void *providerIpcData, [[maybe_unused]] void **ptr) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } umf_result_t ext_close_ipc_handle([[maybe_unused]] void *ptr, [[maybe_unused]] size_t size) noexcept { - return UMF_RESULT_ERROR_UNKNOWN; + return UMF_RESULT_ERROR_NOT_SUPPORTED; } virtual ~provider_base_t() = default; } provider_base_t; diff --git a/test/pools/jemalloc_pool.cpp b/test/pools/jemalloc_pool.cpp index 97a2128f7..906aba763 100644 --- a/test/pools/jemalloc_pool.cpp +++ b/test/pools/jemalloc_pool.cpp @@ -192,18 +192,10 @@ TEST_F(test, jemallocPoolName) { umf_jemalloc_pool_params_handle_t params = nullptr; umf_result_t res = umfJemallocPoolParamsCreate(¶ms); EXPECT_EQ(res, UMF_RESULT_SUCCESS); - umf_memory_provider_handle_t provider_handle = nullptr; umf_memory_pool_handle_t pool = NULL; - struct memory_provider : public umf_test::provider_base_t {}; - umf_memory_provider_ops_t provider_ops = - umf_test::providerMakeCOps(); - auto providerUnique = - wrapProviderUnique(createProviderChecked(&provider_ops, nullptr)); - provider_handle = providerUnique.get(); - - res = - umfPoolCreate(umfJemallocPoolOps(), provider_handle, params, 0, &pool); + auto nullProvider = nullProviderCreate(); + res = umfPoolCreate(umfJemallocPoolOps(), nullProvider, params, 0, &pool); EXPECT_EQ(res, UMF_RESULT_SUCCESS); const char *name = nullptr; res = umfPoolGetName(pool, &name); @@ -211,5 +203,25 @@ TEST_F(test, jemallocPoolName) { EXPECT_STREQ(name, "jemalloc"); umfPoolDestroy(pool); + umfMemoryProviderDestroy(nullProvider); + umfJemallocPoolParamsDestroy(params); +} + +TEST_F(test, jemallocProviderDoesNotSupportSplit) { + umf_jemalloc_pool_params_handle_t params = nullptr; + umf_result_t res = umfJemallocPoolParamsCreate(¶ms); + EXPECT_EQ(res, UMF_RESULT_SUCCESS); + + umf_memory_provider_handle_t ba_provider; + umf_result_t ret = + umfMemoryProviderCreate(&BA_GLOBAL_PROVIDER_OPS, nullptr, &ba_provider); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + umf_memory_pool_handle_t pool = nullptr; + res = umfPoolCreate(umfJemallocPoolOps(), ba_provider, params, 0, &pool); + EXPECT_EQ(res, UMF_RESULT_ERROR_NOT_SUPPORTED); + EXPECT_EQ(pool, nullptr); + + umfMemoryProviderDestroy(ba_provider); umfJemallocPoolParamsDestroy(params); }