From bf8dea758ca81c4e711de69f299099b413455675 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Wed, 29 Jan 2025 12:16:45 +0000 Subject: [PATCH] todo --- .github/workflows/pr_push.yml | 78 +--------- .github/workflows/reusable_compatibility.yml | 135 ++++++++++++++++++ .../custom_file_provider.c | 2 +- include/umf/memory_pool_ops.h | 7 +- include/umf/memory_provider_ops.h | 22 ++- .../umf/providers/provider_devdax_memory.h | 1 + include/umf/providers/provider_file_memory.h | 1 + src/CMakeLists.txt | 1 + src/cpp_helpers.hpp | 4 +- src/libumf.def | 8 +- src/libumf.map | 8 +- src/memory_pool.c | 6 +- src/memory_provider.c | 64 ++++++++- src/memtarget.c | 7 +- src/memtarget_ops.h | 5 + src/memtargets/memtarget_numa.c | 2 +- src/pool/pool_jemalloc.c | 2 +- src/pool/pool_proxy.c | 2 +- src/pool/pool_scalable.c | 2 +- src/provider/provider_cuda.c | 4 +- src/provider/provider_deprecated.c | 101 +++++++++++++ src/provider/provider_deprecated.h | 63 ++++++++ src/provider/provider_devdax_memory.c | 11 +- src/provider/provider_file_memory.c | 11 +- src/provider/provider_fixed_memory.c | 2 +- src/provider/provider_level_zero.c | 4 +- src/provider/provider_os_memory.c | 2 +- src/provider/provider_tracking.c | 2 +- test/common/pool_null.c | 2 +- test/common/pool_trace.c | 2 +- test/common/provider_null.c | 2 +- test/common/provider_trace.c | 2 +- test/test_init_teardown.c | 41 ++++++ 33 files changed, 486 insertions(+), 120 deletions(-) create mode 100644 .github/workflows/reusable_compatibility.yml create mode 100644 src/provider/provider_deprecated.c create mode 100644 src/provider/provider_deprecated.h diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 9623b69f1..d250c16cf 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -16,75 +16,11 @@ permissions: contents: read jobs: - CodeChecks: - uses: ./.github/workflows/reusable_checks.yml - DocsBuild: - uses: ./.github/workflows/reusable_docs_build.yml - FastBuild: - name: Fast builds - needs: [CodeChecks, DocsBuild] - uses: ./.github/workflows/reusable_fast.yml - Build: - name: Basic builds - needs: [FastBuild] - uses: ./.github/workflows/reusable_basic.yml - DevDax: - needs: [FastBuild] - uses: ./.github/workflows/reusable_dax.yml - MultiNuma: - needs: [FastBuild] - uses: ./.github/workflows/reusable_multi_numa.yml - L0: - needs: [Build] - uses: ./.github/workflows/reusable_gpu.yml + Compatibility: + name: Compatibility + uses: ./.github/workflows/reusable_compatibility.yml + strategy: + matrix: + tag: ["v0.10.1"] with: - name: "LEVEL_ZERO" - shared_lib: "['ON']" - CUDA: - needs: [Build] - uses: ./.github/workflows/reusable_gpu.yml - with: - name: "CUDA" - shared_lib: "['ON']" - Sanitizers: - needs: [FastBuild] - uses: ./.github/workflows/reusable_sanitizers.yml - QEMU: - needs: [FastBuild] - uses: ./.github/workflows/reusable_qemu.yml - with: - short_run: true - Benchmarks: - needs: [Build] - uses: ./.github/workflows/reusable_benchmarks.yml - ProxyLib: - needs: [Build] - uses: ./.github/workflows/reusable_proxy_lib.yml - Valgrind: - needs: [Build] - uses: ./.github/workflows/reusable_valgrind.yml - Coverage: - # total coverage (on upstream only) - if: github.repository == 'oneapi-src/unified-memory-framework' - needs: [Build, DevDax, L0, CUDA, MultiNuma, QEMU, ProxyLib] - uses: ./.github/workflows/reusable_coverage.yml - secrets: inherit - with: - trigger: "${{github.event_name}}" - Coverage_partial: - # partial coverage (on forks) - if: github.repository != 'oneapi-src/unified-memory-framework' - needs: [Build, QEMU, ProxyLib] - uses: ./.github/workflows/reusable_coverage.yml - CodeQL: - needs: [Build] - permissions: - contents: read - security-events: write - uses: ./.github/workflows/reusable_codeql.yml - Trivy: - needs: [Build] - permissions: - contents: read - security-events: write - uses: ./.github/workflows/reusable_trivy.yml + tag: ${{ matrix.tag }} diff --git a/.github/workflows/reusable_compatibility.yml b/.github/workflows/reusable_compatibility.yml new file mode 100644 index 000000000..17386a632 --- /dev/null +++ b/.github/workflows/reusable_compatibility.yml @@ -0,0 +1,135 @@ +# TODO +name: Compatibility + +on: + workflow_call: + inputs: + tag: + description: Check backward compatibility with this tag + type: string + default: "0.10.1" + +permissions: + contents: read + +jobs: + ubuntu-build: + name: Ubuntu + strategy: + matrix: + # TODO other systems? + os: ['ubuntu-22.04'] + build_type: [Debug] + compiler: [{c: gcc, cxx: g++}] + shared_library: ['ON'] + level_zero_provider: ['ON'] + cuda_provider: ['ON'] + install_tbb: ['ON'] + runs-on: ${{matrix.os}} + + steps: + # NOTE: we need jemalloc for older version of UMF + - name: Install apt packages + run: | + sudo apt-get update + sudo apt-get install -y clang cmake libnuma-dev libjemalloc-dev + + - name: Install TBB apt package + if: matrix.install_tbb == 'ON' + run: | + sudo apt-get install -y libtbb-dev + + - name: Checkout "tag" UMF version + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + ref: refs/tags/${{inputs.tag}} + path: ${{github.workspace}}/tag_version + + - name: Install libhwloc + working-directory: ${{github.workspace}}/tag_version + run: .github/scripts/install_hwloc.sh + + - name: Get "tag" UMF version + working-directory: ${{github.workspace}}/tag_version + run: | + VERSION=$(git describe --tags --abbrev=0 | grep -oP '\d+\.\d+\.\d+') + echo "tag version: $VERSION" + + - name: Configure "tag" UMF build + working-directory: ${{github.workspace}}/tag_version + run: > + cmake + -B ${{github.workspace}}/tag_version/build + -DCMAKE_INSTALL_PREFIX="${{github.workspace}}/tag_version/build/install" + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} + -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} + -DCMAKE_C_COMPILER=${{matrix.compiler.c}} + -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=${{matrix.level_zero_provider}} + -DUMF_BUILD_CUDA_PROVIDER=${{matrix.cuda_provider}} + -DUMF_FORMAT_CODE_STYLE=OFF + -DUMF_DEVELOPER_MODE=ON + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON + -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON + -DUMF_TESTS_FAIL_ON_SKIP=ON + + - name: Build "tag" UMF + working-directory: ${{github.workspace}}/tag_version + run: | + cmake --build ${{github.workspace}}/tag_version/build -j $(nproc) + + # NOTE: we need jemalloc for older version of UMF + # if: startsWith(github.event.inputs.tag, '0.10.') || startsWith(github.event.inputs.tag, '0.9.') + - name: Set ptrace value for IPC test + run: sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" + + - name: Run "tag" UMF tests + working-directory: ${{github.workspace}}/tag_version/build + run: | + LD_LIBRARY_PATH=${{github.workspace}}/tag_version/build/lib/ ctest --output-on-failure + + - name: Checkout latest UMF version + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + path: ${{github.workspace}}/latest_version + + - name: Get latest UMF version + working-directory: ${{github.workspace}}/latest_version + run: | + VERSION=$(git describe --tags --abbrev=0 | grep -oP '\d+\.\d+\.\d+') + echo "checked version: $VERSION" + + - name: Configure latest UMF build + working-directory: ${{github.workspace}}/latest_version + run: > + cmake + -B ${{github.workspace}}/latest_version/build + -DCMAKE_INSTALL_PREFIX="${{github.workspace}}/latest_version/build/install" + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} + -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} + -DCMAKE_C_COMPILER=${{matrix.compiler.c}} + -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=${{matrix.level_zero_provider}} + -DUMF_BUILD_CUDA_PROVIDER=${{matrix.cuda_provider}} + -DUMF_FORMAT_CODE_STYLE=OFF + -DUMF_DEVELOPER_MODE=ON + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON + -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON + -DUMF_TESTS_FAIL_ON_SKIP=ON + + - name: Build latest UMF + working-directory: ${{github.workspace}}/latest_version + run: | + cmake --build ${{github.workspace}}/latest_version/build -j $(nproc) + + # NOTE: exclude umf-provider_coarse, umf-disjointCoarseMallocPool, + # umf-jemalloc_coarse_file, umf-scalable_coarse_file + - name: Run "tag" UMF tests with latest UMF libs (warnigs enabled) + working-directory: ${{github.workspace}}/tag_version/build + run: > + UMF_LOG="level:warning;flush:debug;output:stderr;pid:no" + LD_LIBRARY_PATH=${{github.workspace}}/latest_version/build/lib/ + ctest --output-on-failure -E "umf-provider_coarse|umf-disjointCoarseMallocPool|umf-jemalloc_coarse_file|umf-scalable_coarse_file" + \ No newline at end of file diff --git a/examples/custom_file_provider/custom_file_provider.c b/examples/custom_file_provider/custom_file_provider.c index b17fdc0f0..e4f12c0a8 100644 --- a/examples/custom_file_provider/custom_file_provider.c +++ b/examples/custom_file_provider/custom_file_provider.c @@ -234,7 +234,7 @@ static umf_result_t file_get_min_page_size(void *provider, void *ptr, // File provider operations static umf_memory_provider_ops_t file_ops = { - .version = UMF_VERSION_CURRENT, + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = file_init, .finalize = file_deinit, .alloc = file_alloc, diff --git a/include/umf/memory_pool_ops.h b/include/umf/memory_pool_ops.h index 829f49fb7..c818c107c 100644 --- a/include/umf/memory_pool_ops.h +++ b/include/umf/memory_pool_ops.h @@ -17,6 +17,11 @@ extern "C" { #endif +// TODO comment +// NOTE: This is equal to the latest UMF version, in which the ops structure +// has been modified. +#define UMF_POOL_OPS_VERSION_CURRENT UMF_MAKE_VERSION(0, 11) + /// /// @brief This structure comprises function pointers used by corresponding umfPool* /// calls. Each memory pool implementation should initialize all function @@ -24,7 +29,7 @@ extern "C" { /// typedef struct umf_memory_pool_ops_t { /// Version of the ops structure. - /// Should be initialized using UMF_VERSION_CURRENT. + /// Should be initialized using UMF_POOL_OPS_VERSION_CURRENT. uint32_t version; /// diff --git a/include/umf/memory_provider_ops.h b/include/umf/memory_provider_ops.h index a61e0aad0..e00f269bf 100644 --- a/include/umf/memory_provider_ops.h +++ b/include/umf/memory_provider_ops.h @@ -16,12 +16,17 @@ extern "C" { #endif +// TODO comment +// NOTE: This is equal to the latest UMF version, in which the ops structure +// has been modified. +#define UMF_PROVIDER_OPS_VERSION_CURRENT UMF_MAKE_VERSION(0, 11) + /// /// @brief This structure comprises optional function pointers used /// by corresponding umfMemoryProvider* calls. A memory provider implementation /// can keep them NULL. /// -typedef struct umf_memory_provider_ext_ops_t { +typedef struct umf_memory_provider_ext_ops_0_11_t { /// /// @brief Discard physical pages within the virtual memory mapping associated at the given addr /// and \p size. This call is asynchronous and may delay purging the pages indefinitely. @@ -78,13 +83,14 @@ typedef struct umf_memory_provider_ext_ops_t { umf_result_t (*allocation_split)(void *hProvider, void *ptr, size_t totalSize, size_t firstSize); -} umf_memory_provider_ext_ops_t; +} umf_memory_provider_ext_ops_0_11_t; +typedef umf_memory_provider_ext_ops_0_11_t umf_memory_provider_ext_ops_t; /// /// @brief This structure comprises optional IPC API. The API allows sharing of /// memory objects across different processes. A memory provider implementation can keep them NULL. /// -typedef struct umf_memory_provider_ipc_ops_t { +typedef struct umf_memory_provider_ipc_ops_0_11_t { /// /// @brief Retrieve the size of opaque data structure required to store IPC data. /// @param provider pointer to the memory provider. @@ -134,16 +140,17 @@ typedef struct umf_memory_provider_ipc_ops_t { /// UMF_RESULT_ERROR_INVALID_ARGUMENT if invalid \p ptr is passed. /// UMF_RESULT_ERROR_NOT_SUPPORTED if IPC functionality is not supported by this provider. umf_result_t (*close_ipc_handle)(void *provider, void *ptr, size_t size); -} umf_memory_provider_ipc_ops_t; +} umf_memory_provider_ipc_ops_0_11_t; +typedef umf_memory_provider_ipc_ops_0_11_t umf_memory_provider_ipc_ops_t; /// /// @brief This structure comprises function pointers used by corresponding /// umfMemoryProvider* calls. Each memory provider implementation should /// initialize all function pointers. /// -typedef struct umf_memory_provider_ops_t { +typedef struct umf_memory_provider_ops_0_11_t { /// Version of the ops structure. - /// Should be initialized using UMF_VERSION_CURRENT. + /// Should be initialized using UMF_PROVIDER_OPS_VERSION_CURRENT. uint32_t version; /// @@ -245,7 +252,8 @@ typedef struct umf_memory_provider_ops_t { /// @brief Optional IPC ops. The API allows sharing of memory objects across different processes. /// umf_memory_provider_ipc_ops_t ipc; -} umf_memory_provider_ops_t; +} umf_memory_provider_ops_0_11_t; +typedef umf_memory_provider_ops_0_11_t umf_memory_provider_ops_t; #ifdef __cplusplus } diff --git a/include/umf/providers/provider_devdax_memory.h b/include/umf/providers/provider_devdax_memory.h index 0fb5218bc..f27b879e7 100644 --- a/include/umf/providers/provider_devdax_memory.h +++ b/include/umf/providers/provider_devdax_memory.h @@ -66,6 +66,7 @@ typedef enum umf_devdax_memory_provider_native_error { } umf_devdax_memory_provider_native_error_t; umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void); +#define umfDevDaxMemoryProviderOps_0_11 umfDevDaxMemoryProviderOps #ifdef __cplusplus } diff --git a/include/umf/providers/provider_file_memory.h b/include/umf/providers/provider_file_memory.h index f652e2cb8..540bec52e 100644 --- a/include/umf/providers/provider_file_memory.h +++ b/include/umf/providers/provider_file_memory.h @@ -66,6 +66,7 @@ typedef enum umf_file_memory_provider_native_error { UMF_FILE_RESULT_ERROR_PURGE_FORCE_FAILED, ///< Force purging failed } umf_file_memory_provider_native_error_t; +#define umfFileMemoryProviderOps umfFileMemoryProviderOps_0_11 umf_memory_provider_ops_t *umfFileMemoryProviderOps(void); #ifdef __cplusplus diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c0072be7e..abf622284 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -77,6 +77,7 @@ set(UMF_SOURCES memspaces/memspace_lowest_latency.c memspaces/memspace_numa.c provider/provider_cuda.c + provider/provider_deprecated.c provider/provider_devdax_memory.c provider/provider_file_memory.c provider/provider_fixed_memory.c diff --git a/src/cpp_helpers.hpp b/src/cpp_helpers.hpp index 878910581..4b7cc54d0 100644 --- a/src/cpp_helpers.hpp +++ b/src/cpp_helpers.hpp @@ -67,7 +67,7 @@ umf_result_t initialize(T *obj, ArgsTuple &&args) { template umf_memory_pool_ops_t poolOpsBase() { umf_memory_pool_ops_t ops{}; - ops.version = UMF_VERSION_CURRENT; + ops.version = UMF_POOL_OPS_VERSION_CURRENT; ops.finalize = [](void *obj) { delete reinterpret_cast(obj); }; UMF_ASSIGN_OP(ops, T, malloc, ((void *)nullptr)); UMF_ASSIGN_OP(ops, T, calloc, ((void *)nullptr)); @@ -81,7 +81,7 @@ template umf_memory_pool_ops_t poolOpsBase() { template constexpr umf_memory_provider_ops_t providerOpsBase() { umf_memory_provider_ops_t ops{}; - ops.version = UMF_VERSION_CURRENT; + ops.version = UMF_PROVIDER_OPS_VERSION_CURRENT; ops.finalize = [](void *obj) { delete reinterpret_cast(obj); }; UMF_ASSIGN_OP(ops, T, alloc, UMF_RESULT_ERROR_UNKNOWN); UMF_ASSIGN_OP(ops, T, free, UMF_RESULT_ERROR_UNKNOWN); diff --git a/src/libumf.def b/src/libumf.def index 090b3a86f..9857339f7 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -14,18 +14,20 @@ EXPORTS umfTearDown umfGetCurrentVersion umfCloseIPCHandle + umfCoarseMemoryProviderGetStats ; deprecated + umfCoarseMemoryProviderOps ; deprecated umfCUDAMemoryProviderOps umfCUDAMemoryProviderParamsCreate umfCUDAMemoryProviderParamsDestroy umfCUDAMemoryProviderParamsSetContext umfCUDAMemoryProviderParamsSetDevice umfCUDAMemoryProviderParamsSetMemoryType - umfDevDaxMemoryProviderOps + umfDevDaxMemoryProviderOps ; deprecated umfDevDaxMemoryProviderParamsCreate umfDevDaxMemoryProviderParamsDestroy umfDevDaxMemoryProviderParamsSetDeviceDax umfDevDaxMemoryProviderParamsSetProtection - umfFileMemoryProviderOps + umfFileMemoryProviderOps ; deprecated umfFileMemoryProviderParamsCreate umfFileMemoryProviderParamsDestroy umfFileMemoryProviderParamsSetPath @@ -118,6 +120,8 @@ EXPORTS umfScalablePoolParamsSetGranularity umfScalablePoolParamsSetKeepAllMemory ; Added in UMF_0.11 + umfDevDaxMemoryProviderOps_0_11 ; redefined 0.10 + umfFileMemoryProviderOps_0_11 ; redefined 0.10 umfFixedMemoryProviderOps umfFixedMemoryProviderParamsCreate umfFixedMemoryProviderParamsDestroy diff --git a/src/libumf.map b/src/libumf.map index c33bb7c10..fbe899148 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -8,18 +8,20 @@ UMF_0.10 { umfTearDown; umfGetCurrentVersion; umfCloseIPCHandle; + umfCoarseMemoryProviderGetStats; # deprecated + umfCoarseMemoryProviderOps; # deprecated umfCUDAMemoryProviderOps; umfCUDAMemoryProviderParamsCreate; umfCUDAMemoryProviderParamsDestroy; umfCUDAMemoryProviderParamsSetContext; umfCUDAMemoryProviderParamsSetDevice; umfCUDAMemoryProviderParamsSetMemoryType; - umfDevDaxMemoryProviderOps; + umfDevDaxMemoryProviderOps; # deprecated umfDevDaxMemoryProviderParamsCreate; umfDevDaxMemoryProviderParamsDestroy; umfDevDaxMemoryProviderParamsSetDeviceDax; umfDevDaxMemoryProviderParamsSetProtection; - umfFileMemoryProviderOps; + umfFileMemoryProviderOps; # deprecated umfFileMemoryProviderParamsCreate; umfFileMemoryProviderParamsDestroy; umfFileMemoryProviderParamsSetPath; @@ -116,6 +118,8 @@ UMF_0.10 { }; UMF_0.11 { + umfDevDaxMemoryProviderOps_0_11; # redefined 0.10 + umfFileMemoryProviderOps_0_11; # redefined 0.10 umfFixedMemoryProviderOps; umfFixedMemoryProviderParamsCreate; umfFixedMemoryProviderParamsDestroy; diff --git a/src/memory_pool.c b/src/memory_pool.c index e739f3f2f..12207c6c3 100644 --- a/src/memory_pool.c +++ b/src/memory_pool.c @@ -38,7 +38,11 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops, return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - assert(ops->version == UMF_VERSION_CURRENT); + if (ops->version != UMF_POOL_OPS_VERSION_CURRENT) { + LOG_WARN("memory pool ops version \"%d\" is different than current " + "version \"%d\"", + ops->version, UMF_POOL_OPS_VERSION_CURRENT); + } if (!(flags & UMF_POOL_CREATE_FLAG_DISABLE_TRACKING)) { // Wrap provider with memory tracking provider. diff --git a/src/memory_provider.c b/src/memory_provider.c index 59f3f1259..12a0fd8d2 100644 --- a/src/memory_provider.c +++ b/src/memory_provider.c @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -18,6 +19,7 @@ #include "base_alloc_global.h" #include "libumf.h" #include "memory_provider_internal.h" +#include "provider_deprecated.h" #include "utils_assert.h" typedef struct umf_memory_provider_t { @@ -163,22 +165,70 @@ umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops, void *params, umf_memory_provider_handle_t *hProvider) { libumfInit(); - if (!ops || !hProvider || !validateOps(ops)) { + if (!ops || !hProvider) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + umf_memory_provider_ops_t ops_current_ver; + if (ops->version != UMF_PROVIDER_OPS_VERSION_CURRENT) { + LOG_WARN("memory provider ops version \"%d\" is different than current " + "version \"%d\"", + ops->version, UMF_PROVIDER_OPS_VERSION_CURRENT); + + // TODO move to provider_deprecated.c? + if (ops->version == UMF_MAKE_VERSION(0, 10)) { + umf_memory_provider_ops_0_10_t ops_0_10; + memcpy(&ops_0_10, ops, sizeof(ops_0_10)); + + ops_current_ver.version = UMF_PROVIDER_OPS_VERSION_CURRENT; + ops_current_ver.alloc = ops_0_10.alloc; + + // in UMF 0.10 the free() was a part of ext and could be NULL + if (ops_0_10.ext.free != NULL) { + ops_current_ver.free = ops_0_10.ext.free; + } else { + ops_current_ver.free = umfDefaultFree_0_10; + } + + ops_current_ver.get_last_native_error = + ops_0_10.get_last_native_error; + ops_current_ver.get_recommended_page_size = + ops_0_10.get_recommended_page_size; + ops_current_ver.get_min_page_size = ops_0_10.get_min_page_size; + ops_current_ver.get_name = ops_0_10.get_name; + ops_current_ver.initialize = ops_0_10.initialize; + ops_current_ver.finalize = ops_0_10.finalize; + + ops_current_ver.ext.purge_lazy = ops_0_10.ext.purge_lazy; + ops_current_ver.ext.purge_force = ops_0_10.ext.purge_force; + ops_current_ver.ext.allocation_merge = + ops_0_10.ext.allocation_merge; + ops_current_ver.ext.allocation_split = + ops_0_10.ext.allocation_split; + + // IPC hasn't changed + assert(sizeof(umf_memory_provider_ipc_ops_t) == + sizeof(umf_memory_provider_ipc_ops_0_10_t)); + memcpy(&ops_current_ver.ipc, &ops_0_10.ipc, sizeof(ops_0_10.ipc)); + } + } else { + ops_current_ver = *ops; + } + + if (validateOps(&ops_current_ver) == false) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + assignOpsExtDefaults(&ops_current_ver); + assignOpsIpcDefaults(&ops_current_ver); + umf_memory_provider_handle_t provider = umf_ba_global_alloc(sizeof(umf_memory_provider_t)); if (!provider) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - assert(ops->version == UMF_VERSION_CURRENT); - - provider->ops = *ops; - - assignOpsExtDefaults(&(provider->ops)); - assignOpsIpcDefaults(&(provider->ops)); + provider->ops = ops_current_ver; void *provider_priv; umf_result_t ret = ops->initialize(params, &provider_priv); diff --git a/src/memtarget.c b/src/memtarget.c index a89708460..7dc001ff4 100644 --- a/src/memtarget.c +++ b/src/memtarget.c @@ -15,6 +15,7 @@ #include "memtarget_internal.h" #include "memtarget_ops.h" #include "utils_concurrency.h" +#include "utils_log.h" umf_result_t umfMemtargetCreate(const umf_memtarget_ops_t *ops, void *params, umf_memtarget_handle_t *memoryTarget) { @@ -29,7 +30,11 @@ umf_result_t umfMemtargetCreate(const umf_memtarget_ops_t *ops, void *params, return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - assert(ops->version == UMF_VERSION_CURRENT); + if (ops->version != UMF_MEMTARGET_OPS_VERSION_CURRENT) { + LOG_WARN("memtarget ops version \"%d\" is different than current " + "version \"%d\"", + ops->version, UMF_MEMTARGET_OPS_VERSION_CURRENT); + } target->ops = ops; diff --git a/src/memtarget_ops.h b/src/memtarget_ops.h index 75e16447e..ff04195f1 100644 --- a/src/memtarget_ops.h +++ b/src/memtarget_ops.h @@ -18,6 +18,11 @@ extern "C" { #endif +// TODO comment +// NOTE: This is equal to the latest UMF version, in which the ops structure +// has been modified. +#define UMF_MEMTARGET_OPS_VERSION_CURRENT UMF_MAKE_VERSION(0, 11) + typedef struct umf_memtarget_ops_t { /// Version of the ops structure. /// Should be initialized using UMF_VERSION_CURRENT diff --git a/src/memtargets/memtarget_numa.c b/src/memtargets/memtarget_numa.c index f32774ebb..9c2657cdb 100644 --- a/src/memtargets/memtarget_numa.c +++ b/src/memtargets/memtarget_numa.c @@ -390,7 +390,7 @@ static umf_result_t numa_compare(void *memTarget, void *otherMemTarget, } struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_MEMTARGET_OPS_VERSION_CURRENT, .initialize = numa_initialize, .finalize = numa_finalize, .pool_create_from_memspace = numa_pool_create_from_memspace, diff --git a/src/pool/pool_jemalloc.c b/src/pool/pool_jemalloc.c index 88e8e9342..23ae824d9 100644 --- a/src/pool/pool_jemalloc.c +++ b/src/pool/pool_jemalloc.c @@ -454,7 +454,7 @@ static umf_result_t op_get_last_allocation_error(void *pool) { } static umf_memory_pool_ops_t UMF_JEMALLOC_POOL_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_POOL_OPS_VERSION_CURRENT, .initialize = op_initialize, .finalize = op_finalize, .malloc = op_malloc, diff --git a/src/pool/pool_proxy.c b/src/pool/pool_proxy.c index 2269d9344..ff9d031fa 100644 --- a/src/pool/pool_proxy.c +++ b/src/pool/pool_proxy.c @@ -123,7 +123,7 @@ static umf_result_t proxy_get_last_allocation_error(void *pool) { } static umf_memory_pool_ops_t UMF_PROXY_POOL_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_POOL_OPS_VERSION_CURRENT, .initialize = proxy_pool_initialize, .finalize = proxy_pool_finalize, .malloc = proxy_malloc, diff --git a/src/pool/pool_scalable.c b/src/pool/pool_scalable.c index 6ee364344..fd6245791 100644 --- a/src/pool/pool_scalable.c +++ b/src/pool/pool_scalable.c @@ -382,7 +382,7 @@ static umf_result_t tbb_get_last_allocation_error(void *pool) { } static umf_memory_pool_ops_t UMF_SCALABLE_POOL_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_POOL_OPS_VERSION_CURRENT, .initialize = tbb_pool_initialize, .finalize = tbb_pool_finalize, .malloc = tbb_malloc, diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index edebb04e6..ec9b2f19a 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -618,8 +618,8 @@ cu_memory_provider_close_ipc_handle(void *provider, void *ptr, size_t size) { return UMF_RESULT_SUCCESS; } -static struct umf_memory_provider_ops_t UMF_CUDA_MEMORY_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, +static umf_memory_provider_ops_t UMF_CUDA_MEMORY_PROVIDER_OPS = { + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = cu_memory_provider_initialize, .finalize = cu_memory_provider_finalize, .alloc = cu_memory_provider_alloc, diff --git a/src/provider/provider_deprecated.c b/src/provider/provider_deprecated.c new file mode 100644 index 000000000..b0581537e --- /dev/null +++ b/src/provider/provider_deprecated.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2025 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +*/ + +#include +#include +#include + +#include +#include +#include + +#include "provider_deprecated.h" +#include "utils_log.h" + +#include +#undef umfDevDaxMemoryProviderOps +umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps_0_11(void); +static umf_memory_provider_ops_0_10_t UMF_DEVDAX_MEMORY_PROVIDER_OPS_0_10; + +extern umf_memory_provider_ops_0_11_t UMF_FILE_MEMORY_PROVIDER_OPS_0_11; +static umf_memory_provider_ops_0_10_t UMF_FILE_MEMORY_PROVIDER_OPS_0_10; +asm(".symver " + "umfFileMemoryProviderOps_0_10,umfFileMemoryProviderOps@@UMF_0.10"); + +// TODO comment all +umf_memory_provider_ops_0_10_t *umfFileMemoryProviderOps_0_10(void) { + umf_memory_provider_ops_0_11_t ops = UMF_FILE_MEMORY_PROVIDER_OPS_0_11; + umf_memory_provider_ops_0_10_t ops_0_10 = { + .version = UMF_MAKE_VERSION(0, 10), + .initialize = ops.initialize, + .finalize = ops.finalize, + .alloc = ops.alloc, + .get_last_native_error = ops.get_last_native_error, + .get_recommended_page_size = ops.get_recommended_page_size, + .get_min_page_size = ops.get_min_page_size, + .get_name = ops.get_name, + .ext.purge_lazy = ops.ext.purge_lazy, + .ext.purge_force = ops.ext.purge_force, + .ext.allocation_merge = ops.ext.allocation_merge, + .ext.allocation_split = ops.ext.allocation_split, + .ipc.get_ipc_handle_size = ops.ipc.get_ipc_handle_size, + .ipc.get_ipc_handle = ops.ipc.get_ipc_handle, + .ipc.put_ipc_handle = ops.ipc.put_ipc_handle, + .ipc.open_ipc_handle = ops.ipc.open_ipc_handle, + .ipc.close_ipc_handle = ops.ipc.close_ipc_handle, + }; + UMF_FILE_MEMORY_PROVIDER_OPS_0_10 = ops_0_10; + return &UMF_FILE_MEMORY_PROVIDER_OPS_0_10; +} + +umf_memory_provider_ops_0_10_t *umfDevDaxMemoryProviderOps_0_10(void) { + umf_memory_provider_ops_t ops = *umfDevDaxMemoryProviderOps_0_11(); + umf_memory_provider_ops_0_10_t ops_0_10 = { + .version = UMF_MAKE_VERSION(0, 10), + .initialize = ops.initialize, + .finalize = ops.finalize, + .alloc = ops.alloc, + .get_last_native_error = ops.get_last_native_error, + .get_recommended_page_size = ops.get_recommended_page_size, + .get_min_page_size = ops.get_min_page_size, + .get_name = ops.get_name, + .ext.purge_lazy = ops.ext.purge_lazy, + .ext.purge_force = ops.ext.purge_force, + .ext.allocation_merge = ops.ext.allocation_merge, + .ext.allocation_split = ops.ext.allocation_split, + .ipc.get_ipc_handle_size = ops.ipc.get_ipc_handle_size, + .ipc.get_ipc_handle = ops.ipc.get_ipc_handle, + .ipc.put_ipc_handle = ops.ipc.put_ipc_handle, + .ipc.open_ipc_handle = ops.ipc.open_ipc_handle, + .ipc.close_ipc_handle = ops.ipc.close_ipc_handle, + }; + UMF_DEVDAX_MEMORY_PROVIDER_OPS_0_10 = ops_0_10; + return &UMF_DEVDAX_MEMORY_PROVIDER_OPS_0_10; +} + +umf_result_t umfDefaultFree_0_10(void *provider, void *ptr, size_t size) { + (void)provider; + (void)ptr; + (void)size; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_memory_provider_ops_t *umfCoarseMemoryProviderOps(void) { + LOG_ERR("Coarse Provider is deprecated!"); + return NULL; +} + +typedef struct coarse_memory_provider_stats_t { +} coarse_memory_provider_stats_t; + +coarse_memory_provider_stats_t +umfCoarseMemoryProviderGetStats(umf_memory_provider_handle_t provider) { + (void)provider; + LOG_ERR("Coarse Provider is deprecated!"); + coarse_memory_provider_stats_t ret = {}; + return ret; +} diff --git a/src/provider/provider_deprecated.h b/src/provider/provider_deprecated.h new file mode 100644 index 000000000..e7f2252c2 --- /dev/null +++ b/src/provider/provider_deprecated.h @@ -0,0 +1,63 @@ +/* + * + * Copyright (C) 2025 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +#ifndef UMF_PROVIDER_DEPRECATED_H +#define UMF_PROVIDER_DEPRECATED_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// TODO comment +typedef struct umf_memory_provider_ext_ops_0_10_t { + umf_result_t (*free)(void *provider, void *ptr, size_t size); + umf_result_t (*purge_lazy)(void *provider, void *ptr, size_t size); + umf_result_t (*purge_force)(void *provider, void *ptr, size_t size); + umf_result_t (*allocation_merge)(void *hProvider, void *lowPtr, + void *highPtr, size_t totalSize); + umf_result_t (*allocation_split)(void *hProvider, void *ptr, + size_t totalSize, size_t firstSize); +} umf_memory_provider_ext_ops_0_10_t; + +typedef struct umf_memory_provider_ipc_ops_0_10_t { + umf_result_t (*get_ipc_handle_size)(void *provider, size_t *size); + umf_result_t (*get_ipc_handle)(void *provider, const void *ptr, size_t size, + void *providerIpcData); + umf_result_t (*put_ipc_handle)(void *provider, void *providerIpcData); + umf_result_t (*open_ipc_handle)(void *provider, void *providerIpcData, + void **ptr); + umf_result_t (*close_ipc_handle)(void *provider, void *ptr, size_t size); +} umf_memory_provider_ipc_ops_0_10_t; + +typedef struct umf_memory_provider_ops_0_10_t { + uint32_t version; + umf_result_t (*initialize)(void *params, void **provider); + void (*finalize)(void *provider); + umf_result_t (*alloc)(void *provider, size_t size, size_t alignment, + void **ptr); + void (*get_last_native_error)(void *provider, const char **ppMessage, + int32_t *pError); + umf_result_t (*get_recommended_page_size)(void *provider, size_t size, + size_t *pageSize); + umf_result_t (*get_min_page_size)(void *provider, void *ptr, + size_t *pageSize); + const char *(*get_name)(void *provider); + umf_memory_provider_ext_ops_0_10_t ext; + umf_memory_provider_ipc_ops_0_10_t ipc; +} umf_memory_provider_ops_0_10_t; + +umf_result_t umfDefaultFree_0_10(void *provider, void *ptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef UMF_PROVIDER_DEPRECATED_H */ diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 4841a9919..635aa360b 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -529,8 +529,8 @@ static umf_result_t devdax_free(void *provider, void *ptr, size_t size) { return coarse_free(devdax_provider->coarse, ptr, size); } -static umf_memory_provider_ops_t UMF_DEVDAX_MEMORY_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, +umf_memory_provider_ops_0_11_t UMF_DEVDAX_MEMORY_PROVIDER_OPS_0_11 = { + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = devdax_initialize, .finalize = devdax_finalize, .alloc = devdax_alloc, @@ -547,10 +547,11 @@ static umf_memory_provider_ops_t UMF_DEVDAX_MEMORY_PROVIDER_OPS = { .ipc.get_ipc_handle = devdax_get_ipc_handle, .ipc.put_ipc_handle = devdax_put_ipc_handle, .ipc.open_ipc_handle = devdax_open_ipc_handle, - .ipc.close_ipc_handle = devdax_close_ipc_handle}; + .ipc.close_ipc_handle = devdax_close_ipc_handle, +}; -umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void) { - return &UMF_DEVDAX_MEMORY_PROVIDER_OPS; +umf_memory_provider_ops_0_11_t *umfDevDaxMemoryProviderOps_0_11(void) { + return &UMF_DEVDAX_MEMORY_PROVIDER_OPS_0_11; } umf_result_t umfDevDaxMemoryProviderParamsCreate( diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index ea69dc7b6..4bc5d63cc 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -847,8 +847,8 @@ static umf_result_t file_free(void *provider, void *ptr, size_t size) { return coarse_free(file_provider->coarse, ptr, size); } -static umf_memory_provider_ops_t UMF_FILE_MEMORY_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, +umf_memory_provider_ops_0_11_t UMF_FILE_MEMORY_PROVIDER_OPS_0_11 = { + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = file_initialize, .finalize = file_finalize, .alloc = file_alloc, @@ -865,10 +865,11 @@ static umf_memory_provider_ops_t UMF_FILE_MEMORY_PROVIDER_OPS = { .ipc.get_ipc_handle = file_get_ipc_handle, .ipc.put_ipc_handle = file_put_ipc_handle, .ipc.open_ipc_handle = file_open_ipc_handle, - .ipc.close_ipc_handle = file_close_ipc_handle}; + .ipc.close_ipc_handle = file_close_ipc_handle, +}; -umf_memory_provider_ops_t *umfFileMemoryProviderOps(void) { - return &UMF_FILE_MEMORY_PROVIDER_OPS; +umf_memory_provider_ops_0_11_t *umfFileMemoryProviderOps_0_11(void) { + return &UMF_FILE_MEMORY_PROVIDER_OPS_0_11; } umf_result_t umfFileMemoryProviderParamsCreate( diff --git a/src/provider/provider_fixed_memory.c b/src/provider/provider_fixed_memory.c index 6392b39d3..ad51ce3dd 100644 --- a/src/provider/provider_fixed_memory.c +++ b/src/provider/provider_fixed_memory.c @@ -254,7 +254,7 @@ static umf_result_t fixed_free(void *provider, void *ptr, size_t size) { } static umf_memory_provider_ops_t UMF_FIXED_MEMORY_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = fixed_initialize, .finalize = fixed_finalize, .alloc = fixed_alloc, diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index eaea8abd9..d17ddf434 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -750,8 +750,8 @@ ze_memory_provider_close_ipc_handle(void *provider, void *ptr, size_t size) { return UMF_RESULT_SUCCESS; } -static struct umf_memory_provider_ops_t UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, +static umf_memory_provider_ops_t UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS = { + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = ze_memory_provider_initialize, .finalize = ze_memory_provider_finalize, .alloc = ze_memory_provider_alloc, diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 1fe467942..92e2104d6 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -1402,7 +1402,7 @@ static umf_result_t os_close_ipc_handle(void *provider, void *ptr, } static umf_memory_provider_ops_t UMF_OS_MEMORY_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = os_initialize, .finalize = os_finalize, .alloc = os_alloc, diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index c4fff4133..a9c04a8ec 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -750,7 +750,7 @@ static umf_result_t trackingCloseIpcHandle(void *provider, void *ptr, } umf_memory_provider_ops_t UMF_TRACKING_MEMORY_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = trackingInitialize, .finalize = trackingFinalize, .alloc = trackingAlloc, diff --git a/test/common/pool_null.c b/test/common/pool_null.c index c34bcfc16..248dc2221 100644 --- a/test/common/pool_null.c +++ b/test/common/pool_null.c @@ -64,7 +64,7 @@ static umf_result_t nullGetLastStatus(void *pool) { } umf_memory_pool_ops_t UMF_NULL_POOL_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_POOL_OPS_VERSION_CURRENT, .initialize = nullInitialize, .finalize = nullFinalize, .malloc = nullMalloc, diff --git a/test/common/pool_trace.c b/test/common/pool_trace.c index d8b7522ea..9a9e01019 100644 --- a/test/common/pool_trace.c +++ b/test/common/pool_trace.c @@ -90,7 +90,7 @@ static umf_result_t traceGetLastStatus(void *pool) { } umf_memory_pool_ops_t UMF_TRACE_POOL_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_POOL_OPS_VERSION_CURRENT, .initialize = traceInitialize, .finalize = traceFinalize, .malloc = traceMalloc, diff --git a/test/common/provider_null.c b/test/common/provider_null.c index e667bfce4..25ae743ab 100644 --- a/test/common/provider_null.c +++ b/test/common/provider_null.c @@ -130,7 +130,7 @@ static umf_result_t nullCloseIpcHandle(void *provider, void *ptr, size_t size) { } umf_memory_provider_ops_t UMF_NULL_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = nullInitialize, .finalize = nullFinalize, .alloc = nullAlloc, diff --git a/test/common/provider_trace.c b/test/common/provider_trace.c index 9d063b4f5..827a0d010 100644 --- a/test/common/provider_trace.c +++ b/test/common/provider_trace.c @@ -191,7 +191,7 @@ static umf_result_t traceCloseIpcHandle(void *provider, void *ptr, } umf_memory_provider_ops_t UMF_TRACE_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, + .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = traceInitialize, .finalize = traceFinalize, .alloc = traceAlloc, diff --git a/test/test_init_teardown.c b/test/test_init_teardown.c index e6141c135..c7af8e06d 100644 --- a/test/test_init_teardown.c +++ b/test/test_init_teardown.c @@ -11,6 +11,10 @@ #include #include +#include + +#include "provider_deprecated.h" + #define SIZE_ALLOC 4096 typedef int (*umfMemoryProviderCreateFromMemspace_t)(void *hMemspace, @@ -54,6 +58,8 @@ static int umf_load(int n_init_teardown) { umfMemoryProviderCreateFromMemspace_t umfMemoryProviderCreateFromMemspace; umfGetPtr_t umfMemspaceHostAllGet; // the default memspace umfGetPtr_t umfScalablePoolOps; + umfGetPtr_t umfFileMemoryProviderOps; + umfGetPtr_t umfFileMemoryProviderOps_0_11; umfPoolCreate_t umfPoolCreate; umfVoidVoid_t umfInit; void *memspaceHostAll; @@ -119,6 +125,41 @@ static int umf_load(int n_init_teardown) { goto err_dlclose; } + load_symbol(h_umf, "umfFileMemoryProviderOps", + (void **)&umfFileMemoryProviderOps); + if (umfFileMemoryProviderOps == NULL) { + goto err_dlclose; + } else { + umf_memory_provider_ops_t *ops = umfFileMemoryProviderOps(); + if (ops == NULL) { + fprintf(stderr, "umfFileMemoryProviderOps: NULL ops\n"); + goto err_dlclose; + } + + // default version of umfFileMemoryProviderOps should return ops_0_10 + if (ops->version != UMF_MAKE_VERSION(0, 10)) { + fprintf(stderr, "umfFileMemoryProviderOps: bad ops version\n"); + goto err_dlclose; + } + } + + load_symbol(h_umf, "umfFileMemoryProviderOps_0_11", + (void **)&umfFileMemoryProviderOps_0_11); + if (umfFileMemoryProviderOps_0_11 == NULL) { + goto err_dlclose; + } else { + umf_memory_provider_ops_0_11_t *ops = umfFileMemoryProviderOps_0_11(); + if (ops == NULL) { + fprintf(stderr, "umfFileMemoryProviderOps_0_11: NULL ops\n"); + goto err_dlclose; + } + + if (ops->version != UMF_MAKE_VERSION(0, 11)) { + fprintf(stderr, "umfFileMemoryProviderOps_0_11: bad ops version\n"); + goto err_dlclose; + } + } + load_symbol(h_umf, "umfMemspaceHostAllGet", (void **)&umfMemspaceHostAllGet); if (umfMemspaceHostAllGet == NULL) {