From 4eb9e9c3feb7a9bdb8f44e075c3296498cd00595 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Fri, 11 Aug 2023 15:25:33 +0200 Subject: [PATCH] umf providers --- .../include/umf/memory_provider.h | 33 ++- .../include/umf/memory_provider_ops.h | 6 +- .../src/memory_provider.cpp | 55 +++-- source/common/ur_memory_provider.hpp | 230 ++++++++++++++++++ source/loader/ur_lib.cpp | 16 ++ source/loader/ur_libapi.cpp | 4 +- 6 files changed, 312 insertions(+), 32 deletions(-) create mode 100644 source/common/ur_memory_provider.hpp diff --git a/source/common/unified_malloc_framework/include/umf/memory_provider.h b/source/common/unified_malloc_framework/include/umf/memory_provider.h index 0718c8efb1..9ad0a7dc25 100644 --- a/source/common/unified_malloc_framework/include/umf/memory_provider.h +++ b/source/common/unified_malloc_framework/include/umf/memory_provider.h @@ -20,6 +20,29 @@ extern "C" { typedef struct umf_memory_provider_t *umf_memory_provider_handle_t; +typedef enum umf_device_type_t { + UMF_DEVICE_TYPE_INVALID = -1, + UMF_DEVICE_TYPE_NUMA, + UMF_DEVICE_TYPE_GPU, +} umf_device_type_t; + +typedef struct umf_memory_provider_config_t { + umf_device_type_t type; + + union { + struct { + // TODO + size_t id; + } numa; + + struct { + char address[13]; // in format "0000:00:00.0" + \0 + } gpu; + + // other partition types ... + }; +} umf_memory_provider_config_t; + /// /// \brief Creates new memory provider. /// \param ops instance of umf_memory_provider_ops_t @@ -39,14 +62,12 @@ void umfMemoryProviderDestroy(umf_memory_provider_handle_t hProvider); // TODO comment enum umf_result_t -umfMemoryProviderRegister(struct umf_memory_provider_ops_t *ops); +umfMemoryProviderRegister(umf_device_type_t type, struct umf_memory_provider_ops_t *ops); -enum umf_result_t -umfMemoryProvidersRegistryGet(struct umf_memory_provider_ops_t *providers, - size_t *numProviders); -const struct umf_memory_provider_ops_t * -umfMemoryProvidersRegistryGetOps(char *name); +enum umf_result_t +umfMemoryProvidersCreateFromType(const umf_memory_provider_config_t *config, + umf_memory_provider_handle_t *hProvider /* out */); /// /// \brief Allocates size bytes of uninitialized storage from memory provider diff --git a/source/common/unified_malloc_framework/include/umf/memory_provider_ops.h b/source/common/unified_malloc_framework/include/umf/memory_provider_ops.h index 9a802a2102..3cb1a40ad0 100644 --- a/source/common/unified_malloc_framework/include/umf/memory_provider_ops.h +++ b/source/common/unified_malloc_framework/include/umf/memory_provider_ops.h @@ -18,6 +18,8 @@ extern "C" { #endif +struct umf_memory_provider_config_t; + /// This structure comprises function pointers used by corresponding /// umfMemoryProvider* calls. Each memory provider implementation should /// initialize all function pointers. @@ -26,6 +28,8 @@ struct umf_memory_provider_ops_t { /// Should be initialized using UMF_VERSION_CURRENT uint32_t version; + void *priv; + /// /// \brief Initializes memory provider. /// \param params provider-specific params @@ -51,7 +55,7 @@ struct umf_memory_provider_ops_t { 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); - bool (*supports_device)(const char *name); + bool (*supports_device)(const struct umf_memory_provider_config_t *config); }; #ifdef __cplusplus diff --git a/source/common/unified_malloc_framework/src/memory_provider.cpp b/source/common/unified_malloc_framework/src/memory_provider.cpp index 084c311767..25e44a4b40 100644 --- a/source/common/unified_malloc_framework/src/memory_provider.cpp +++ b/source/common/unified_malloc_framework/src/memory_provider.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -25,7 +26,10 @@ struct umf_memory_provider_t { void *provider_priv; }; -std::vector globalProviders; +// TODO here I use the ptr to vector because the system calls +// globalProviders destructor twice - why? +typedef std::pair umf_provider_desc_pair_t; +std::vector *globalProviders; enum umf_result_t umfMemoryProviderCreate(const struct umf_memory_provider_ops_t *ops, @@ -54,40 +58,45 @@ umfMemoryProviderCreate(const struct umf_memory_provider_ops_t *ops, return UMF_RESULT_SUCCESS; } -enum umf_result_t umfMemoryProviderRegister(umf_memory_provider_ops_t *ops) { +enum umf_result_t umfMemoryProviderRegister(umf_device_type_t type, umf_memory_provider_ops_t *ops) { + + if (globalProviders == NULL) { + // TODO this is never freed + globalProviders = new std::vector; + } // TODO check if this provider isn't already registered - globalProviders.push_back(*ops); + globalProviders->push_back(std::make_pair(type, *ops)); return UMF_RESULT_SUCCESS; } enum umf_result_t -umfMemoryProvidersRegistryGet(umf_memory_provider_ops_t *providers, - size_t *numProviders) { - - if (providers == NULL) { - *numProviders = globalProviders.size(); - } else { - memcpy(providers, globalProviders.data(), - sizeof(umf_memory_provider_ops_t) * *numProviders); - } +umfMemoryProvidersCreateFromType(const umf_memory_provider_config_t *config, + umf_memory_provider_handle_t *hProvider /* out */) { - return UMF_RESULT_SUCCESS; -} + if (config == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } -// TODO rename ;) -const umf_memory_provider_ops_t *umfMemoryProvidersRegistryGetOps(char *name) { - auto it = std::find_if( - std::begin(globalProviders), std::end(globalProviders), - [&](auto &ops) { return std::strcmp(ops.get_name(NULL), name) == 0; }); + if (*hProvider != NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } - if (it != globalProviders.end()) { - return &(*it); + if (globalProviders == NULL) { + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + + for(size_t i = 0; i < globalProviders->size(); i++) { + if (globalProviders->at(i).first == config->type && + globalProviders->at(i).second.supports_device(config)) { + enum umf_result_t ret = umfMemoryProviderCreate(&globalProviders->at(i).second, (void*)config, hProvider); + if (ret == UMF_RESULT_SUCCESS) + return ret; + } } - // else - return NULL; + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } void umfMemoryProviderDestroy(umf_memory_provider_handle_t hProvider) { diff --git a/source/common/ur_memory_provider.hpp b/source/common/ur_memory_provider.hpp new file mode 100644 index 0000000000..b9a006850e --- /dev/null +++ b/source/common/ur_memory_provider.hpp @@ -0,0 +1,230 @@ +/* + Copyright (c) 2023 Intel Corporation + 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ur_api.h" + +typedef struct ur_provider_priv_t +{ + // TODO there will be always single dev per provider instance? + ur_context_handle_t context; + ur_device_handle_t device; + ur_usm_type_t usm_type; +} ur_provider_priv_t; + +enum umf_result_t +ur_initialize(void *params, void **priv_ptr) +{ + urInit(0, 0); + + if (priv_ptr == NULL) + { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (params == NULL) + { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *(struct ur_provider_priv_t **)priv_ptr = (struct ur_provider_priv_t *)malloc( + sizeof(struct ur_provider_priv_t)); + + ur_provider_priv_t *priv = (struct ur_provider_priv_t *)*priv_ptr; + if (priv == NULL) + { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + // TODO + priv->usm_type = UR_USM_TYPE_SHARED; + + // TODO add create from existing context if needed + /* + if (((struct ur_provider_config_t *)params)->context) + { + priv->context = ((struct ur_provider_config_t *)params)->context; + // get the devices list from the context + size_t num_devices = 0; + urContextGetInfo(priv->context, UR_CONTEXT_INFO_NUM_DEVICES, + sizeof(size_t), &num_devices, NULL); + // assume there will be always single device per provider instance + assert(num_devices == 1); // TODO report error + urContextGetInfo(priv->context, UR_CONTEXT_INFO_DEVICES, + sizeof(ur_device_handle_t), &priv->device, NULL); + assert(priv->device != NULL); // TODO report error + + return UMF_RESULT_SUCCESS; + } + */ + + + // NOTE: we browse all platforms here because right now + // there is a single UR provider for all platforms + + uint32_t adapterCount = 0; + urAdapterGet(0, NULL, &adapterCount); + ur_adapter_handle_t *adapters = (ur_adapter_handle_t *)malloc(sizeof(ur_adapter_handle_t) * adapterCount); + urAdapterGet(adapterCount, adapters, NULL); + + uint32_t platformCount = 0; + urPlatformGet(adapters, adapterCount, 1, NULL, &platformCount); + ur_platform_handle_t *platforms = (ur_platform_handle_t *)malloc(sizeof(ur_platform_handle_t) * platformCount); + urPlatformGet(adapters, adapterCount, platformCount, platforms, NULL); + + for (size_t pid = 0; pid < platformCount; pid++) + { + uint32_t deviceCount = 0; + urDeviceGet(platforms[pid], UR_DEVICE_TYPE_GPU, 0, NULL, &deviceCount); + ur_device_handle_t *devices = (ur_device_handle_t *)malloc(sizeof(ur_device_handle_t) * deviceCount); + urDeviceGet(platforms[pid], UR_DEVICE_TYPE_GPU, deviceCount, devices, + NULL); + + for (size_t did = 0; did < deviceCount; did++) + { + static const size_t DEVICE_INFO_MAX_LEN = 1024; + + char *device_pci = (char *)malloc(DEVICE_INFO_MAX_LEN); + memset(device_pci, 0, DEVICE_INFO_MAX_LEN); + urDeviceGetInfo(devices[did], UR_DEVICE_INFO_PCI_ADDRESS, DEVICE_INFO_MAX_LEN - 1, + device_pci, NULL); + + if (strcmp(((struct umf_memory_provider_config_t *)params)->gpu.address, device_pci) == 0) + { + ur_context_handle_t ctx = NULL; + urContextCreate(1, &devices[did], NULL, &ctx); + priv->context = ctx; + priv->device = devices[did]; + + free(device_pci); + return UMF_RESULT_SUCCESS; + } + } + } + + // else + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; +} + +void ur_finalize(void *provider) { free(provider); } + +static enum umf_result_t ur_alloc(void *provider, size_t size, size_t alignment, + void **resultPtr) +{ + struct ur_provider_priv_t *config = (struct ur_provider_priv_t *)provider; + enum umf_result_t result = UMF_RESULT_SUCCESS; + + // TODO check errors + assert(config->context); + + switch (config->usm_type) + { + case UR_USM_TYPE_HOST: + // TODO ur_usm_desc_t + urUSMHostAlloc(config->context, NULL, NULL, size, resultPtr); + break; + case UR_USM_TYPE_DEVICE: + urUSMDeviceAlloc(config->context, config->device, NULL, NULL, size, + resultPtr); + break; + case UR_USM_TYPE_SHARED: + urUSMSharedAlloc(config->context, config->device, NULL, NULL, size, + resultPtr); + break; + default: + assert(0); + } + + return result; +} + +static enum umf_result_t ur_free(void *provider, void *ptr, size_t size) +{ + struct ur_provider_priv_t *config = (struct ur_provider_priv_t *)provider; + + // TODO check errors + urUSMFree(config->context, ptr); + + // TODO - size? + + return UMF_RESULT_SUCCESS; +} + +void ur_get_last_native_error(void *provider, const char **ppMessage, + int32_t *pError) +{ + // TODO +} + +enum umf_result_t ur_get_min_page_size(void *provider, void *ptr, + size_t *pageSize) +{ + *pageSize = 1024; // TODO call urVirtualMemGranularityGetInfo here + return UMF_RESULT_SUCCESS; +} + +const char *ur_get_name(void *provider) { return "USM"; } + +bool ur_supports_device(const struct umf_memory_provider_config_t *config) +{ + if (config->type != UMF_DEVICE_TYPE_GPU) + return false; + + urInit(0, 0); + + uint32_t adapterCount = 0; + urAdapterGet(0, NULL, &adapterCount); + ur_adapter_handle_t *adapters = (ur_adapter_handle_t *)malloc(sizeof(ur_adapter_handle_t) * adapterCount); + urAdapterGet(adapterCount, adapters, NULL); + + uint32_t platformCount = 0; + urPlatformGet(adapters, adapterCount, 1, NULL, &platformCount); + ur_platform_handle_t *platforms = (ur_platform_handle_t *)malloc(sizeof(ur_platform_handle_t) * platformCount); + urPlatformGet(adapters, adapterCount, platformCount, platforms, NULL); + + for (uint32_t pid = 0; pid < platformCount; pid++) + { + uint32_t deviceCount = 0; + urDeviceGet(platforms[pid], UR_DEVICE_TYPE_GPU, 0, NULL, &deviceCount); + ur_device_handle_t *devices = (ur_device_handle_t *)malloc(sizeof(ur_device_handle_t) * deviceCount); + urDeviceGet(platforms[pid], UR_DEVICE_TYPE_GPU, deviceCount, devices, + NULL); + + for (uint32_t did = 0; did < deviceCount; did++) + { + static const size_t DEVICE_INFO_MAX_LEN = 1024; + + // TODO this should check the name (class) not, the pci (context) + char *device_pci = (char *)malloc(DEVICE_INFO_MAX_LEN); + memset(device_pci, 0, DEVICE_INFO_MAX_LEN); + urDeviceGetInfo(devices[did], UR_DEVICE_INFO_PCI_ADDRESS, DEVICE_INFO_MAX_LEN - 1, + device_pci, NULL); + + if (strncmp(config->gpu.address, device_pci, sizeof(config->gpu.address)) == 0) + return true; + } + } + + // no match + return false; +} diff --git a/source/loader/ur_lib.cpp b/source/loader/ur_lib.cpp index 964da234f1..4a736490de 100644 --- a/source/loader/ur_lib.cpp +++ b/source/loader/ur_lib.cpp @@ -13,6 +13,8 @@ #include "logger/ur_logger.hpp" #include "ur_loader.hpp" +#include "ur_memory_provider.hpp" + #include namespace ur_lib { @@ -75,6 +77,20 @@ context_t::Init(ur_device_init_flags_t device_flags, result = urInit(); } + umf_memory_provider_ops_t ur_memory_provider_ops = { + .version = UMF_VERSION_CURRENT, + .initialize = ur_initialize, + .finalize = ur_finalize, + .alloc = ur_alloc, + .free = ur_free, + .get_last_native_error = ur_get_last_native_error, + .get_min_page_size = ur_get_min_page_size, + .get_name = ur_get_name, + .supports_device = ur_supports_device, + }; + + umfMemoryProviderRegister(UMF_DEVICE_TYPE_GPU, &ur_memory_provider_ops); + if (hLoaderConfig) { enabledLayerNames.merge(hLoaderConfig->getEnabledLayerNames()); } diff --git a/source/loader/ur_libapi.cpp b/source/loader/ur_libapi.cpp index 9c7060fdbe..86ca5331ca 100644 --- a/source/loader/ur_libapi.cpp +++ b/source/loader/ur_libapi.cpp @@ -2120,8 +2120,8 @@ ur_result_t UR_APICALL urUSMHostAlloc( size_t size, ///< [in] size in bytes of the USM memory object to be allocated void **ppMem ///< [out] pointer to USM host memory object - ) try { - auto pfnHostAlloc = ur_lib::context->urDdiTable.USM.pfnHostAlloc; + ) try { + auto pfnHostAlloc = ur_lib::context->urDdiTable.USM.pfnHostAlloc; if (nullptr == pfnHostAlloc) { return UR_RESULT_ERROR_UNINITIALIZED; }