From bd6226fadc933892b57e728bbe242d844194faa7 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 19 Oct 2023 11:41:04 +0200 Subject: [PATCH] Copy UMF code from UR repo Signed-off-by: Lukasz Dorau --- .gitignore | 85 +++++++ CMakeLists.txt | 97 ++++++++ LICENSE.TXT | 234 ++++++++++++++++++ README.md | 39 +++ cmake/helpers.cmake | 86 +++++++ .../unified-memory-framework-config.cmake.in | 4 + include/umf.h | 16 ++ include/umf/base.h | 53 ++++ include/umf/memory_pool.h | 154 ++++++++++++ include/umf/memory_pool_ops.h | 59 +++++ include/umf/memory_provider.h | 156 ++++++++++++ include/umf/memory_provider_ops.h | 58 +++++ src/CMakeLists.txt | 28 +++ src/memory_pool.c | 46 ++++ src/memory_pool_default.c | 100 ++++++++ src/memory_pool_internal.h | 36 +++ src/memory_provider.c | 131 ++++++++++ src/memory_provider_get_last_failed.c | 22 ++ src/memory_provider_internal.h | 26 ++ src/utils/utils.h | 109 ++++++++ src/utils/utils_posix.c | 34 +++ src/utils/utils_windows.c | 43 ++++ test/CMakeLists.txt | 34 +++ test/base.cpp | 15 ++ test/common/base.hpp | 36 +++ 25 files changed, 1701 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE.TXT create mode 100644 README.md create mode 100644 cmake/helpers.cmake create mode 100644 cmake/unified-memory-framework-config.cmake.in create mode 100644 include/umf.h create mode 100644 include/umf/base.h create mode 100644 include/umf/memory_pool.h create mode 100644 include/umf/memory_pool_ops.h create mode 100644 include/umf/memory_provider.h create mode 100644 include/umf/memory_provider_ops.h create mode 100644 src/CMakeLists.txt create mode 100644 src/memory_pool.c create mode 100644 src/memory_pool_default.c create mode 100644 src/memory_pool_internal.h create mode 100644 src/memory_provider.c create mode 100644 src/memory_provider_get_last_failed.c create mode 100644 src/memory_provider_internal.h create mode 100644 src/utils/utils.h create mode 100644 src/utils/utils_posix.c create mode 100644 src/utils/utils_windows.c create mode 100644 test/CMakeLists.txt create mode 100644 test/base.cpp create mode 100644 test/common/base.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..a1a488bc14 --- /dev/null +++ b/.gitignore @@ -0,0 +1,85 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj +*.exp +*.pdb +*.log +*.tlog +*.ilk +*.idb +*.CopyComplete +*.pyc +*.tmp + +# Precompiled Headers +*.gch +*.pch +*.ipch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Project files +*.sln +*.vcproj +*.vcxproj +*.pyproj +*.suo +*.db +*.opendb +*.user +*.filters +.vs/ +.idea/ + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Debug files +scripts/**/*.json + +# Python cache +__pycache__/ +*.py[cod] + +# Generated docs +docs/ + +# Build files +/build*/ +out/ + +# irepo files +.irepo + +# ci deps +.deps + +# third_party files +/third_party/*/ + + +# VS CMake settings +/CMakeSettings.json + +# Temporary files +*.~vsdx + +# IDE Files +/.vscode +/.devcontainer diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..b2ae476214 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,97 @@ +# Copyright (C) 2022-2023 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) +project(unified-memory-framework VERSION 0.1.0) + +include(CTest) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +include(helpers) + +# Build Options +option(UMF_DEVELOPER_MODE "enable developer checks, treats warnings as errors" OFF) +option(UMF_BUILD_SHARED_LIBRARY "Build UMF as shared library" OFF) + +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_UMF_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +if(MSVC) + set(CMAKE_UMF_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/$) +endif() + +# Define a path for custom commands to work around MSVC +set(CUSTOM_COMMAND_BINARY_DIR ${CMAKE_UMF_OUTPUT_DIRECTORY}) +if(MSVC) + # MSVC implicitly adds $ to the output path + set(CUSTOM_COMMAND_BINARY_DIR ${CUSTOM_COMMAND_BINARY_DIR}/$) +endif() + +# Obtain files for clang-format and license check +set(format_glob) +set(license_glob) +foreach(dir examples include source test tools) + list(APPEND format_glob + "${dir}/*.h" + "${dir}/*.c" + "${dir}/**/*.h" + "${dir}/**/*.c") + list(APPEND license_glob + "${dir}/*.yml" + "${dir}/**/*.yml" + "${dir}/*.py" + "${dir}/**/*.py" + "${dir}/**/CMakeLists.txt" + "${dir}/CMakeLists.txt" + ) +endforeach() +file(GLOB_RECURSE format_src ${format_glob}) +file(GLOB_RECURSE license_src ${license_glob}) + +# A header only library to specify include directories in transitive +# dependencies. +add_library(umf_headers INTERFACE) +# Alias target to support FetchContent. +add_library(${PROJECT_NAME}::headers ALIAS umf_headers) +target_include_directories(umf_headers INTERFACE + $ + $) + +# Add the include directory and the headers target to the install. +install( + DIRECTORY "${PROJECT_SOURCE_DIR}/include/" + DESTINATION include COMPONENT umf_headers) +install( + TARGETS umf_headers + EXPORT ${PROJECT_NAME}-targets) + +add_subdirectory(src) +add_subdirectory(test) + +# Add the list of installed targets to the install. This includes the namespace +# which all installed targets will be prefixed with, e.g. for the headers +# target users will depend on ${PROJECT_NAME}::headers. +install( + EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}-targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION lib/cmake/${PROJECT_NAME}) + +# Configure the package versions file for use in find_package when installed. +write_basic_package_version_file( + ${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}-config-version.cmake + COMPATIBILITY SameMajorVersion) +# Configure the package file that is searched for by find_package when +# installed. +configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake.in + ${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}-config.cmake + INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}) + +# Add the package files to the install. +install( + FILES + ${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}-config.cmake + ${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}-config-version.cmake + DESTINATION lib/cmake/${PROJECT_NAME}) diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 0000000000..c556c55755 --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,234 @@ +============================================================================== +The Unified Memory Framework is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + +============================================================================== +Software from third parties included in the Unified Memory Framework: +============================================================================== +The Unified Memory Framework contains third party software which is under different license +terms. All such code will be identified clearly using at least one of two +mechanisms: +1) It will be in a separate directory tree with its own `LICENSE.txt` or + `LICENSE` file at the top containing the specific license and restrictions + which apply to that software, or +2) It will contain specific license and restriction terms at the top of every + file. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..1ac812543c --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# Unified Memory Framework + +## Building + +### Requirements + +Required packages: +- C compiler +- [CMake](https://cmake.org/) >= 3.14.0 + +### Windows + +Generating Visual Studio Project. EXE and binaries will be in **build/bin/{build_config}** + +```bash +$ mkdir build +$ cd build +$ cmake {path_to_source_dir} -G "Visual Studio 15 2017 Win64" +``` + +### Linux + +Executable and binaries will be in **build/bin** + +```bash +$ mkdir build +$ cd build +$ cmake {path_to_source_dir} +$ make +``` + +### CMake standard options + +List of options provided by CMake: + +| Name | Description | Values | Default | +| - | - | - | - | +| UMF_DEVELOPER_MODE | Treat warnings as errors and enables additional checks | ON/OFF | OFF | +| UMF_BUILD_SHARED_LIBRARY | Build UMF as shared library | ON/OFF | OFF | diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake new file mode 100644 index 0000000000..522365f6ec --- /dev/null +++ b/cmake/helpers.cmake @@ -0,0 +1,86 @@ +# Copyright (C) 2023 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# +# helpers.cmake -- helper functions for top-level CMakeLists.txt +# + +# Sets ${ret} to version of program specified by ${name} in major.minor format +function(get_program_version_major_minor name ret) + execute_process(COMMAND ${name} --version + OUTPUT_VARIABLE cmd_ret + ERROR_QUIET) + STRING(REGEX MATCH "([0-9]+)\.([0-9]+)" VERSION "${cmd_ret}") + SET(${ret} ${VERSION} PARENT_SCOPE) +endfunction() + +function(add_umf_target_compile_options name) + if(NOT MSVC) + target_compile_options(${name} PRIVATE + -fPIC + -Wall + -Wpedantic + -Wempty-body + -Wunused-parameter + $<$:-fdiagnostics-color=always> + $<$:-fcolor-diagnostics> + ) + if (CMAKE_BUILD_TYPE STREQUAL "Release") + target_compile_definitions(${name} PRIVATE -D_FORTIFY_SOURCE=2) + endif() + if(UMF_DEVELOPER_MODE) + target_compile_options(${name} PRIVATE + -Werror + -fno-omit-frame-pointer + -fstack-protector-strong + ) + endif() + elseif(MSVC) + target_compile_options(${name} PRIVATE + $<$:/MP> # clang-cl.exe does not support /MP + /W3 + /MD$<$:d> + /GS + ) + + if(UMF_DEVELOPER_MODE) + target_compile_options(${name} PRIVATE /WX /GS) + endif() + endif() +endfunction() + +function(add_umf_target_link_options name) + if(NOT MSVC) + if (NOT APPLE) + target_link_options(${name} PRIVATE "LINKER:-z,relro,-z,now") + endif() + elseif(MSVC) + target_link_options(${name} PRIVATE + /DYNAMICBASE + /HIGHENTROPYVA + /NXCOMPAT + ) + endif() +endfunction() + +function(add_umf_target_exec_options name) + if(MSVC) + target_link_options(${name} PRIVATE + /ALLOWISOLATION + ) + endif() +endfunction() + +function(add_umf_executable name) + add_executable(${name} ${ARGN}) + add_umf_target_compile_options(${name}) + add_umf_target_exec_options(${name}) + add_umf_target_link_options(${name}) +endfunction() + +function(add_umf_library name) + add_library(${name} ${ARGN}) + add_umf_target_compile_options(${name}) + add_umf_target_link_options(${name}) +endfunction() diff --git a/cmake/unified-memory-framework-config.cmake.in b/cmake/unified-memory-framework-config.cmake.in new file mode 100644 index 0000000000..035dc0fa0b --- /dev/null +++ b/cmake/unified-memory-framework-config.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/include/umf.h b/include/umf.h new file mode 100644 index 0000000000..6f63741ad7 --- /dev/null +++ b/include/umf.h @@ -0,0 +1,16 @@ +/* + * + * Copyright (C) 2023 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_UNIFIED_MEMORY_FRAMEWORK_H +#define UMF_UNIFIED_MEMORY_FRAMEWORK_H 1 + +#include +#include + +#endif /* UMF_UNIFIED_MEMORY_FRAMEWORK_H */ diff --git a/include/umf/base.h b/include/umf/base.h new file mode 100644 index 0000000000..63071fd4bc --- /dev/null +++ b/include/umf/base.h @@ -0,0 +1,53 @@ +/* + * + * Copyright (C) 2023 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_BASE_H +#define UMF_BASE_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// \brief Generates generic 'UMF' API versions +#define UMF_MAKE_VERSION(_major, _minor) \ + ((_major << 16) | (_minor & 0x0000ffff)) + +/// \brief Extracts 'UMF' API major version +#define UMF_MAJOR_VERSION(_ver) (_ver >> 16) + +/// \brief Extracts 'UMF' API minor version +#define UMF_MINOR_VERSION(_ver) (_ver & 0x0000ffff) + +/// \brief Current version of the UMF headers +#define UMF_VERSION_CURRENT UMF_MAKE_VERSION(0, 9) + +/// \brief Operation results +enum umf_result_t { + UMF_RESULT_SUCCESS = 0, ///< Success + UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY = + 1, ///< Insufficient host memory to satisfy call, + UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC = + 2, ///< A provider specific warning/error has been reported and can be + ///< Retrieved via the umfMemoryProviderGetLastNativeError entry point. + UMF_RESULT_ERROR_INVALID_ARGUMENT = + 3, ///< Generic error code for invalid arguments + UMF_RESULT_ERROR_INVALID_ALIGNMENT = 4, /// Invalid alignment of an argument + UMF_RESULT_ERROR_NOT_SUPPORTED = 5, /// Operation not supported + + UMF_RESULT_ERROR_UNKNOWN = 0x7ffffffe ///< Unknown or internal error +}; + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_BASE_H */ diff --git a/include/umf/memory_pool.h b/include/umf/memory_pool.h new file mode 100644 index 0000000000..1b1653b4b8 --- /dev/null +++ b/include/umf/memory_pool.h @@ -0,0 +1,154 @@ +/* + * + * Copyright (C) 2023 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_MEMORY_POOL_H +#define UMF_MEMORY_POOL_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct umf_memory_pool_t *umf_memory_pool_handle_t; + +struct umf_memory_pool_ops_t; + +/// +/// \brief Creates new memory pool. +/// \param ops instance of umf_memory_pool_ops_t +/// \param providers array of memory providers that will be used for coarse-grain allocations. +/// Should contain at least one memory provider. +/// \param numProvider number of elements in the providers array +/// \param params pointer to pool-specific parameters +/// \param hPool [out] handle to the newly created memory pool +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// +enum umf_result_t umfPoolCreate(const struct umf_memory_pool_ops_t *ops, + umf_memory_provider_handle_t *providers, + size_t numProviders, void *params, + umf_memory_pool_handle_t *hPool); + +/// +/// \brief Destroys memory pool. +/// \param hPool handle to the pool +/// +void umfPoolDestroy(umf_memory_pool_handle_t hPool); + +/// +/// \brief Allocates size bytes of uninitialized storage of the specified hPool. +/// \param hPool specified memory hPool +/// \param size number of bytes to allocate +/// \return Pointer to the allocated memory. +/// +void *umfPoolMalloc(umf_memory_pool_handle_t hPool, size_t size); + +/// +/// \brief Allocates size bytes of uninitialized storage of the specified hPool. +/// with specified alignment +/// \param hPool specified memory hPool +/// \param size number of bytes to allocate +/// \param alignment alignment of the allocation +/// \return Pointer to the allocated memory. +/// +void *umfPoolAlignedMalloc(umf_memory_pool_handle_t hPool, size_t size, + size_t alignment); + +/// +/// \brief Allocates memory of the specified hPool for an array of num elements +/// of size bytes each and initializes all bytes in the allocated storage +/// to zero. +/// \param hPool specified memory hPool +/// \param num number of objects +/// \param size specified size of each element +/// \return Pointer to the allocated memory. +/// +void *umfPoolCalloc(umf_memory_pool_handle_t hPool, size_t num, size_t size); + +/// +/// \brief Reallocates memory of the specified hPool. +/// \param hPool specified memory hPool +/// \param ptr pointer to the memory block to be reallocated +/// \param size new size for the memory block in bytes +/// \return Pointer to the allocated memory. +/// +void *umfPoolRealloc(umf_memory_pool_handle_t hPool, void *ptr, size_t size); + +/// +/// \brief Obtains size of block of memory allocated from the pool. +/// \param hPool specified memory hPool +/// \param ptr pointer to the allocated memory +/// \return Number of bytes. +/// +size_t umfPoolMallocUsableSize(umf_memory_pool_handle_t hPool, void *ptr); + +/// +/// \brief Frees the memory space of the specified hPool pointed by ptr. +/// \param hPool specified memory hPool +/// \param ptr pointer to the allocated memory +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// Whether any status other than UMF_RESULT_SUCCESS can be returned +/// depends on the memory provider used by the pool. +/// +enum umf_result_t umfPoolFree(umf_memory_pool_handle_t hPool, void *ptr); + +/// +/// \brief Frees the memory space pointed by ptr if it belongs to UMF pool, does nothing otherwise. +/// \param ptr pointer to the allocated memory +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// Whether any status other than UMF_RESULT_SUCCESS can be returned +/// depends on the memory provider used by the pool. +/// +enum umf_result_t umfFree(void *ptr); + +/// +/// \brief Retrieve umf_result_t representing the error of the last failed allocation +/// operation in this thread (malloc, calloc, realloc, aligned_malloc). +/// +/// \details +/// * Implementations *must* store the error code in thread-local +/// storage prior to returning NULL from the allocation functions. +/// +/// * If the last allocation/de-allocation operation succeeded, the value returned by +/// this function is unspecified. +/// +/// * The application *may* call this function from simultaneous threads. +/// +/// * The implementation of this function *should* be lock-free. +/// \param hPool specified memory hPool +/// \return Error code desciribng the failure of the last failed allocation operation. +/// The value is undefined if the previous allocation was successful. +enum umf_result_t umfPoolGetLastAllocationError(umf_memory_pool_handle_t hPool); + +/// +/// \brief Retrieve memory pool associated with a given ptr. Only memory allocated +/// with the usage of a memory provider is being tracked. +/// \param ptr pointer to memory belonging to a memory pool +/// \return Handle to a memory pool that contains ptr or NULL if pointer does not belong to any UMF pool. +umf_memory_pool_handle_t umfPoolByPtr(const void *ptr); + +/// +/// \brief Retrieve memory providers associated with a given pool. +/// \param hPool specified memory pool +/// \param hProviders [out] pointer to an array of memory providers. If numProviders is not equal to or +/// greater than the real number of providers, UMF_RESULT_ERROR_INVALID_ARGUMENT is returned. +/// \param numProviders [in] number of memory providers to return +/// \param numProvidersRet pointer to the actual number of memory providers +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +enum umf_result_t +umfPoolGetMemoryProviders(umf_memory_pool_handle_t hPool, size_t numProviders, + umf_memory_provider_handle_t *hProviders, + size_t *numProvidersRet); + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_MEMORY_POOL_H */ diff --git a/include/umf/memory_pool_ops.h b/include/umf/memory_pool_ops.h new file mode 100644 index 0000000000..6db6a47412 --- /dev/null +++ b/include/umf/memory_pool_ops.h @@ -0,0 +1,59 @@ +/* + * + * Copyright (C) 2023 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_MEMORY_POOL_OPS_H +#define UMF_MEMORY_POOL_OPS_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// \brief This structure comprises function pointers used by corresponding umfPool* +/// calls. Each memory pool implementation should initialize all function +/// pointers. +struct umf_memory_pool_ops_t { + /// Version of the ops structure. + /// Should be initialized using UMF_VERSION_CURRENT + uint32_t version; + + /// + /// \brief Initializes memory pool. + /// \param providers array of memory providers that will be used for coarse-grain allocations. + /// Should contain at least one memory provider. + /// \param numProvider number of elements in the providers array + /// \param params pool-specific params + /// \param pool [out] returns pointer to the pool + /// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. + enum umf_result_t (*initialize)(umf_memory_provider_handle_t *providers, + size_t numProviders, void *params, + void **pool); + + /// + /// \brief Finalizes memory pool + /// \param pool pool to finalize + void (*finalize)(void *pool); + + /// Refer to memory_pool.h for description of those functions + void *(*malloc)(void *pool, size_t size); + void *(*calloc)(void *pool, size_t num, size_t size); + void *(*realloc)(void *pool, void *ptr, size_t size); + void *(*aligned_malloc)(void *pool, size_t size, size_t alignment); + size_t (*malloc_usable_size)(void *pool, void *ptr); + enum umf_result_t (*free)(void *pool, void *); + enum umf_result_t (*get_last_allocation_error)(void *pool); +}; + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_MEMORY_POOL_OPS_H */ diff --git a/include/umf/memory_provider.h b/include/umf/memory_provider.h new file mode 100644 index 0000000000..b1cdadc356 --- /dev/null +++ b/include/umf/memory_provider.h @@ -0,0 +1,156 @@ +/* + * + * Copyright (C) 2023 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_MEMORY_PROVIDER_H +#define UMF_MEMORY_PROVIDER_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct umf_memory_provider_t *umf_memory_provider_handle_t; + +/// +/// \brief Creates new memory provider. +/// \param ops instance of umf_memory_provider_ops_t +/// \param params pointer to provider-specific parameters +/// \param hProvider [out] pointer to the newly created memory provider +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// +enum umf_result_t +umfMemoryProviderCreate(const struct umf_memory_provider_ops_t *ops, + void *params, umf_memory_provider_handle_t *hProvider); + +/// +/// \brief Destroys memory provider. +/// \param hPool handle to the memory provider +/// +void umfMemoryProviderDestroy(umf_memory_provider_handle_t hProvider); + +/// +/// \brief Allocates size bytes of uninitialized storage from memory provider +/// with specified alignment. +/// \param hProvider handle to the memory provider +/// \param size number of bytes to allocate +/// \param alignment alignment of the allocation +/// \param ptr [out] pointer to the allocated memory +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// +enum umf_result_t umfMemoryProviderAlloc(umf_memory_provider_handle_t hProvider, + size_t size, size_t alignment, + void **ptr); + +/// +/// \brief Frees the memory space pointed by ptr from the memory provider. +/// \param hProvider handle to the memory provider +/// \param ptr pointer to the allocated memory +/// \param size size of the allocation +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// +enum umf_result_t umfMemoryProviderFree(umf_memory_provider_handle_t hProvider, + void *ptr, size_t size); + +/// +/// \brief Retrieve string representation of the underlying provider specific +/// result reported by the last API that returned +/// UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC. Allows for a provider +/// independent way to return a provider specific result. +/// +/// \details +/// * Implementations *must* store the message and error code in thread-local +/// storage prior to returning UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC. +/// +/// * The message and error code will only be valid if a previously +/// called entry-point returned UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC. +/// +/// * The memory pointed to by the C string returned in `ppMessage` is owned by +/// the adapter and *must* be null terminated. +/// +/// * The application *may* call this function from simultaneous threads. +/// +/// * The implementation of this function *should* be lock-free. +/// \param hProvider handle to the memory provider +/// \param ppMessage [out] pointer to a string containing provider specific +/// result in string representation +/// \param pError [out] pointer to an integer where the adapter specific error code will be stored +void umfMemoryProviderGetLastNativeError(umf_memory_provider_handle_t hProvider, + const char **ppMessage, + int32_t *pError); + +/// +/// \brief Retrieve recommended page size for a given allocation size. +/// \param hProvider handle to the memory provider +/// \param size allocation size +/// \param pageSize [out] will be updated with recommended page size +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +enum umf_result_t +umfMemoryProviderGetRecommendedPageSize(umf_memory_provider_handle_t hProvider, + size_t size, size_t *pageSize); + +/// +/// \brief Retrieve minimum possible page size used by memory region referenced by given ptr +/// or minimum possible page size that can be used by this provider if ptr is NULL. +/// \param hProvider handle to the memory provider +/// \param ptr [optional] pointer to memory allocated by this memory provider +/// \param pageSize [out] will be updated with page size value. +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +enum umf_result_t +umfMemoryProviderGetMinPageSize(umf_memory_provider_handle_t hProvider, + void *ptr, size_t *pageSize); + +/// +/// \brief Discard physical pages within the virtual memory mapping associated at given addr and size. +/// This call is asynchronous and may delay purging the pages indefinitely. +/// \param hProvider handle to the memory provider +/// \param ptr beginning of the virtual memory range +/// \param size size of the virtual memory range +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// UMF_RESULT_ERROR_INVALID_ALIGNMENT if ptr or size is not page-aligned. +/// UMF_RESULT_ERROR_NOT_SUPPORTED if operation is not supported by this provider. +enum umf_result_t +umfMemoryProviderPurgeLazy(umf_memory_provider_handle_t hProvider, void *ptr, + size_t size); + +/// +/// \brief Discard physical pages within the virtual memory mapping associated at given addr and size. +/// This call is synchronous and if it succeeds, pages are guaranteed to be zero-filled on the next access. +/// \param hProvider handle to the memory provider +/// \param ptr beginning of the virtual memory range +/// \param size size of the virtual memory range +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure +/// UMF_RESULT_ERROR_INVALID_ALIGNMENT if ptr or size is not page-aligned. +/// UMF_RESULT_ERROR_NOT_SUPPORTED if operation is not supported by this provider. +enum umf_result_t +umfMemoryProviderPurgeForce(umf_memory_provider_handle_t hProvider, void *ptr, + size_t size); + +/// +/// \brief Retrieve name of a given memory provider. +/// \param hProvider handle to the memory provider +/// \param ppName [out] pointer to a string containing name of the provider +const char *umfMemoryProviderGetName(umf_memory_provider_handle_t hProvider); + +/// \brief Retrieve handle to the last memory provider that returned status other +/// than UMF_RESULT_SUCCESS on the calling thread. +/// +/// \details Handle to the memory provider is stored in the thread local +/// storage. The handle is updated every time a memory provider +/// returns status other than UMF_RESULT_SUCCESS. +/// +/// \return Handle to the memory provider +umf_memory_provider_handle_t umfGetLastFailedMemoryProvider(void); + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_MEMORY_PROVIDER_H */ diff --git a/include/umf/memory_provider_ops.h b/include/umf/memory_provider_ops.h new file mode 100644 index 0000000000..58991d81b2 --- /dev/null +++ b/include/umf/memory_provider_ops.h @@ -0,0 +1,58 @@ +/* + * + * Copyright (C) 2023 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_MEMORY_PROVIDER_OPS_H +#define UMF_MEMORY_PROVIDER_OPS_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// This structure comprises function pointers used by corresponding +/// umfMemoryProvider* calls. Each memory provider implementation should +/// initialize all function pointers. +struct umf_memory_provider_ops_t { + /// Version of the ops structure. + /// Should be initialized using UMF_VERSION_CURRENT + uint32_t version; + + /// + /// \brief Initializes memory provider. + /// \param params provider-specific params + /// \param provider returns pointer to the provider + /// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. + enum umf_result_t (*initialize)(void *params, void **provider); + + /// + /// \brief Finalizes memory provider. + /// \param provider provider to finalize + void (*finalize)(void *provider); + + /// Refer to memory_provider.h for description of those functions + enum umf_result_t (*alloc)(void *provider, size_t size, size_t alignment, + void **ptr); + enum umf_result_t (*free)(void *provider, void *ptr, size_t size); + void (*get_last_native_error)(void *provider, const char **ppMessage, + int32_t *pError); + enum umf_result_t (*get_recommended_page_size)(void *provider, size_t size, + size_t *pageSize); + enum umf_result_t (*get_min_page_size)(void *provider, void *ptr, + size_t *pageSize); + enum umf_result_t (*purge_lazy)(void *provider, void *ptr, size_t size); + enum umf_result_t (*purge_force)(void *provider, void *ptr, size_t size); + const char *(*get_name)(void *provider); +}; + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef UMF_MEMORY_PROVIDER_OPS_H */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..eb40c6f3ad --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2023 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set(UMF_SOURCES + memory_pool.c + memory_provider.c + memory_provider_get_last_failed.c +) + +if(MSVC) + set(UMF_SOURCES ${UMF_SOURCES} utils/utils_windows.c) +else() + set(UMF_SOURCES ${UMF_SOURCES} utils/utils_posix.c) +endif() + +if(UMF_BUILD_SHARED_LIBRARY) + add_umf_library(unified_memory_framework SHARED ${UMF_SOURCES}) + target_compile_definitions(unified_memory_framework PUBLIC UMF_SHARED_LIBRARY) +else() + add_umf_library(unified_memory_framework STATIC ${UMF_SOURCES}) +endif() + +target_sources(unified_memory_framework PRIVATE memory_pool_default.c) + +add_library(${PROJECT_NAME}::unified_memory_framework ALIAS unified_memory_framework) + +target_include_directories(unified_memory_framework PUBLIC ../include) diff --git a/src/memory_pool.c b/src/memory_pool.c new file mode 100644 index 0000000000..ee619dbdad --- /dev/null +++ b/src/memory_pool.c @@ -0,0 +1,46 @@ +/* + * + * Copyright (C) 2023 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +#include "memory_pool_internal.h" + +#include +#include + +#include +#include + +void *umfPoolMalloc(umf_memory_pool_handle_t hPool, size_t size) { + return hPool->ops.malloc(hPool->pool_priv, size); +} + +void *umfPoolAlignedMalloc(umf_memory_pool_handle_t hPool, size_t size, + size_t alignment) { + return hPool->ops.aligned_malloc(hPool->pool_priv, size, alignment); +} + +void *umfPoolCalloc(umf_memory_pool_handle_t hPool, size_t num, size_t size) { + return hPool->ops.calloc(hPool->pool_priv, num, size); +} + +void *umfPoolRealloc(umf_memory_pool_handle_t hPool, void *ptr, size_t size) { + return hPool->ops.realloc(hPool->pool_priv, ptr, size); +} + +size_t umfPoolMallocUsableSize(umf_memory_pool_handle_t hPool, void *ptr) { + return hPool->ops.malloc_usable_size(hPool->pool_priv, ptr); +} + +enum umf_result_t umfPoolFree(umf_memory_pool_handle_t hPool, void *ptr) { + return hPool->ops.free(hPool->pool_priv, ptr); +} + +enum umf_result_t +umfPoolGetLastAllocationError(umf_memory_pool_handle_t hPool) { + return hPool->ops.get_last_allocation_error(hPool->pool_priv); +} diff --git a/src/memory_pool_default.c b/src/memory_pool_default.c new file mode 100644 index 0000000000..dea1e3c369 --- /dev/null +++ b/src/memory_pool_default.c @@ -0,0 +1,100 @@ +/* + * + * Copyright (C) 2023 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +#include "memory_pool_internal.h" + +#include + +#include +#include + +enum umf_result_t umfPoolCreate(const struct umf_memory_pool_ops_t *ops, + umf_memory_provider_handle_t *providers, + size_t numProviders, void *params, + umf_memory_pool_handle_t *hPool) { + if (!numProviders || !providers) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + enum umf_result_t ret = UMF_RESULT_SUCCESS; + umf_memory_pool_handle_t pool = malloc(sizeof(struct umf_memory_pool_t)); + if (!pool) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + assert(ops->version == UMF_VERSION_CURRENT); + + pool->providers = + calloc(numProviders, sizeof(umf_memory_provider_handle_t)); + if (!pool->providers) { + ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + goto err_providers_alloc; + } + + size_t providerInd = 0; + pool->numProviders = numProviders; + + for (providerInd = 0; providerInd < numProviders; providerInd++) { + pool->providers[providerInd] = providers[providerInd]; + } + + pool->ops = *ops; + ret = ops->initialize(pool->providers, pool->numProviders, params, + &pool->pool_priv); + if (ret != UMF_RESULT_SUCCESS) { + goto err_pool_init; + } + + *hPool = pool; + return UMF_RESULT_SUCCESS; + +err_pool_init: + free(pool->providers); +err_providers_alloc: + free(pool); + + return ret; +} + +void umfPoolDestroy(umf_memory_pool_handle_t hPool) { + hPool->ops.finalize(hPool->pool_priv); + free(hPool->providers); + free(hPool); +} + +enum umf_result_t umfFree(void *ptr) { + (void)ptr; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_memory_pool_handle_t umfPoolByPtr(const void *ptr) { + (void)ptr; + return NULL; +} + +enum umf_result_t +umfPoolGetMemoryProviders(umf_memory_pool_handle_t hPool, size_t numProviders, + umf_memory_provider_handle_t *hProviders, + size_t *numProvidersRet) { + if (hProviders && numProviders < hPool->numProviders) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (numProvidersRet) { + *numProvidersRet = hPool->numProviders; + } + + if (hProviders) { + for (size_t i = 0; i < hPool->numProviders; i++) { + hProviders[i] = hPool->providers[i]; + } + } + + return UMF_RESULT_SUCCESS; +} diff --git a/src/memory_pool_internal.h b/src/memory_pool_internal.h new file mode 100644 index 0000000000..86d488bc11 --- /dev/null +++ b/src/memory_pool_internal.h @@ -0,0 +1,36 @@ +/* + * + * Copyright (C) 2023 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_MEMORY_POOL_INTERNAL_H +#define UMF_MEMORY_POOL_INTERNAL_H 1 + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct umf_memory_pool_t { + void *pool_priv; + struct umf_memory_pool_ops_t ops; + + // Holds array of memory providers. All providers are wrapped + // by memory tracking providers (owned and released by UMF). + umf_memory_provider_handle_t *providers; + + size_t numProviders; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_MEMORY_POOL_INTERNAL_H */ diff --git a/src/memory_provider.c b/src/memory_provider.c new file mode 100644 index 0000000000..4980954c9c --- /dev/null +++ b/src/memory_provider.c @@ -0,0 +1,131 @@ +/* + * + * Copyright (C) 2023 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +#include "memory_provider_internal.h" +#include + +#include +#include + +struct umf_memory_provider_t { + struct umf_memory_provider_ops_t ops; + void *provider_priv; +}; + +enum umf_result_t +umfMemoryProviderCreate(const struct umf_memory_provider_ops_t *ops, + void *params, umf_memory_provider_handle_t *hProvider) { + umf_memory_provider_handle_t provider = + malloc(sizeof(struct umf_memory_provider_t)); + if (!provider) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + assert(ops->version == UMF_VERSION_CURRENT); + + provider->ops = *ops; + + void *provider_priv; + enum umf_result_t ret = ops->initialize(params, &provider_priv); + if (ret != UMF_RESULT_SUCCESS) { + free(provider); + return ret; + } + + provider->provider_priv = provider_priv; + + *hProvider = provider; + + return UMF_RESULT_SUCCESS; +} + +void umfMemoryProviderDestroy(umf_memory_provider_handle_t hProvider) { + hProvider->ops.finalize(hProvider->provider_priv); + free(hProvider); +} + +static void +checkErrorAndSetLastProvider(enum umf_result_t result, + umf_memory_provider_handle_t hProvider) { + if (result != UMF_RESULT_SUCCESS) { + *umfGetLastFailedMemoryProviderPtr() = hProvider; + } +} + +enum umf_result_t umfMemoryProviderAlloc(umf_memory_provider_handle_t hProvider, + size_t size, size_t alignment, + void **ptr) { + enum umf_result_t res = + hProvider->ops.alloc(hProvider->provider_priv, size, alignment, ptr); + checkErrorAndSetLastProvider(res, hProvider); + return res; +} + +enum umf_result_t umfMemoryProviderFree(umf_memory_provider_handle_t hProvider, + void *ptr, size_t size) { + enum umf_result_t res = + hProvider->ops.free(hProvider->provider_priv, ptr, size); + checkErrorAndSetLastProvider(res, hProvider); + return res; +} + +void umfMemoryProviderGetLastNativeError(umf_memory_provider_handle_t hProvider, + const char **ppMessage, + int32_t *pError) { + hProvider->ops.get_last_native_error(hProvider->provider_priv, ppMessage, + pError); +} + +void *umfMemoryProviderGetPriv(umf_memory_provider_handle_t hProvider) { + return hProvider->provider_priv; +} + +enum umf_result_t +umfMemoryProviderGetRecommendedPageSize(umf_memory_provider_handle_t hProvider, + size_t size, size_t *pageSize) { + enum umf_result_t res = hProvider->ops.get_recommended_page_size( + hProvider->provider_priv, size, pageSize); + checkErrorAndSetLastProvider(res, hProvider); + return res; +} + +enum umf_result_t +umfMemoryProviderGetMinPageSize(umf_memory_provider_handle_t hProvider, + void *ptr, size_t *pageSize) { + enum umf_result_t res = hProvider->ops.get_min_page_size( + hProvider->provider_priv, ptr, pageSize); + checkErrorAndSetLastProvider(res, hProvider); + return res; +} + +enum umf_result_t +umfMemoryProviderPurgeLazy(umf_memory_provider_handle_t hProvider, void *ptr, + size_t size) { + enum umf_result_t res = + hProvider->ops.purge_lazy(hProvider->provider_priv, ptr, size); + checkErrorAndSetLastProvider(res, hProvider); + return res; +} + +enum umf_result_t +umfMemoryProviderPurgeForce(umf_memory_provider_handle_t hProvider, void *ptr, + size_t size) { + enum umf_result_t res = + hProvider->ops.purge_force(hProvider->provider_priv, ptr, size); + checkErrorAndSetLastProvider(res, hProvider); + return res; +} + +const char *umfMemoryProviderGetName(umf_memory_provider_handle_t hProvider) { + return hProvider->ops.get_name(hProvider->provider_priv); +} + +umf_memory_provider_handle_t umfGetLastFailedMemoryProvider(void) { + return *umfGetLastFailedMemoryProviderPtr(); +} diff --git a/src/memory_provider_get_last_failed.c b/src/memory_provider_get_last_failed.c new file mode 100644 index 0000000000..119b809d21 --- /dev/null +++ b/src/memory_provider_get_last_failed.c @@ -0,0 +1,22 @@ +/* + * + * Copyright (C) 2023 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +#include "memory_provider_internal.h" + +#ifdef _WIN32 +#define __TLS __declspec(thread) +#else +#define __TLS __thread +#endif + +static __TLS umf_memory_provider_handle_t lastFailedProvider = NULL; + +umf_memory_provider_handle_t *umfGetLastFailedMemoryProviderPtr(void) { + return &lastFailedProvider; +} diff --git a/src/memory_provider_internal.h b/src/memory_provider_internal.h new file mode 100644 index 0000000000..4e858992d0 --- /dev/null +++ b/src/memory_provider_internal.h @@ -0,0 +1,26 @@ +/* + * + * Copyright (C) 2023 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_MEMORY_PROVIDER_INTERNAL_H +#define UMF_MEMORY_PROVIDER_INTERNAL_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *umfMemoryProviderGetPriv(umf_memory_provider_handle_t hProvider); +umf_memory_provider_handle_t *umfGetLastFailedMemoryProviderPtr(void); + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_MEMORY_PROVIDER_INTERNAL_H */ diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000000..2eee1c9396 --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,109 @@ +/* + * + * Copyright (C) 2023 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 +#if defined(_WIN32) +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_mutex_t; + +struct os_mutex_t *util_mutex_create(void); +void util_mutex_destroy(struct os_mutex_t *mutex); +int util_mutex_lock(struct os_mutex_t *mutex); +int util_mutex_unlock(struct os_mutex_t *mutex); + +#if defined(_WIN32) +static __inline unsigned char util_lssb_index(long long value) { + unsigned long ret; + _BitScanForward64(&ret, value); + return (unsigned char)ret; +} +static __inline unsigned char util_mssb_index(long long value) { + unsigned long ret; + _BitScanReverse64(&ret, value); + return (unsigned char)ret; +} + +// There is no good way to do atomic_load on windows... +#define util_atomic_load_acquire(object, dest) \ + do { \ + *dest = InterlockedOr64Acquire((LONG64 volatile *)dest, 0); \ + } while (0) + +#define util_atomic_store_release(object, desired) \ + InterlockedExchange64((LONG64 volatile *)object, (LONG64)desired) +#define util_atomic_increment(object) \ + InterlockedIncrement64((LONG64 volatile *)object) +#else +#define util_lssb_index(x) ((unsigned char)__builtin_ctzll(x)) +#define util_mssb_index(x) ((unsigned char)(63 - __builtin_clzll(x))) +#define util_atomic_load_acquire(object, dest) \ + __atomic_load(object, dest, memory_order_acquire) +#define util_atomic_store_release(object, desired) \ + __atomic_store_n(object, desired, memory_order_release) +#define util_atomic_increment(object) \ + __atomic_add_fetch(object, 1, __ATOMIC_ACQ_REL) +#endif + +#define Malloc malloc +#define Free free + +static inline void *Zalloc(size_t s) { + void *m = Malloc(s); + if (m) { + memset(m, 0, s); + } + return m; +} + +#define NOFUNCTION \ + do { \ + } while (0) +#define VALGRIND_ANNOTATE_NEW_MEMORY(p, s) NOFUNCTION +#define VALGRIND_HG_DRD_DISABLE_CHECKING(p, s) NOFUNCTION + +#ifdef NDEBUG +#define ASSERT(x) NOFUNCTION +#define ASSERTne(x, y) ASSERT(x != y) +#else +#define ASSERT(x) \ + do \ + if (!(x)) { \ + fprintf(stderr, \ + "Assertion failed: " #x " at " __FILE__ " line %d.\n", \ + __LINE__); \ + abort(); \ + } \ + while (0) +#define ASSERTne(x, y) \ + do { \ + long X = (x); \ + long Y = (y); \ + if (X == Y) { \ + fprintf(stderr, \ + "Assertion failed: " #x " != " #y \ + ", both are %ld, at " __FILE__ " line %d.\n", \ + X, __LINE__); \ + abort(); \ + } \ + } while (0) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/utils/utils_posix.c b/src/utils/utils_posix.c new file mode 100644 index 0000000000..e1f701f32e --- /dev/null +++ b/src/utils/utils_posix.c @@ -0,0 +1,34 @@ +/* + * + * Copyright (C) 2023 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 "utils.h" + +struct os_mutex_t *util_mutex_create(void) { + pthread_mutex_t *mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); + int ret = pthread_mutex_init(mutex, NULL); + return ret == 0 ? ((struct os_mutex_t *)mutex) : NULL; +} + +void util_mutex_destroy(struct os_mutex_t *m) { + pthread_mutex_t *mutex = (pthread_mutex_t *)m; + int ret = pthread_mutex_destroy(mutex); + (void)ret; // TODO: add logging + free(m); +} + +int util_mutex_lock(struct os_mutex_t *m) { + return pthread_mutex_lock((pthread_mutex_t *)m); +} + +int util_mutex_unlock(struct os_mutex_t *m) { + return pthread_mutex_unlock((pthread_mutex_t *)m); +} diff --git a/src/utils/utils_windows.c b/src/utils/utils_windows.c new file mode 100644 index 0000000000..98461ccf6f --- /dev/null +++ b/src/utils/utils_windows.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (C) 2023 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +#include "utils.h" + +typedef struct { + CRITICAL_SECTION lock; +} internal_os_mutex_t; + +struct os_mutex_t *util_mutex_create(void) { + internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)calloc(1, sizeof(internal_os_mutex_t)); + InitializeCriticalSection(&mutex_internal->lock); + return (struct os_mutex_t *)mutex_internal; +} + +void util_mutex_destroy(struct os_mutex_t *mutex) { + internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; + DeleteCriticalSection(&mutex_internal->lock); +} + +int util_mutex_lock(struct os_mutex_t *mutex) { + internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; + EnterCriticalSection(&mutex_internal->lock); + + if (mutex_internal->lock.RecursionCount > 1) { + LeaveCriticalSection(&mutex_internal->lock); + /* deadlock detected */ + return -1; + } + return 0; +} + +int util_mutex_unlock(struct os_mutex_t *mutex) { + internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; + LeaveCriticalSection(&mutex_internal->lock); + return 0; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000000..493a150b5f --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2022-2023 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.12.1 +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) +enable_testing() + +set(UMF_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +function(add_umf_test name) + set(TEST_TARGET_NAME umf_test-${name}) + add_umf_executable(${TEST_TARGET_NAME} + ${ARGN}) + target_link_libraries(${TEST_TARGET_NAME} + PRIVATE + ${PROJECT_NAME}::unified_memory_framework + GTest::gtest_main) + target_include_directories(${TEST_TARGET_NAME} PRIVATE + ${UMF_TEST_DIR}/common) + add_test(NAME umf-${name} + COMMAND ${TEST_TARGET_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + set_tests_properties(umf-${name} PROPERTIES LABELS "umf") +endfunction() + +add_umf_test(base base.cpp) diff --git a/test/base.cpp b/test/base.cpp new file mode 100644 index 0000000000..9154cf8bb3 --- /dev/null +++ b/test/base.cpp @@ -0,0 +1,15 @@ +// Copyright (C) 2023 Intel Corporation +// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "base.hpp" + +#include + +using umf_test::test; + +TEST_F(test, versionEncodeDecode) { + auto encoded = UMF_MAKE_VERSION(0, 9); + ASSERT_EQ(UMF_MAJOR_VERSION(encoded), 0); + ASSERT_EQ(UMF_MINOR_VERSION(encoded), 9); +} diff --git a/test/common/base.hpp b/test/common/base.hpp new file mode 100644 index 0000000000..dae07d86a4 --- /dev/null +++ b/test/common/base.hpp @@ -0,0 +1,36 @@ +/* + * + * Copyright (C) 2023 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_TEST_BASE_HPP +#define UMF_TEST_BASE_HPP 1 + +#include + +namespace umf_test { + +#define NOEXCEPT_COND(cond, val, expected_val) \ + try { \ + cond(val, expected_val); \ + } catch ( \ + ...) { /* Silencing possible GoogleTestFailureException throw when gtest flag throw_on_failure is set */ \ + } + +#define EXPECT_EQ_NOEXCEPT(val, expected_val) \ + NOEXCEPT_COND(EXPECT_EQ, val, expected_val) + +#define EXPECT_NE_NOEXCEPT(val, expected_val) \ + NOEXCEPT_COND(EXPECT_NE, val, expected_val) + +struct test : ::testing::Test { + void SetUp() override { ::testing::Test::SetUp(); } + void TearDown() override { ::testing::Test::TearDown(); } +}; +} // namespace umf_test + +#endif /* UMF_TEST_BASE_HPP */