diff --git a/level_zero/api/driver_experimental/public/zex_memory.cpp b/level_zero/api/driver_experimental/public/zex_memory.cpp index 8dd983d83d..f55b2289d1 100644 --- a/level_zero/api/driver_experimental/public/zex_memory.cpp +++ b/level_zero/api/driver_experimental/public/zex_memory.cpp @@ -7,3 +7,23 @@ #include "level_zero/api/driver_experimental/public/zex_api.h" #include "level_zero/core/source/context/context.h" + +ZE_APIEXPORT ze_result_t ZE_APICALL +zexMemGetIpcHandles( + ze_context_handle_t hContext, + const void *ptr, + uint32_t *numIpcHandles, + ze_ipc_mem_handle_t *pIpcHandles) { + return L0::Context::fromHandle(hContext)->getIpcMemHandles(ptr, numIpcHandles, pIpcHandles); +} + +ZE_APIEXPORT ze_result_t ZE_APICALL +zexMemOpenIpcHandles( + ze_context_handle_t hContext, + ze_device_handle_t hDevice, + uint32_t numIpcHandles, + ze_ipc_mem_handle_t *pIpcHandles, + ze_ipc_memory_flags_t flags, + void **pptr) { + return L0::Context::fromHandle(hContext)->openIpcMemHandles(hDevice, numIpcHandles, pIpcHandles, flags, pptr); +} \ No newline at end of file diff --git a/level_zero/api/driver_experimental/public/zex_memory.h b/level_zero/api/driver_experimental/public/zex_memory.h index c7245c7a4f..77d34e8647 100644 --- a/level_zero/api/driver_experimental/public/zex_memory.h +++ b/level_zero/api/driver_experimental/public/zex_memory.h @@ -17,6 +17,71 @@ extern "C" { #include "level_zero/api/driver_experimental/public/zex_api.h" +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZEX_MEM_IPC_HANDLES_NAME +/// @brief Multiple IPC handles driver extension name +#define ZEX_MEM_IPC_HANDLES_NAME "ZEX_mem_ipc_handles" +#endif // ZEX_MEM_IPC_HANDLES_NAME + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Multiple IPC handles driver extension Version(s) +typedef enum _zex_mem_ipc_handles_version_t { + ZEX_MEM_IPC_HANDLES_VERSION_1_0 = ZE_MAKE_VERSION(1, 0), ///< version 1.0 + ZEX_MEM_IPC_HANDLES_VERSION_CURRENT = ZE_MAKE_VERSION(1, 0), ///< latest known version + ZEX_MEM_IPC_HANDLES_VERSION_FORCE_UINT32 = 0x7fffffff + +} zex_mem_ipc_handles_version_t; + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Returns an array IPC memory handles for the specified allocation +/// +/// @details +/// - Takes a pointer to a device memory allocation and returns an array of +// IPC memory handle for exporting it for use in another process. +/// - The application may call this function from simultaneous threads. +/// - The implementation of this function must be thread-safe. +/// +/// @returns +/// - ::ZE_RESULT_SUCCESS +/// - ::ZE_RESULT_ERROR_INVALID_ARGUMENT +/// + `ptr` not known +ZE_APIEXPORT ze_result_t ZE_APICALL +zexMemGetIpcHandles( + ze_context_handle_t hContext, ///< [in] handle of the context object + const void *ptr, ///< [in] pointer to the device memory allocation + uint32_t *numIpcHandles, ///< [in,out] number of IPC handles associated with the allocation + ///< if numIpcHandles is zero, then the driver shall update the value with the + ///< total number of IPC handles associated with the allocation. + ze_ipc_mem_handle_t *pIpcHandles ///< [in,out][optional][range(0, *numIpcHandles)] returned array of IPC memory handles +); + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Creates an allocation associated with an array of IPC memory handles +/// imported from another process. +/// +/// @details +/// - Takes an array of IPC memory handles from a remote process and associates it +/// with a device pointer usable in this process. +/// - The device pointer in this process should not be freed with +/// ::zeMemFree, but rather with ::zeMemCloseIpcHandle. +/// - The application may call this function from simultaneous threads. +/// - The implementation of this function must be thread-safe. +/// +/// @returns +/// - ::ZE_RESULT_SUCCESS +/// - ::ZE_RESULT_ERROR_INVALID_ARGUMENT +/// + handles not known +ZE_APIEXPORT ze_result_t ZE_APICALL +zexMemOpenIpcHandles( + ze_context_handle_t hContext, ///< [in] handle of the context object + ze_device_handle_t hDevice, ///< [in] handle of the device to associate with the IPC memory handle + uint32_t numIpcHandles, ///< [in] number of IPC handles associated with the allocation + ze_ipc_mem_handle_t *pIpcHandles, ///< [in][range(0, *numIpcHandles)] array of IPC memory handles + ze_ipc_memory_flags_t flags, ///< [in] flags controlling the operation. + ///< must be 0 (default) or a valid combination of ::ze_ipc_memory_flag_t. + void **pptr ///< [out] pointer to device allocation in this process +); + #if defined(__cplusplus) } // extern "C" #endif diff --git a/level_zero/api/extensions/public/ze_exp_ext.h b/level_zero/api/extensions/public/ze_exp_ext.h index 8a967d23be..613b0e1adc 100644 --- a/level_zero/api/extensions/public/ze_exp_ext.h +++ b/level_zero/api/extensions/public/ze_exp_ext.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2022 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -8,3 +8,11 @@ #pragma once #include + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__cplusplus) +} // extern "C" +#endif diff --git a/level_zero/core/source/context/context.h b/level_zero/core/source/context/context.h index b5f12a5fb8..64396901f0 100644 --- a/level_zero/core/source/context/context.h +++ b/level_zero/core/source/context/context.h @@ -71,6 +71,20 @@ struct Context : _ze_context_handle_t { virtual ze_result_t closeIpcMemHandle(const void *ptr) = 0; virtual ze_result_t getIpcMemHandle(const void *ptr, ze_ipc_mem_handle_t *pIpcHandle) = 0; + virtual ze_result_t + getIpcMemHandles( + const void *ptr, + uint32_t *numIpcHandles, + ze_ipc_mem_handle_t *pIpcHandles) = 0; + + virtual ze_result_t + openIpcMemHandles( + ze_device_handle_t hDevice, + uint32_t numIpcHandles, + ze_ipc_mem_handle_t *pIpcHandles, + ze_ipc_memory_flags_t flags, + void **pptr) = 0; + virtual ze_result_t openIpcMemHandle(ze_device_handle_t hDevice, ze_ipc_mem_handle_t handle, ze_ipc_memory_flags_t flags, diff --git a/level_zero/core/source/context/context_imp.cpp b/level_zero/core/source/context/context_imp.cpp index 5f518c5298..6503aa7241 100644 --- a/level_zero/core/source/context/context_imp.cpp +++ b/level_zero/core/source/context/context_imp.cpp @@ -429,6 +429,31 @@ ze_result_t ContextImp::getIpcMemHandle(const void *ptr, return ZE_RESULT_ERROR_INVALID_ARGUMENT; } +ze_result_t ContextImp::getIpcMemHandles(const void *ptr, + uint32_t *numIpcHandles, + ze_ipc_mem_handle_t *pIpcHandles) { + NEO::SvmAllocationData *allocData = this->driverHandle->svmAllocsManager->getSVMAlloc(ptr); + if (allocData) { + auto alloc = allocData->gpuAllocations.getDefaultGraphicsAllocation(); + uint32_t numHandles = alloc->getNumHandles(); + if (pIpcHandles == nullptr) { + *numIpcHandles = numHandles; + return ZE_RESULT_SUCCESS; + } + + for (uint32_t i = 0; i < numHandles; i++) { + int handle = static_cast(allocData->gpuAllocations.getDefaultGraphicsAllocation()->peekInternalHandle(this->driverHandle->getMemoryManager(), i)); + memcpy_s(reinterpret_cast(pIpcHandles[i].data), + sizeof(ze_ipc_mem_handle_t), + &handle, + sizeof(handle)); + } + + return ZE_RESULT_SUCCESS; + } + return ZE_RESULT_ERROR_INVALID_ARGUMENT; +} + ze_result_t ContextImp::openIpcMemHandle(ze_device_handle_t hDevice, ze_ipc_mem_handle_t pIpcHandle, ze_ipc_memory_flags_t flags, @@ -447,6 +472,29 @@ ze_result_t ContextImp::openIpcMemHandle(ze_device_handle_t hDevice, return ZE_RESULT_SUCCESS; } +ze_result_t ContextImp::openIpcMemHandles(ze_device_handle_t hDevice, + uint32_t numIpcHandles, + ze_ipc_mem_handle_t *pIpcHandles, + ze_ipc_memory_flags_t flags, + void **pptr) { + std::vector handles; + for (uint32_t i = 0; i < numIpcHandles; i++) { + uint64_t handle = 0; + memcpy_s(&handle, + sizeof(handle), + reinterpret_cast(pIpcHandles[i].data), + sizeof(handle)); + handles.push_back(static_cast(handle)); + } + + *pptr = this->driverHandle->importFdHandles(hDevice, flags, handles, nullptr); + if (nullptr == *pptr) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + + return ZE_RESULT_SUCCESS; +} + ze_result_t EventPoolImp::closeIpcHandle() { return this->destroy(); } diff --git a/level_zero/core/source/context/context_imp.h b/level_zero/core/source/context/context_imp.h index 81a945cb9d..e144835372 100644 --- a/level_zero/core/source/context/context_imp.h +++ b/level_zero/core/source/context/context_imp.h @@ -57,6 +57,21 @@ struct ContextImp : Context { ze_ipc_mem_handle_t handle, ze_ipc_memory_flags_t flags, void **ptr) override; + + ze_result_t + getIpcMemHandles( + const void *ptr, + uint32_t *numIpcHandles, + ze_ipc_mem_handle_t *pIpcHandles) override; + + ze_result_t + openIpcMemHandles( + ze_device_handle_t hDevice, + uint32_t numIpcHandles, + ze_ipc_mem_handle_t *pIpcHandles, + ze_ipc_memory_flags_t flags, + void **pptr) override; + ze_result_t getMemAllocProperties(const void *ptr, ze_memory_allocation_properties_t *pMemAllocProperties, ze_device_handle_t *phDevice) override; diff --git a/level_zero/core/source/driver/driver_handle_imp.cpp b/level_zero/core/source/driver/driver_handle_imp.cpp index afe9d87e6f..8408e7f9e8 100644 --- a/level_zero/core/source/driver/driver_handle_imp.cpp +++ b/level_zero/core/source/driver/driver_handle_imp.cpp @@ -459,6 +459,46 @@ void *DriverHandleImp::importFdHandle(ze_device_handle_t hDevice, ze_ipc_memory_ return reinterpret_cast(alloc->getGpuAddress()); } +void *DriverHandleImp::importFdHandles(ze_device_handle_t hDevice, ze_ipc_memory_flags_t flags, std::vector handles, NEO::GraphicsAllocation **pAlloc) { + auto neoDevice = Device::fromHandle(hDevice)->getNEODevice(); + NEO::AllocationProperties unifiedMemoryProperties{neoDevice->getRootDeviceIndex(), + MemoryConstants::pageSize, + NEO::AllocationType::BUFFER, + neoDevice->getDeviceBitfield()}; + unifiedMemoryProperties.subDevicesBitfield = neoDevice->getDeviceBitfield(); + + NEO::GraphicsAllocation *alloc = + this->getMemoryManager()->createGraphicsAllocationFromMultipleSharedHandles(handles, + unifiedMemoryProperties, + false, + false); + if (alloc == nullptr) { + return nullptr; + } + + NEO::SvmAllocationData allocData(neoDevice->getRootDeviceIndex()); + allocData.gpuAllocations.addAllocation(alloc); + allocData.cpuAllocation = nullptr; + allocData.size = alloc->getUnderlyingBufferSize(); + allocData.memoryType = InternalMemoryType::DEVICE_UNIFIED_MEMORY; + allocData.device = neoDevice; + if (flags & ZE_DEVICE_MEM_ALLOC_FLAG_BIAS_UNCACHED) { + allocData.allocationFlagsProperty.flags.locallyUncachedResource = 1; + } + + if (flags & ZE_IPC_MEMORY_FLAG_BIAS_UNCACHED) { + allocData.allocationFlagsProperty.flags.locallyUncachedResource = 1; + } + + this->getSvmAllocsManager()->insertSVMAlloc(allocData); + + if (pAlloc) { + *pAlloc = alloc; + } + + return reinterpret_cast(alloc->getGpuAddress()); +} + NEO::GraphicsAllocation *DriverHandleImp::getPeerAllocation(Device *device, NEO::SvmAllocationData *allocData, void *basePtr, diff --git a/level_zero/core/source/driver/driver_handle_imp.h b/level_zero/core/source/driver/driver_handle_imp.h index 417ade8f0c..87f50c4dfc 100644 --- a/level_zero/core/source/driver/driver_handle_imp.h +++ b/level_zero/core/source/driver/driver_handle_imp.h @@ -35,6 +35,7 @@ struct DriverHandleImp : public DriverHandle { NEO::MemoryManager *getMemoryManager() override; void setMemoryManager(NEO::MemoryManager *memoryManager) override; MOCKABLE_VIRTUAL void *importFdHandle(ze_device_handle_t hDevice, ze_ipc_memory_flags_t flags, uint64_t handle, NEO::GraphicsAllocation **pAlloc); + MOCKABLE_VIRTUAL void *importFdHandles(ze_device_handle_t hDevice, ze_ipc_memory_flags_t flags, std::vector handles, NEO::GraphicsAllocation **pAlloc); MOCKABLE_VIRTUAL void *importNTHandle(ze_device_handle_t hDevice, void *handle); ze_result_t checkMemoryAccessFromDevice(Device *device, const void *ptr) override; NEO::SVMAllocsManager *getSvmAllocsManager() override; diff --git a/level_zero/core/source/get_extension_function_lookup_map.cpp b/level_zero/core/source/get_extension_function_lookup_map.cpp index 5c738e9478..023d927f4c 100644 --- a/level_zero/core/source/get_extension_function_lookup_map.cpp +++ b/level_zero/core/source/get_extension_function_lookup_map.cpp @@ -19,6 +19,9 @@ std::unordered_map getExtensionFunctionsLookupMap() { addToMap(lookupMap, zexDriverGetHostPointerBaseAddress); addToMap(lookupMap, zexKernelGetBaseAddress); + + addToMap(lookupMap, zexMemGetIpcHandles); + addToMap(lookupMap, zexMemOpenIpcHandles); #undef addToMap return lookupMap; diff --git a/level_zero/core/test/black_box_tests/zello_ipc_copy_dma_buf.cpp b/level_zero/core/test/black_box_tests/zello_ipc_copy_dma_buf.cpp index 9814a368c9..00224240b5 100644 --- a/level_zero/core/test/black_box_tests/zello_ipc_copy_dma_buf.cpp +++ b/level_zero/core/test/black_box_tests/zello_ipc_copy_dma_buf.cpp @@ -18,65 +18,59 @@ int sv[CHILDPROCESSES][2]; extern bool verbose; bool verbose = false; -size_t allocSize = 4096 + 7; // +7 to break alignment and make it harder +size_t allocSize = 131072 + 7; // +7 to break alignment and make it harder -static int sendmsg_fd(int socket, int fd) { - char sendBuf[sizeof(ze_ipc_mem_handle_t)] = {}; - char cmsgBuf[CMSG_SPACE(sizeof(ze_ipc_mem_handle_t))]; +static int sendmsgForIpcHandle(int socket, int fd, char *payload) { + char sendBuf[ZE_MAX_IPC_HANDLE_SIZE] = {}; + memcpy(sendBuf, payload, sizeof(sendBuf)); + char cmsgBuf[CMSG_SPACE(ZE_MAX_IPC_HANDLE_SIZE)]; - struct iovec msgBuffer; + struct iovec msgBuffer = {}; msgBuffer.iov_base = sendBuf; - msgBuffer.iov_len = sizeof(*sendBuf); + msgBuffer.iov_len = ZE_MAX_IPC_HANDLE_SIZE; struct msghdr msgHeader = {}; msgHeader.msg_iov = &msgBuffer; msgHeader.msg_iovlen = 1; msgHeader.msg_control = cmsgBuf; msgHeader.msg_controllen = CMSG_LEN(sizeof(fd)); - struct cmsghdr *controlHeader = CMSG_FIRSTHDR(&msgHeader); controlHeader->cmsg_type = SCM_RIGHTS; controlHeader->cmsg_level = SOL_SOCKET; controlHeader->cmsg_len = CMSG_LEN(sizeof(fd)); - *(int *)CMSG_DATA(controlHeader) = fd; ssize_t bytesSent = sendmsg(socket, &msgHeader, 0); if (bytesSent < 0) { + std::cerr << "Error on sendmsgForIpcHandle " << strerror(errno) << "\n"; return -1; } - return 0; } - -static int recvmsg_fd(int socket) { +static int recvmsgForIpcHandle(int socket, char *payload) { int fd = -1; - char recvBuf[sizeof(ze_ipc_mem_handle_t)] = {}; - char cmsgBuf[CMSG_SPACE(sizeof(ze_ipc_mem_handle_t))]; - + char recvBuf[ZE_MAX_IPC_HANDLE_SIZE] = {}; + char cmsgBuf[CMSG_SPACE(ZE_MAX_IPC_HANDLE_SIZE)]; struct iovec msgBuffer; msgBuffer.iov_base = recvBuf; - msgBuffer.iov_len = sizeof(recvBuf); - + msgBuffer.iov_len = ZE_MAX_IPC_HANDLE_SIZE; struct msghdr msgHeader = {}; msgHeader.msg_iov = &msgBuffer; msgHeader.msg_iovlen = 1; msgHeader.msg_control = cmsgBuf; msgHeader.msg_controllen = CMSG_LEN(sizeof(fd)); - ssize_t bytesSent = recvmsg(socket, &msgHeader, 0); if (bytesSent < 0) { + std::cerr << "Error on recvmsgForIpcHandle " << strerror(errno) << "\n"; return -1; } - struct cmsghdr *controlHeader = CMSG_FIRSTHDR(&msgHeader); - if (!CMSG_DATA(controlHeader)) { - return -1; - } memmove(&fd, CMSG_DATA(controlHeader), sizeof(int)); + memmove(payload, recvBuf, sizeof(recvBuf)); return fd; } -inline void initializeProcess(ze_context_handle_t &context, +inline void initializeProcess(ze_driver_handle_t &driverHandle, + ze_context_handle_t &context, ze_device_handle_t &device, ze_command_queue_handle_t &cmdQueue, ze_command_list_handle_t &cmdList) { @@ -86,7 +80,6 @@ inline void initializeProcess(ze_context_handle_t &context, uint32_t driverCount = 0; SUCCESS_OR_TERMINATE(zeDriverGet(&driverCount, nullptr)); - ze_driver_handle_t driverHandle; SUCCESS_OR_TERMINATE(zeDriverGet(&driverCount, &driverHandle)); ze_context_desc_t contextDesc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC}; @@ -137,33 +130,63 @@ inline void initializeProcess(ze_context_handle_t &context, SUCCESS_OR_TERMINATE(zeCommandListCreate(context, device, &cmdListDesc, &cmdList)); } +typedef ze_result_t (*pFnzexMemGetIpcHandle)(ze_context_handle_t, const void *, uint32_t *, ze_ipc_mem_handle_t *); +typedef ze_result_t (*pFnzexMemOpenIpcHandle)(ze_context_handle_t, ze_device_handle_t, uint32_t, ze_ipc_mem_handle_t *, ze_ipc_memory_flags_t, void **); + void run_client(int commSocket, uint32_t clientId) { std::cout << "Client " << clientId << ", process ID: " << std::dec << getpid() << "\n"; + ze_driver_handle_t driverHandle; ze_context_handle_t context; ze_device_handle_t device; ze_command_queue_handle_t cmdQueue; ze_command_list_handle_t cmdList; - initializeProcess(context, device, cmdQueue, cmdList); + initializeProcess(driverHandle, context, device, cmdQueue, cmdList); char *heapBuffer = new char[allocSize]; for (size_t i = 0; i < allocSize; ++i) { heapBuffer[i] = static_cast(i + 1); } - // get the dma_buf from the other process - int dma_buf_fd = recvmsg_fd(commSocket); - if (dma_buf_fd < 0) { - std::cerr << "Failing to get dma_buf fd from server\n"; + pFnzexMemOpenIpcHandle zexMemOpenIpcHandlePointer = nullptr; + SUCCESS_OR_TERMINATE(zeDriverGetExtensionFunctionAddress(driverHandle, "zexMemOpenIpcHandles", reinterpret_cast(&zexMemOpenIpcHandlePointer))); + + // receive the IPC handle for the memory from the other process + std::vector pIpcHandles; + + char payload[ZE_MAX_IPC_HANDLE_SIZE]; + int handle = recvmsgForIpcHandle(commSocket, payload); + if (handle < 0) { + std::cerr << "Failing to get IPC memory handle from server\n"; std::terminate(); } - ze_ipc_mem_handle_t pIpcHandle; - memcpy(&pIpcHandle, static_cast(&dma_buf_fd), sizeof(dma_buf_fd)); - // get a memory pointer to the BO associated with the dma_buf + // check for the number of ipc (dma-buf) handles sent in the payload + uint32_t numIpcHandles = 0; + memcpy(&numIpcHandles, static_cast(&payload), sizeof(numIpcHandles)); + if (numIpcHandles == 0) { + std::cerr << "numIpcHandles is zero\n"; + std::terminate(); + } + + // get first handle + pIpcHandles.resize(numIpcHandles); + memcpy(pIpcHandles[0].data, static_cast(&handle), sizeof(handle)); + + // get rest of handles + for (uint32_t h = 1; h < numIpcHandles; h++) { + int handle = recvmsgForIpcHandle(commSocket, payload); + if (handle < 0) { + std::cerr << "Failing to get IPC memory handle from server\n"; + std::terminate(); + } + memcpy(pIpcHandles[h].data, static_cast(&handle), sizeof(handle)); + } + + // get a memory pointer to the BO associated with the dma_buf handles void *zeIpcBuffer; - SUCCESS_OR_TERMINATE(zeMemOpenIpcHandle(context, device, pIpcHandle, - 0u, &zeIpcBuffer)); + SUCCESS_OR_TERMINATE(zexMemOpenIpcHandlePointer(context, device, numIpcHandles, pIpcHandles.data(), 0u, &zeIpcBuffer)); + // Copy from heap to IPC buffer memory SUCCESS_OR_TERMINATE(zeCommandListAppendMemoryCopy(cmdList, zeIpcBuffer, heapBuffer, allocSize, nullptr, 0, nullptr)); @@ -182,11 +205,12 @@ void run_client(int commSocket, uint32_t clientId) { void run_server(bool &validRet) { std::cout << "Server process ID " << std::dec << getpid() << "\n"; + ze_driver_handle_t driverHandle; ze_context_handle_t context; ze_device_handle_t device; ze_command_queue_handle_t cmdQueue; ze_command_list_handle_t cmdList; - initializeProcess(context, device, cmdQueue, cmdList); + initializeProcess(driverHandle, context, device, cmdQueue, cmdList); void *zeBuffer = nullptr; ze_device_mem_alloc_desc_t deviceDesc = {ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC}; @@ -203,19 +227,39 @@ void run_server(bool &validRet) { SUCCESS_OR_TERMINATE(zeCommandQueueSynchronize(cmdQueue, std::numeric_limits::max())); SUCCESS_OR_TERMINATE(zeCommandListReset(cmdList)); - // Get a dma_buf for the previously allocated pointer - ze_ipc_mem_handle_t pIpcHandle; - SUCCESS_OR_TERMINATE(zeMemGetIpcHandle(context, zeBuffer, &pIpcHandle)); + // Get the IPC handles for the previously allocated pointer + pFnzexMemGetIpcHandle zexMemGetIpcHandlePointer = nullptr; + SUCCESS_OR_TERMINATE(zeDriverGetExtensionFunctionAddress(driverHandle, "zexMemGetIpcHandles", reinterpret_cast(&zexMemGetIpcHandlePointer))); - // Pass the dma_buf to the other process - int dma_buf_fd; - memcpy(static_cast(&dma_buf_fd), &pIpcHandle, sizeof(dma_buf_fd)); - int commSocket = sv[i][0]; - if (sendmsg_fd(commSocket, static_cast(dma_buf_fd)) < 0) { - std::cerr << "Failing to send dma_buf fd to client\n"; + std::vector pIpcHandles; + + // get the number of ipc handles associated with the allocation + uint32_t numIpcHandles = 0; + SUCCESS_OR_TERMINATE(zexMemGetIpcHandlePointer(context, zeBuffer, &numIpcHandles, nullptr)); + if (numIpcHandles == 0) { + std::cerr << "numIpcHandles is zero\n"; std::terminate(); } + // get the handles + pIpcHandles.resize(numIpcHandles); + SUCCESS_OR_TERMINATE(zexMemGetIpcHandlePointer(context, zeBuffer, &numIpcHandles, pIpcHandles.data())); + + // copy the number of ipc handles to the payload, then transmit each handle to the client + char payload[ZE_MAX_IPC_HANDLE_SIZE]; + memcpy(static_cast(&payload), &numIpcHandles, sizeof(numIpcHandles)); + for (uint32_t h = 0; h < numIpcHandles; h++) { + int commSocket = sv[i][0]; + int handle = 0; + memcpy(static_cast(&handle), &pIpcHandles[h].data, sizeof(handle)); + + int ret = sendmsgForIpcHandle(commSocket, handle, payload); + if (ret < 0) { + std::cerr << "Failing to send IPC memory handle to client\n"; + std::terminate(); + } + } + char *heapBuffer = new char[allocSize]; for (size_t i = 0; i < allocSize; ++i) { heapBuffer[i] = static_cast(i + 1); @@ -248,6 +292,14 @@ void run_server(bool &validRet) { SUCCESS_OR_TERMINATE(zeCommandQueueExecuteCommandLists(cmdQueue, 1, &cmdList, nullptr)); SUCCESS_OR_TERMINATE(zeCommandQueueSynchronize(cmdQueue, std::numeric_limits::max())); + char *ipcBuffer = static_cast(validateBuffer); + for (uint32_t h = 0; h < allocSize; h++) { + if (static_cast(ipcBuffer[h]) != static_cast(heapBuffer[h])) { + printf("Error: ipcBuffer %d %d, heapBuffer %d\n", h, static_cast(ipcBuffer[h]), heapBuffer[h]); + break; + } + } + // Validate stack and buffers have the original data from heapBuffer validRet = (0 == memcmp(heapBuffer, validateBuffer, allocSize)); delete[] heapBuffer; diff --git a/level_zero/core/test/unit_tests/fixtures/memory_ipc_fixture.h b/level_zero/core/test/unit_tests/fixtures/memory_ipc_fixture.h index fb1393d57b..250c92e1cb 100644 --- a/level_zero/core/test/unit_tests/fixtures/memory_ipc_fixture.h +++ b/level_zero/core/test/unit_tests/fixtures/memory_ipc_fixture.h @@ -384,6 +384,7 @@ struct ContextGetIpcHandleMock : public L0::ContextImp { class MemoryManagerIpcMock : public NEO::MemoryManager { public: MemoryManagerIpcMock(NEO::ExecutionEnvironment &executionEnvironment) : NEO::MemoryManager(executionEnvironment) {} + NEO::GraphicsAllocation *createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { return nullptr; } NEO::GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { return nullptr; } void addAllocationToHostPtrManager(NEO::GraphicsAllocation *memory) override{}; void removeAllocationFromHostPtrManager(NEO::GraphicsAllocation *memory) override{}; @@ -414,20 +415,63 @@ class MemoryManagerIpcMock : public NEO::MemoryManager { void unlockResourceImpl(NEO::GraphicsAllocation &graphicsAllocation) override{}; }; +class IpcImplicitScalingMockGraphicsAllocation : public NEO::MemoryAllocation { + public: + using MemoryAllocation::allocationOffset; + using MemoryAllocation::allocationType; + using MemoryAllocation::aubInfo; + using MemoryAllocation::gpuAddress; + using MemoryAllocation::MemoryAllocation; + using MemoryAllocation::memoryPool; + using MemoryAllocation::objectNotResident; + using MemoryAllocation::objectNotUsed; + using MemoryAllocation::size; + using MemoryAllocation::usageInfos; + + IpcImplicitScalingMockGraphicsAllocation() + : NEO::MemoryAllocation(0, AllocationType::UNKNOWN, nullptr, 0u, 0, MemoryPool::MemoryNull, MemoryManager::maxOsContextCount) {} + + IpcImplicitScalingMockGraphicsAllocation(void *buffer, size_t sizeIn) + : NEO::MemoryAllocation(0, AllocationType::UNKNOWN, buffer, castToUint64(buffer), 0llu, sizeIn, MemoryPool::MemoryNull, MemoryManager::maxOsContextCount) {} + + IpcImplicitScalingMockGraphicsAllocation(void *buffer, uint64_t gpuAddr, size_t sizeIn) + : NEO::MemoryAllocation(0, AllocationType::UNKNOWN, buffer, gpuAddr, 0llu, sizeIn, MemoryPool::MemoryNull, MemoryManager::maxOsContextCount) {} + + IpcImplicitScalingMockGraphicsAllocation(uint32_t rootDeviceIndex, void *buffer, size_t sizeIn) + : NEO::MemoryAllocation(rootDeviceIndex, AllocationType::UNKNOWN, buffer, castToUint64(buffer), 0llu, sizeIn, MemoryPool::MemoryNull, MemoryManager::maxOsContextCount) {} + + uint32_t getNumHandles() override { + return 2u; + } +}; + class MemoryManagerOpenIpcMock : public MemoryManagerIpcMock { public: MemoryManagerOpenIpcMock(NEO::ExecutionEnvironment &executionEnvironment) : MemoryManagerIpcMock(executionEnvironment) {} + + NEO::GraphicsAllocation *allocateGraphicsMemoryWithProperties(const AllocationProperties &properties) override { + auto alloc = new IpcImplicitScalingMockGraphicsAllocation(0, + NEO::AllocationType::BUFFER, + reinterpret_cast(sharedHandleAddress++), + 0x1000, + 0, + sizeof(uint32_t), + MemoryPool::System4KBPages); + alloc->setGpuBaseAddress(0xabcd); + return alloc; + } + NEO::GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { if (failOnCreateGraphicsAllocationFromSharedHandle) { return nullptr; } - auto alloc = new NEO::MockGraphicsAllocation(0, - NEO::AllocationType::BUFFER, - reinterpret_cast(sharedHandleAddress++), - 0x1000, - 0, - sizeof(uint32_t), - MemoryPool::System4KBPages); + auto alloc = new IpcImplicitScalingMockGraphicsAllocation(0, + NEO::AllocationType::BUFFER, + reinterpret_cast(sharedHandleAddress++), + 0x1000, + 0, + sizeof(uint32_t), + MemoryPool::System4KBPages); alloc->setGpuBaseAddress(0xabcd); return alloc; } @@ -502,5 +546,136 @@ struct MemoryOpenIpcHandleTest : public ::testing::Test { std::unique_ptr context; }; +class MemoryManagerIpcImplicitScalingMock : public NEO::MemoryManager { + public: + MemoryManagerIpcImplicitScalingMock(NEO::ExecutionEnvironment &executionEnvironment) : NEO::MemoryManager(executionEnvironment) {} + + NEO::GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { return nullptr; } + void addAllocationToHostPtrManager(NEO::GraphicsAllocation *memory) override{}; + void removeAllocationFromHostPtrManager(NEO::GraphicsAllocation *memory) override{}; + NEO::GraphicsAllocation *createGraphicsAllocationFromNTHandle(void *handle, uint32_t rootDeviceIndex, AllocationType allocType) override { return nullptr; }; + AllocationStatus populateOsHandles(NEO::OsHandleStorage &handleStorage, uint32_t rootDeviceIndex) override { return AllocationStatus::Success; }; + void cleanOsHandles(NEO::OsHandleStorage &handleStorage, uint32_t rootDeviceIndex) override{}; + void freeGraphicsMemoryImpl(NEO::GraphicsAllocation *gfxAllocation) override{}; + void freeGraphicsMemoryImpl(GraphicsAllocation *gfxAllocation, bool isImportedAllocation) override{}; + uint64_t getSystemSharedMemory(uint32_t rootDeviceIndex) override { return 0; }; + uint64_t getLocalMemorySize(uint32_t rootDeviceIndex, uint32_t deviceBitfield) override { return 0; }; + double getPercentOfGlobalMemoryAvailable(uint32_t rootDeviceIndex) override { return 0; } + AddressRange reserveGpuAddress(size_t size, uint32_t rootDeviceIndex) override { + return {}; + } + void freeGpuAddress(AddressRange addressRange, uint32_t rootDeviceIndex) override{}; + NEO::GraphicsAllocation *createGraphicsAllocation(OsHandleStorage &handleStorage, const NEO::AllocationData &allocationData) override { return nullptr; }; + NEO::GraphicsAllocation *allocateGraphicsMemoryForNonSvmHostPtr(const NEO::AllocationData &allocationData) override { return nullptr; }; + NEO::GraphicsAllocation *allocateGraphicsMemoryWithAlignment(const NEO::AllocationData &allocationData) override { return nullptr; }; + NEO::GraphicsAllocation *allocateUSMHostGraphicsMemory(const NEO::AllocationData &allocationData) override { return nullptr; }; + NEO::GraphicsAllocation *allocateGraphicsMemory64kb(const NEO::AllocationData &allocationData) override { return nullptr; }; + NEO::GraphicsAllocation *allocate32BitGraphicsMemoryImpl(const NEO::AllocationData &allocationData, bool useLocalMemory) override { return nullptr; }; + NEO::GraphicsAllocation *allocateGraphicsMemoryInDevicePool(const NEO::AllocationData &allocationData, AllocationStatus &status) override { return nullptr; }; + NEO::GraphicsAllocation *allocateGraphicsMemoryWithGpuVa(const NEO::AllocationData &allocationData) override { return nullptr; }; + + NEO::GraphicsAllocation *allocateGraphicsMemoryForImageImpl(const NEO::AllocationData &allocationData, std::unique_ptr gmm) override { return nullptr; }; + NEO::GraphicsAllocation *allocateMemoryByKMD(const NEO::AllocationData &allocationData) override { return nullptr; }; + void *lockResourceImpl(NEO::GraphicsAllocation &graphicsAllocation) override { return nullptr; }; + void unlockResourceImpl(NEO::GraphicsAllocation &graphicsAllocation) override{}; + + NEO::GraphicsAllocation *allocateGraphicsMemoryInPreferredPool(const AllocationProperties &properties, const void *hostPtr) override { + auto alloc = new IpcImplicitScalingMockGraphicsAllocation(0, + NEO::AllocationType::BUFFER, + reinterpret_cast(sharedHandleAddress++), + 0x1000, + 0, + sizeof(uint32_t), + MemoryPool::System4KBPages); + alloc->setGpuBaseAddress(0xabcd); + return alloc; + } + + NEO::GraphicsAllocation *allocateGraphicsMemoryWithProperties(const AllocationProperties &properties) override { + auto alloc = new IpcImplicitScalingMockGraphicsAllocation(0, + NEO::AllocationType::BUFFER, + reinterpret_cast(sharedHandleAddress++), + 0x1000, + 0, + sizeof(uint32_t), + MemoryPool::System4KBPages); + alloc->setGpuBaseAddress(0xabcd); + return alloc; + } + + NEO::GraphicsAllocation *createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { + if (failOnCreateGraphicsAllocationFromSharedHandle) { + return nullptr; + } + auto alloc = new IpcImplicitScalingMockGraphicsAllocation(0, + NEO::AllocationType::BUFFER, + reinterpret_cast(sharedHandleAddress++), + 0x1000, + 0, + sizeof(uint32_t), + MemoryPool::System4KBPages); + alloc->setGpuBaseAddress(0xabcd); + return alloc; + } + + void freeGraphicsMemory(NEO::GraphicsAllocation *alloc, bool isImportedAllocation) override { + delete alloc; + } + + uint64_t sharedHandleAddress = 0x1234; + + bool failOnCreateGraphicsAllocationFromSharedHandle = false; +}; + +struct MemoryExportImportImplicitScalingTest : public ::testing::Test { + void SetUp() override { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableImplicitScaling.set(1); + + NEO::MockCompilerEnableGuard mock(true); + neoDevice = + NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get()); + auto mockBuiltIns = new MockBuiltins(); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->builtins.reset(mockBuiltIns); + NEO::DeviceVector devices; + devices.push_back(std::unique_ptr(neoDevice)); + driverHandle = std::make_unique(); + driverHandle->initialize(std::move(devices)); + prevMemoryManager = driverHandle->getMemoryManager(); + currMemoryManager = new MemoryManagerIpcImplicitScalingMock(*neoDevice->executionEnvironment); + driverHandle->setMemoryManager(currMemoryManager); + + prevSvmAllocsManager = driverHandle->svmAllocsManager; + currSvmAllocsManager = new NEO::SVMAllocsManager(currMemoryManager, false); + driverHandle->svmAllocsManager = currSvmAllocsManager; + + device = driverHandle->devices[0]; + + context = std::make_unique(driverHandle.get()); + EXPECT_NE(context, nullptr); + context->getDevices().insert(std::make_pair(device->toHandle(), device)); + auto neoDevice = device->getNEODevice(); + context->rootDeviceIndices.push_back(neoDevice->getRootDeviceIndex()); + context->deviceBitfields.insert({neoDevice->getRootDeviceIndex(), neoDevice->getDeviceBitfield()}); + } + + void TearDown() override { + driverHandle->svmAllocsManager = prevSvmAllocsManager; + delete currSvmAllocsManager; + driverHandle->setMemoryManager(prevMemoryManager); + delete currMemoryManager; + } + + NEO::SVMAllocsManager *prevSvmAllocsManager; + NEO::SVMAllocsManager *currSvmAllocsManager; + + NEO::MemoryManager *prevMemoryManager = nullptr; + MemoryManagerIpcImplicitScalingMock *currMemoryManager = nullptr; + std::unique_ptr driverHandle; + NEO::MockDevice *neoDevice = nullptr; + L0::Device *device = nullptr; + std::unique_ptr context; +}; + } // namespace ult } // namespace L0 diff --git a/level_zero/core/test/unit_tests/sources/driver/test_driver.cpp b/level_zero/core/test/unit_tests/sources/driver/test_driver.cpp index a3a3adc013..f84f307b34 100644 --- a/level_zero/core/test/unit_tests/sources/driver/test_driver.cpp +++ b/level_zero/core/test/unit_tests/sources/driver/test_driver.cpp @@ -205,6 +205,45 @@ HWTEST_F(ImportNTHandle, givenNTHandleWhenCreatingDeviceMemoryThenSuccessIsRetur delete device; } +HWTEST_F(ImportNTHandle, whenCallingCreateGraphicsAllocationFromMultipleSharedHandlesFromOsAgnosticMemoryManagerThenNullptrIsReturned) { + using RENDER_SURFACE_STATE = typename FamilyType::RENDER_SURFACE_STATE; + + ze_device_mem_alloc_desc_t devProperties = {}; + devProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_MEMORY_PROPERTIES; + + uint64_t imageHandle = 0x1; + ze_external_memory_import_win32_handle_t importNTHandle = {}; + importNTHandle.handle = &imageHandle; + importNTHandle.flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32; + importNTHandle.stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_WIN32; + devProperties.pNext = &importNTHandle; + + NEO::MockDevice *neoDevice = nullptr; + auto executionEnvironment = NEO::MockDevice::prepareExecutionEnvironment(NEO::defaultHwInfo.get(), 0); + executionEnvironment->memoryManager.reset(new MemoryManagerNTHandleMock(*executionEnvironment)); + + neoDevice = NEO::MockDevice::createWithExecutionEnvironment(NEO::defaultHwInfo.get(), executionEnvironment, 0); + + driverHandle->setMemoryManager(executionEnvironment->memoryManager.get()); + + ze_result_t result = ZE_RESULT_SUCCESS; + auto device = L0::Device::create(driverHandle.get(), neoDevice, false, &result); + + std::vector handles{6, 7}; + AllocationProperties properties = {device->getRootDeviceIndex(), + true, + MemoryConstants::pageSize, + AllocationType::BUFFER, + false, + device->getNEODevice()->getDeviceBitfield()}; + bool requireSpecificBitness{}; + bool isHostIpcAllocation{}; + auto ptr = executionEnvironment->memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles, properties, requireSpecificBitness, isHostIpcAllocation); + EXPECT_EQ(nullptr, ptr); + + delete device; +} + HWTEST_F(ImportNTHandle, givenNotExistingNTHandleWhenCreatingDeviceMemoryThenErrorIsReturned) { using RENDER_SURFACE_STATE = typename FamilyType::RENDER_SURFACE_STATE; diff --git a/level_zero/core/test/unit_tests/sources/event/test_event.cpp b/level_zero/core/test/unit_tests/sources/event/test_event.cpp index 524457496a..3499911260 100644 --- a/level_zero/core/test/unit_tests/sources/event/test_event.cpp +++ b/level_zero/core/test/unit_tests/sources/event/test_event.cpp @@ -50,6 +50,7 @@ class MemoryManagerEventPoolFailMock : public NEO::MemoryManager { void *createMultiGraphicsAllocationInSystemMemoryPool(RootDeviceIndicesContainer &rootDeviceIndices, AllocationProperties &properties, NEO::MultiGraphicsAllocation &multiGraphicsAllocation) override { return nullptr; }; + GraphicsAllocation *createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { return nullptr; } NEO::GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { return nullptr; } void addAllocationToHostPtrManager(NEO::GraphicsAllocation *memory) override{}; void removeAllocationFromHostPtrManager(NEO::GraphicsAllocation *memory) override{}; diff --git a/level_zero/core/test/unit_tests/sources/memory/test_memory.cpp b/level_zero/core/test/unit_tests/sources/memory/test_memory.cpp index 42ed735161..d2a333fcaf 100644 --- a/level_zero/core/test/unit_tests/sources/memory/test_memory.cpp +++ b/level_zero/core/test/unit_tests/sources/memory/test_memory.cpp @@ -19,6 +19,7 @@ #include "level_zero/core/source/cmdlist/cmdlist_hw.h" #include "level_zero/core/source/context/context_imp.h" #include "level_zero/core/source/device/device_imp.h" +#include "level_zero/core/source/driver/driver_handle_imp.h" #include "level_zero/core/source/driver/host_pointer_manager.h" #include "level_zero/core/source/hw_helpers/l0_hw_helper.h" #include "level_zero/core/source/image/image.h" @@ -35,6 +36,215 @@ namespace L0 { namespace ult { +TEST_F(MemoryExportImportImplicitScalingTest, + givenCallToGetIpcHandleWithNotKnownPointerThenInvalidArgumentIsReturned) { + + uint32_t value = 0; + + uint32_t numIpcHandles = 0; + ze_result_t result = context->getIpcMemHandles(&value, &numIpcHandles, nullptr); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, result); +} + +TEST_F(MemoryExportImportImplicitScalingTest, + givenCallToGetIpcHandleWithDeviceAllocationThenIpcHandleIsReturned) { + size_t size = 10; + size_t alignment = 1u; + void *ptr = nullptr; + + ze_device_mem_alloc_desc_t deviceDesc = {}; + ze_result_t result = context->allocDeviceMem(device->toHandle(), + &deviceDesc, + size, alignment, &ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_NE(nullptr, ptr); + + uint32_t numIpcHandles = 0; + result = context->getIpcMemHandles(ptr, &numIpcHandles, nullptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(numIpcHandles, 2u); + + std::vector ipcHandles(numIpcHandles); + result = context->getIpcMemHandles(ptr, &numIpcHandles, ipcHandles.data()); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + result = context->freeMem(ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); +} + +TEST_F(MemoryExportImportImplicitScalingTest, + whenCallingOpenIpcHandlesWithIpcHandleThenDeviceAllocationIsReturned) { + size_t size = 10; + size_t alignment = 1u; + void *ptr = nullptr; + + ze_device_mem_alloc_desc_t deviceDesc = {}; + ze_result_t result = context->allocDeviceMem(device->toHandle(), + &deviceDesc, + size, alignment, &ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_NE(nullptr, ptr); + + uint32_t numIpcHandles = 0; + result = context->getIpcMemHandles(ptr, &numIpcHandles, nullptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(numIpcHandles, 2u); + + std::vector ipcHandles(numIpcHandles); + result = context->getIpcMemHandles(ptr, &numIpcHandles, ipcHandles.data()); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface()); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique(512)); + + ze_ipc_memory_flags_t flags = {}; + void *ipcPtr; + result = context->openIpcMemHandles(device->toHandle(), numIpcHandles, ipcHandles.data(), flags, &ipcPtr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + result = context->closeIpcMemHandle(ipcPtr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + result = context->freeMem(ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); +} + +TEST_F(MemoryExportImportImplicitScalingTest, + whenCallingImportFdHandlesWithAllocationPointerThenAllocationIsReturned) { + size_t size = 10; + size_t alignment = 1u; + void *ptr = nullptr; + + ze_device_mem_alloc_desc_t deviceDesc = {}; + ze_result_t result = context->allocDeviceMem(device->toHandle(), + &deviceDesc, + size, alignment, &ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_NE(nullptr, ptr); + + uint32_t numIpcHandles = 0; + result = context->getIpcMemHandles(ptr, &numIpcHandles, nullptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(numIpcHandles, 2u); + + std::vector ipcHandles(numIpcHandles); + result = context->getIpcMemHandles(ptr, &numIpcHandles, ipcHandles.data()); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface()); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique(512)); + + std::vector handles; + for (uint32_t i = 0; i < numIpcHandles; i++) { + uint64_t handle = 0; + memcpy_s(&handle, + sizeof(handle), + reinterpret_cast(ipcHandles[i].data), + sizeof(handle)); + handles.push_back(static_cast(handle)); + } + + ze_ipc_memory_flags_t flags = {}; + void *ipcPtr; + NEO::GraphicsAllocation *ipcAlloc = nullptr; + DriverHandleImp *driverHandleImp = static_cast(context->getDriverHandle()); + ipcPtr = driverHandleImp->importFdHandles(device->toHandle(), flags, handles, &ipcAlloc); + EXPECT_NE(ipcPtr, nullptr); + EXPECT_NE(ipcAlloc, nullptr); + + result = context->closeIpcMemHandle(ipcPtr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + result = context->freeMem(ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); +} + +TEST_F(MemoryExportImportImplicitScalingTest, + whenCallingImportFdHandlesWithUncachedFlagAllocationPointerThenAllocationIsReturned) { + size_t size = 10; + size_t alignment = 1u; + void *ptr = nullptr; + + ze_device_mem_alloc_desc_t deviceDesc = {}; + ze_result_t result = context->allocDeviceMem(device->toHandle(), + &deviceDesc, + size, alignment, &ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_NE(nullptr, ptr); + + uint32_t numIpcHandles = 0; + result = context->getIpcMemHandles(ptr, &numIpcHandles, nullptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(numIpcHandles, 2u); + + std::vector ipcHandles(numIpcHandles); + result = context->getIpcMemHandles(ptr, &numIpcHandles, ipcHandles.data()); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface()); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique(512)); + + std::vector handles; + for (uint32_t i = 0; i < numIpcHandles; i++) { + uint64_t handle = 0; + memcpy_s(&handle, + sizeof(handle), + reinterpret_cast(ipcHandles[i].data), + sizeof(handle)); + handles.push_back(static_cast(handle)); + } + + ze_ipc_memory_flags_t flags = {ZE_IPC_MEMORY_FLAG_BIAS_UNCACHED}; + void *ipcPtr; + NEO::GraphicsAllocation *ipcAlloc = nullptr; + DriverHandleImp *driverHandleImp = static_cast(context->getDriverHandle()); + ipcPtr = driverHandleImp->importFdHandles(device->toHandle(), flags, handles, &ipcAlloc); + EXPECT_NE(ipcPtr, nullptr); + EXPECT_NE(ipcAlloc, nullptr); + + result = context->closeIpcMemHandle(ipcPtr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + result = context->freeMem(ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); +} + +TEST_F(MemoryExportImportImplicitScalingTest, + whenCallingGetIpcMemHandlesAndImportFailsThenInvalidArgumentFails) { + currMemoryManager->failOnCreateGraphicsAllocationFromSharedHandle = true; + + size_t size = 10; + size_t alignment = 1u; + void *ptr = nullptr; + + ze_device_mem_alloc_desc_t deviceDesc = {}; + ze_result_t result = context->allocDeviceMem(device->toHandle(), + &deviceDesc, + size, alignment, &ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_NE(nullptr, ptr); + + uint32_t numIpcHandles = 0; + result = context->getIpcMemHandles(ptr, &numIpcHandles, nullptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(numIpcHandles, 2u); + + std::vector ipcHandles(numIpcHandles); + result = context->getIpcMemHandles(ptr, &numIpcHandles, ipcHandles.data()); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface()); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique(512)); + + ze_ipc_memory_flags_t flags = {}; + void *ipcPtr; + result = context->openIpcMemHandles(device->toHandle(), numIpcHandles, ipcHandles.data(), flags, &ipcPtr); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, result); + + result = context->freeMem(ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); +} + using MemoryTest = Test; struct CompressionMemoryTest : public MemoryTest { @@ -2526,6 +2736,44 @@ struct MemoryFailedOpenIpcHandleTest : public ::testing::Test { std::unique_ptr context; }; +struct MemoryFailedOpenIpcHandleImplicitScalingTest : public ::testing::Test { + void SetUp() override { + DebugManagerStateRestore restorer; + DebugManager.flags.EnableImplicitScaling.set(1); + NEO::MockCompilerEnableGuard mock(true); + neoDevice = + NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get()); + auto mockBuiltIns = new MockBuiltins(); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->builtins.reset(mockBuiltIns); + NEO::DeviceVector devices; + devices.push_back(std::unique_ptr(neoDevice)); + driverHandle = std::make_unique(); + driverHandle->initialize(std::move(devices)); + prevMemoryManager = driverHandle->getMemoryManager(); + currMemoryManager = new MemoryManagerIpcMock(*neoDevice->executionEnvironment); + driverHandle->setMemoryManager(currMemoryManager); + device = driverHandle->devices[0]; + + context = std::make_unique(driverHandle.get()); + EXPECT_NE(context, nullptr); + context->getDevices().insert(std::make_pair(device->toHandle(), device)); + auto neoDevice = device->getNEODevice(); + context->rootDeviceIndices.push_back(neoDevice->getRootDeviceIndex()); + context->deviceBitfields.insert({neoDevice->getRootDeviceIndex(), neoDevice->getDeviceBitfield()}); + } + + void TearDown() override { + driverHandle->setMemoryManager(prevMemoryManager); + delete currMemoryManager; + } + NEO::MemoryManager *prevMemoryManager = nullptr; + NEO::MemoryManager *currMemoryManager = nullptr; + std::unique_ptr driverHandle; + NEO::MockDevice *neoDevice = nullptr; + L0::Device *device = nullptr; + std::unique_ptr context; +}; + TEST_F(MemoryFailedOpenIpcHandleTest, givenCallToOpenIpcMemHandleWithNullPtrFromCreateGraphicsAllocationFromSharedHandleThenInvalidArgumentIsReturned) { size_t size = 10; @@ -2553,6 +2801,37 @@ TEST_F(MemoryFailedOpenIpcHandleTest, EXPECT_EQ(ZE_RESULT_SUCCESS, result); } +TEST_F(MemoryFailedOpenIpcHandleImplicitScalingTest, + givenCallToOpenIpcMemHandleWithNullPtrFromCreateGraphicsAllocationFromSharedHandleThenInvalidArgumentIsReturned) { + size_t size = 10; + size_t alignment = 1u; + void *ptr = nullptr; + + ze_device_mem_alloc_desc_t deviceDesc = {}; + ze_result_t result = context->allocDeviceMem(device->toHandle(), + &deviceDesc, + size, alignment, &ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_NE(nullptr, ptr); + + uint32_t numIpcHandles = 0; + result = context->getIpcMemHandles(ptr, &numIpcHandles, nullptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + std::vector ipcHandles(numIpcHandles); + result = context->getIpcMemHandles(ptr, &numIpcHandles, ipcHandles.data()); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + ze_ipc_memory_flags_t flags = {}; + void *ipcPtr; + result = context->openIpcMemHandles(device->toHandle(), numIpcHandles, ipcHandles.data(), flags, &ipcPtr); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, result); + EXPECT_EQ(ipcPtr, nullptr); + + result = context->freeMem(ptr); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); +} + using DeviceMemorySizeTest = Test; TEST_F(DeviceMemorySizeTest, givenSizeGreaterThanLimitThenDeviceAllocationFails) { diff --git a/level_zero/doc/experimental_extensions/DRIVER_EXPERIMENTAL_EXTENSIONS.md b/level_zero/doc/experimental_extensions/DRIVER_EXPERIMENTAL_EXTENSIONS.md new file mode 100644 index 0000000000..73f1b72413 --- /dev/null +++ b/level_zero/doc/experimental_extensions/DRIVER_EXPERIMENTAL_EXTENSIONS.md @@ -0,0 +1,27 @@ + + + +# Level Zero GPU Driver Driver Experimental Extensions + +## Introduction + +The following document describes the driver experimental extensions implemented in the Level Zero Intel(R) GPU driver. These extensions are meant to test and/or gather feedback on interfaces before they could potentially be added Level Zero specification, as well to provide access to functionality specific to Intel(R) GPUs. + +Access to these extensions is possible through [zeDriverGetExtensionFunctionAddress](https://spec.oneapi.io/level-zero/latest/core/api.html?highlight=zedrivergetextensionfunctionaddress#_CPPv435zeDriverGetExtensionFunctionAddress18ze_driver_handle_tPKcPPv). Sample code: + + +```cpp +typedef ze_result_t (*pFnzexMemGetIpcHandles)(ze_context_handle_t, const void *, uint32_t *, ze_ipc_mem_handle_t *); +... + +pFnzexMemGetIpcHandles zexMemOpenIpcHandlePointer = nullptr; +ze_result_t res = zeDriverGetExtensionFunctionAddress(hDriver, "zexMemOpenIpcHandles", reinterpret_cast(&zexMemOpenIpcHandlePointer))); +``` + +### [Multiple IPC Handles](MULTIPLE_IPC_HANDLES.md) \ No newline at end of file diff --git a/level_zero/doc/experimental_extensions/MULTIPLE_IPC_HANDLES.md b/level_zero/doc/experimental_extensions/MULTIPLE_IPC_HANDLES.md new file mode 100644 index 0000000000..171eecd271 --- /dev/null +++ b/level_zero/doc/experimental_extensions/MULTIPLE_IPC_HANDLES.md @@ -0,0 +1,106 @@ + + +# Multiple IPC handles + +* [Overview](#Overview) +* [Definitions](#Definitions) +* [Known Issues and Limitations](#Known-Issues-and-Limitations) + +# Overview + +When using multi-tile architectures, Level Zero runtime allocations (i.e. `zeMemAllocDevice`) may be split by the GPU driver into several smaller allocations, each one allocated in a given tile. This is done for instance when using implicit scaling, to equally distribute memory on the available tiles. Although this is done as an internal optimization the application should not be aware of, there are scenarios where the number of internal allocations need to be known by the application. One of those being when exchanging the IPC handles of the runtime allocation with other process. If the allocation has been split into several smaller ones, then each of thse internal allocations would have its own file descriptor, and each of them need to be separately interchanged with the other process. + +Current IPC memory interfaces in the Level Zero specification `zeMemGetIpcHandle` and `zeMemOpenIpcHandle` assume the existence of only one file descriptor, and cannot be used when multiple internal allocations and file descriptors are associated with a single Level Zero allocation. + +This extension provides two new interfaces with which applications can query the number of file descriptors associated with a Level Zero allocation, get those descriptors, and then create a new allocation composed of the exported internal allocations. + +# Definitions + +```cpp +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZEX_MEM_IPC_HANDLES_NAME +/// @brief Multiple IPC handles driver extension name +#define ZEX_MEM_IPC_HANDLES_NAME "ZEX_mem_ipc_handles" +#endif // ZEX_MEM_IPC_HANDLES_NAME + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Multiple IPC handles driver extension Version(s) +typedef enum _zex_mem_ipc_handles_version_t +{ + ZEX_MEM_IPC_HANDLES_VERSION_1_0 = ZE_MAKE_VERSION( 1, 0 ), ///< version 1.0 + ZEX_MEM_IPC_HANDLES_VERSION_CURRENT = ZE_MAKE_VERSION( 1, 0 ), ///< latest known version + ZEX_MEM_IPC_HANDLES_VERSION_FORCE_UINT32 = 0x7fffffff + +} zex_mem_ipc_handles_version_t; +``` + +## Interfaces + +```cpp +/////////////////////////////////////////////////////////////////////////////// +/// @brief Returns an array IPC memory handles for the specified allocation +/// +/// @details +/// - Takes a pointer to a device memory allocation and returns an array of +// IPC memory handle for exporting it for use in another process. +/// - The application may call this function from simultaneous threads. +/// - The implementation of this function must be thread-safe. +/// +/// @returns +/// - ::ZE_RESULT_SUCCESS +/// - ::ZE_RESULT_ERROR_INVALID_ARGUMENT +/// + ptr` not known +ZE_APIEXPORT ze_result_t ZE_APICALL +zexMemGetIpcHandles( + ze_context_handle_t hContext, ///< [in] handle of the context object + const void *ptr, ///< [in] pointer to the device memory allocation + uint32_t *numIpcHandles, ///< [in,out] number of IPC handles associated with the allocation + ///< if numIpcHandles is zero, then the driver shall update the value with the + ///< total number of IPC handles associated with the allocation. + ze_ipc_mem_handle_t *pIpcHandles ///< [in,out][optional][range(0, *numIpcHandles)] returned array of IPC memory handles + ); +``` + +```cpp +/////////////////////////////////////////////////////////////////////////////// +/// @brief Creates an allocation associated with an array of IPC memory handles +/// imported from another process. +/// +/// @details +/// - Takes an array of IPC memory handles from a remote process and associates it +/// with a device pointer usable in this process. +/// - The device pointer in this process should not be freed with +/// ::zeMemFree, but rather with ::zeMemCloseIpcHandle. +/// - The application may call this function from simultaneous threads. +/// - The implementation of this function must be thread-safe. +/// +/// @returns +/// - ::ZE_RESULT_SUCCESS +/// - ::ZE_RESULT_ERROR_INVALID_ARGUMENT +/// + handles not known +ZE_APIEXPORT ze_result_t ZE_APICALL +zexMemOpenIpcHandles( + ze_context_handle_t hContext, ///< [in] handle of the context object + ze_device_handle_t hDevice, ///< [in] handle of the device to associate with the IPC memory handle + uint32_t numIpcHandles, ///< [in] number of IPC handles associated with the allocation + ze_ipc_mem_handle_t *pIpcHandles, ///< [in][range(0, *numIpcHandles)] array of IPC memory handles + ze_ipc_memory_flags_t flags, ///< [in] flags controlling the operation. + ///< must be 0 (default) or a valid combination of ::ze_ipc_memory_flag_t. + void **pptr ///< [out] pointer to device allocation in this process + ); +``` + +## Enums + +None. + +# Known Issues and Limitations + +* Currently supported only on Linux. +* Mainly implemented for and validated on Xe HPC (PVC) and XeHP_SDV platforms. diff --git a/opencl/test/unit_test/os_interface/linux/drm_memory_manager_localmem_prelim_tests.cpp b/opencl/test/unit_test/os_interface/linux/drm_memory_manager_localmem_prelim_tests.cpp index 0946c49226..e4d56aab0d 100644 --- a/opencl/test/unit_test/os_interface/linux/drm_memory_manager_localmem_prelim_tests.cpp +++ b/opencl/test/unit_test/os_interface/linux/drm_memory_manager_localmem_prelim_tests.cpp @@ -11,6 +11,7 @@ #include "shared/source/memory_manager/compression_selector.h" #include "shared/source/memory_manager/unified_memory_manager.h" #include "shared/source/os_interface/linux/allocator_helper.h" +#include "shared/test/common/fixtures/memory_allocator_multi_device_fixture.h" #include "shared/test/common/libult/linux/drm_mock_helper.h" #include "shared/test/common/libult/linux/drm_mock_prelim_context.h" #include "shared/test/common/libult/linux/drm_query_mock.h" @@ -1550,6 +1551,115 @@ TEST_F(DrmMemoryManagerCopyMemoryToAllocationPrelimTest, givenDrmMemoryManagerWh typedef Test DrmMemoryManagerTestPrelim; +TEST_F(DrmMemoryManagerTestPrelim, whenSettingNumHandlesThenTheyAreRetrievedCorrectly) { + mock->ioctl_expected.primeFdToHandle = 2; + mock->ioctl_expected.gemWait = 1; + mock->ioctl_expected.gemClose = 2; + + std::vector handles{6, 7}; + size_t size = 65536u * 2; + AllocationProperties properties(rootDeviceIndex, true, size, AllocationType::BUFFER_HOST_MEMORY, false, device->getDeviceBitfield()); + + auto graphicsAllocation = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, false); + ASSERT_NE(nullptr, graphicsAllocation); + + uint32_t numHandlesExpected = 8; + graphicsAllocation->setNumHandles(numHandlesExpected); + EXPECT_EQ(graphicsAllocation->getNumHandles(), numHandlesExpected); + + graphicsAllocation->setNumHandles(static_cast(handles.size())); + + memoryManager->freeGraphicsMemory(graphicsAllocation); +} + +TEST_F(DrmMemoryManagerTestPrelim, whenCreatingAllocationFromMultipleSharedHandlesAndFindAndReferenceSharedBufferObjectReturnsNonNullThenAllocationSucceeds) { + mock->ioctl_expected.primeFdToHandle = 4; + mock->ioctl_expected.gemWait = 2; + mock->ioctl_expected.gemClose = 2; + + std::vector handles{6, 7}; + size_t size = 65536u * 2; + AllocationProperties properties(rootDeviceIndex, true, size, AllocationType::BUFFER_HOST_MEMORY, false, device->getDeviceBitfield()); + + memoryManager->failOnfindAndReferenceSharedBufferObject = false; + auto graphicsAllocation = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, false); + ASSERT_NE(nullptr, graphicsAllocation); + + DrmAllocation *drmAllocation = static_cast(graphicsAllocation); + auto bo = drmAllocation->getBO(); + EXPECT_EQ(bo->peekHandle(), (int)this->mock->outputHandle); + EXPECT_NE(0llu, bo->peekAddress()); + + auto graphicsAllocationFromReferencedHandle = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, false); + ASSERT_NE(nullptr, graphicsAllocationFromReferencedHandle); + + DrmAllocation *drmAllocationFromReferencedHandle = static_cast(graphicsAllocationFromReferencedHandle); + auto boFromReferencedHandle = drmAllocationFromReferencedHandle->getBO(); + EXPECT_EQ(boFromReferencedHandle->peekHandle(), (int)this->mock->outputHandle); + EXPECT_NE(0llu, boFromReferencedHandle->peekAddress()); + + memoryManager->freeGraphicsMemory(graphicsAllocation); + memoryManager->freeGraphicsMemory(graphicsAllocationFromReferencedHandle); +} + +TEST_F(DrmMemoryManagerTestPrelim, whenCreatingAllocationFromMultipleSharedHandlesWithOneHandleThenAllocationSucceeds) { + mock->ioctl_expected.primeFdToHandle = 1; + mock->ioctl_expected.gemWait = 1; + mock->ioctl_expected.gemClose = 1; + + std::vector handles{6}; + size_t size = 65536u * 2; + AllocationProperties properties(rootDeviceIndex, true, size, AllocationType::BUFFER_HOST_MEMORY, false, device->getDeviceBitfield()); + + memoryManager->failOnfindAndReferenceSharedBufferObject = false; + auto graphicsAllocation = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, false); + ASSERT_NE(nullptr, graphicsAllocation); + + DrmAllocation *drmAllocation = static_cast(graphicsAllocation); + auto bo = drmAllocation->getBO(); + EXPECT_EQ(bo->peekHandle(), (int)this->mock->outputHandle); + EXPECT_NE(0llu, bo->peekAddress()); + EXPECT_EQ(1u, bo->getRefCount()); + + memoryManager->freeGraphicsMemory(graphicsAllocation); +} + +TEST_F(DrmMemoryManagerTestPrelim, whenCreatingAllocationFromMultipleSharedHandlesAndIoctlFailsThenNullIsReturned) { + mock->ioctl_expected.primeFdToHandle = 1; + mock->ioctl_expected.gemWait = 0; + mock->ioctl_expected.gemClose = 0; + mock->failOnPrimeFdToHandle = true; + + std::vector handles{6, 7}; + size_t size = 65536u * 2; + AllocationProperties properties(rootDeviceIndex, true, size, AllocationType::BUFFER_HOST_MEMORY, false, device->getDeviceBitfield()); + + memoryManager->failOnfindAndReferenceSharedBufferObject = false; + auto graphicsAllocation = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, false); + EXPECT_EQ(nullptr, graphicsAllocation); +} + +TEST_F(DrmMemoryManagerTestPrelim, whenCreatingAllocationFromMultipleSharedHandlesThenAllocationSucceeds) { + mock->ioctl_expected.primeFdToHandle = 2; + mock->ioctl_expected.gemWait = 1; + mock->ioctl_expected.gemClose = 2; + + std::vector handles{6, 7}; + size_t size = 65536u * 2; + AllocationProperties properties(rootDeviceIndex, true, size, AllocationType::BUFFER_HOST_MEMORY, false, device->getDeviceBitfield()); + + auto graphicsAllocation = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, false); + ASSERT_NE(nullptr, graphicsAllocation); + + DrmAllocation *drmAllocation = static_cast(graphicsAllocation); + auto bo = drmAllocation->getBO(); + EXPECT_EQ(bo->peekHandle(), (int)this->mock->outputHandle); + EXPECT_NE(0llu, bo->peekAddress()); + EXPECT_EQ(1u, bo->getRefCount()); + + memoryManager->freeGraphicsMemory(graphicsAllocation); +} + TEST_F(DrmMemoryManagerTestPrelim, givenDrmMemoryManagerWhenLockUnlockIsCalledOnAllocationInLocalMemoryButFailsOnMmapFunctionThenReturnNullPtr) { mock->ioctl_expected.gemMmapOffset = 2; this->ioctlResExt = {mock->ioctl_cnt.total, -1}; diff --git a/opencl/test/unit_test/os_interface/linux/drm_memory_manager_tests.cpp b/opencl/test/unit_test/os_interface/linux/drm_memory_manager_tests.cpp index 65d881239a..39fd15a7d2 100644 --- a/opencl/test/unit_test/os_interface/linux/drm_memory_manager_tests.cpp +++ b/opencl/test/unit_test/os_interface/linux/drm_memory_manager_tests.cpp @@ -475,6 +475,21 @@ TEST_F(DrmMemoryManagerTest, whenPeekInternalHandleIsCalledThenBoIsReturend) { memoryManager->freeGraphicsMemory(allocation); } +TEST_F(DrmMemoryManagerTest, whenPeekInternalHandleWithHandleIdIsCalledThenBoIsReturend) { + mock->ioctl_expected.gemUserptr = 1; + mock->ioctl_expected.gemWait = 1; + mock->ioctl_expected.gemClose = 1; + mock->ioctl_expected.handleToPrimeFd = 1; + mock->outputFd = 1337; + auto allocation = static_cast(this->memoryManager->allocateGraphicsMemoryWithProperties(createAllocationProperties(rootDeviceIndex, 10 * MemoryConstants::pageSize, true))); + ASSERT_NE(allocation->getBO(), nullptr); + + uint32_t handleId = 0; + ASSERT_EQ(allocation->peekInternalHandle(this->memoryManager, handleId), static_cast(1337)); + + memoryManager->freeGraphicsMemory(allocation); +} + TEST_F(DrmMemoryManagerTest, givenDrmContextIdWhenAllocationIsCreatedThenPinWithPassedDrmContextId) { mock->ioctl_expected.gemUserptr = 2; mock->ioctl_expected.execbuffer2 = 1; diff --git a/opencl/test/unit_test/os_interface/windows/wddm20_tests.cpp b/opencl/test/unit_test/os_interface/windows/wddm20_tests.cpp index 7a137f365f..68199d5237 100644 --- a/opencl/test/unit_test/os_interface/windows/wddm20_tests.cpp +++ b/opencl/test/unit_test/os_interface/windows/wddm20_tests.cpp @@ -552,6 +552,20 @@ TEST_F(Wddm20WithMockGdiDllTests, givenSharedHandleWhenCreateGraphicsAllocationF EXPECT_EQ(1u, destroyWithResourceHandleCalled); } +TEST_F(Wddm20WithMockGdiDllTests, givenSharedHandleWhenCreateGraphicsAllocationFromMultipleSharedHandlesIsCalledThenNullptrIsReturned) { + void *pSysMem = (void *)0x1000; + std::unique_ptr gmm(new Gmm(getGmmHelper(), pSysMem, 4096u, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, false, {}, true)); + auto status = setSizesFcn(gmm->gmmResourceInfo.get(), 1u, 1024u, 1u); + EXPECT_EQ(0u, status); + + MemoryManagerCreate mm(false, false, *executionEnvironment); + AllocationProperties properties(0, false, 4096u, AllocationType::SHARED_BUFFER, false, {}); + + std::vector handles{ALLOCATION_HANDLE}; + auto graphicsAllocation = mm.createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, false); + ASSERT_EQ(nullptr, graphicsAllocation); +} + TEST_F(Wddm20WithMockGdiDllTests, givenSharedHandleWhenCreateGraphicsAllocationFromSharedHandleIsCalledThenMapGpuVaWithCpuPtrDepensOnBitness) { void *pSysMem = (void *)0x1000; std::unique_ptr gmm(new Gmm(getGmmHelper(), pSysMem, 4096u, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, false, {}, true)); diff --git a/opencl/test/unit_test/os_interface/windows/wddm_memory_manager_tests.cpp b/opencl/test/unit_test/os_interface/windows/wddm_memory_manager_tests.cpp index 95f02bdf61..626c040340 100644 --- a/opencl/test/unit_test/os_interface/windows/wddm_memory_manager_tests.cpp +++ b/opencl/test/unit_test/os_interface/windows/wddm_memory_manager_tests.cpp @@ -318,6 +318,25 @@ TEST_F(WddmMemoryManagerSimpleTest, givenMemoryManagerWhenCreateAllocationFromHa memoryManager->freeGraphicsMemory(allocation); } +TEST_F(WddmMemoryManagerSimpleTest, givenSharedHandleWhenCreateGraphicsAllocationFromMultipleSharedHandlesIsCalledThenNullptrIsReturned) { + memoryManager.reset(new MockWddmMemoryManager(false, false, *executionEnvironment)); + auto handle = 1u; + gdi->getQueryResourceInfoArgOut().NumAllocations = 1; + std::unique_ptr gmm(new Gmm(rootDeviceEnvironment->getGmmHelper(), nullptr, 0, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, false, {}, true)); + + D3DDDI_OPENALLOCATIONINFO allocationInfo; + allocationInfo.pPrivateDriverData = gmm->gmmResourceInfo->peekHandle(); + allocationInfo.hAllocation = ALLOCATION_HANDLE; + allocationInfo.PrivateDriverDataSize = sizeof(GMM_RESOURCE_INFO); + + gdi->getOpenResourceArgOut().pOpenAllocationInfo = &allocationInfo; + + AllocationProperties properties(0, false, 0, AllocationType::SHARED_BUFFER, false, false, 0); + std::vector handles{handle}; + auto allocation = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, false); + EXPECT_EQ(nullptr, allocation); +} + TEST_F(WddmMemoryManagerSimpleTest, givenAllocationPropertiesWhenCreateAllocationFromHandleIsCalledThenCorrectAllocationTypeIsSet) { memoryManager.reset(new MockWddmMemoryManager(false, false, *executionEnvironment)); auto osHandle = 1u; diff --git a/shared/source/memory_manager/graphics_allocation.h b/shared/source/memory_manager/graphics_allocation.h index 394f1499b1..79ba1bd96f 100644 --- a/shared/source/memory_manager/graphics_allocation.h +++ b/shared/source/memory_manager/graphics_allocation.h @@ -176,6 +176,17 @@ class GraphicsAllocation : public IDNode { virtual std::string getAllocationInfoString() const; virtual uint64_t peekInternalHandle(MemoryManager *memoryManager) { return 0llu; } + virtual uint64_t peekInternalHandle(MemoryManager *memoryManager, uint32_t handleId) { + return 0u; + } + + virtual uint32_t getNumHandles() { + return 0u; + } + + virtual void setNumHandles(uint32_t numHandles) { + } + static bool isCpuAccessRequired(AllocationType allocationType) { return allocationType == AllocationType::COMMAND_BUFFER || allocationType == AllocationType::CONSTANT_SURFACE || diff --git a/shared/source/memory_manager/memory_manager.h b/shared/source/memory_manager/memory_manager.h index e399abd4d7..3bd9235690 100644 --- a/shared/source/memory_manager/memory_manager.h +++ b/shared/source/memory_manager/memory_manager.h @@ -92,6 +92,7 @@ class MemoryManager { virtual bool verifyHandle(osHandle handle, uint32_t rootDeviceIndex, bool) { return true; } virtual bool isNTHandle(osHandle handle, uint32_t rootDeviceIndex) { return false; } + virtual GraphicsAllocation *createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) = 0; virtual GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) = 0; virtual void closeSharedHandle(GraphicsAllocation *graphicsAllocation){}; virtual GraphicsAllocation *createGraphicsAllocationFromNTHandle(void *handle, uint32_t rootDeviceIndex, AllocationType allocType) = 0; diff --git a/shared/source/memory_manager/os_agnostic_memory_manager.cpp b/shared/source/memory_manager/os_agnostic_memory_manager.cpp index d7b7b7eda2..b63453cc6b 100644 --- a/shared/source/memory_manager/os_agnostic_memory_manager.cpp +++ b/shared/source/memory_manager/os_agnostic_memory_manager.cpp @@ -223,6 +223,10 @@ GraphicsAllocation *OsAgnosticMemoryManager::allocate32BitGraphicsMemoryImpl(con return memoryAllocation; } +GraphicsAllocation *OsAgnosticMemoryManager::createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) { + return nullptr; +} + GraphicsAllocation *OsAgnosticMemoryManager::createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) { auto graphicsAllocation = createMemoryAllocation(properties.allocationType, nullptr, reinterpret_cast(1), 1, 4096u, static_cast(handle), MemoryPool::SystemCpuInaccessible, properties.rootDeviceIndex, diff --git a/shared/source/memory_manager/os_agnostic_memory_manager.h b/shared/source/memory_manager/os_agnostic_memory_manager.h index ae991754de..c8e850028b 100644 --- a/shared/source/memory_manager/os_agnostic_memory_manager.h +++ b/shared/source/memory_manager/os_agnostic_memory_manager.h @@ -69,6 +69,7 @@ class OsAgnosticMemoryManager : public MemoryManager { OsAgnosticMemoryManager(bool aubUsage, ExecutionEnvironment &executionEnvironment); void initialize(bool aubUsage); ~OsAgnosticMemoryManager() override; + GraphicsAllocation *createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override; GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override; GraphicsAllocation *createGraphicsAllocationFromNTHandle(void *handle, uint32_t rootDeviceIndex, AllocationType allocType) override { return nullptr; } diff --git a/shared/source/os_interface/linux/drm_allocation.cpp b/shared/source/os_interface/linux/drm_allocation.cpp index ad043087db..aa90de7c68 100644 --- a/shared/source/os_interface/linux/drm_allocation.cpp +++ b/shared/source/os_interface/linux/drm_allocation.cpp @@ -40,6 +40,10 @@ uint64_t DrmAllocation::peekInternalHandle(MemoryManager *memoryManager) { return static_cast((static_cast(memoryManager))->obtainFdFromHandle(getBO()->peekHandle(), this->rootDeviceIndex)); } +uint64_t DrmAllocation::peekInternalHandle(MemoryManager *memoryManager, uint32_t handleId) { + return static_cast((static_cast(memoryManager))->obtainFdFromHandle(getBufferObjectToModify(handleId)->peekHandle(), this->rootDeviceIndex)); +} + void DrmAllocation::setCachePolicy(CachePolicy memType) { for (auto bo : bufferObjects) { if (bo != nullptr) { diff --git a/shared/source/os_interface/linux/drm_allocation.h b/shared/source/os_interface/linux/drm_allocation.h index e4fa5ade8d..650363c151 100644 --- a/shared/source/os_interface/linux/drm_allocation.h +++ b/shared/source/os_interface/linux/drm_allocation.h @@ -78,8 +78,18 @@ class DrmAllocation : public GraphicsAllocation { this->bufferObjects.resize(size); } + uint32_t getNumHandles() override { + return this->numHandles; + } + + void setNumHandles(uint32_t numHandles) override { + this->numHandles = numHandles; + } + uint64_t peekInternalHandle(MemoryManager *memoryManager) override; + uint64_t peekInternalHandle(MemoryManager *memoryManager, uint32_t handleId) override; + bool setCacheRegion(Drm *drm, CacheRegion regionIndex); bool setCacheAdvice(Drm *drm, size_t regionSize, CacheRegion regionIndex); void setCachePolicy(CachePolicy memType); @@ -107,6 +117,7 @@ class DrmAllocation : public GraphicsAllocation { StackVec registeredBoBindHandles; MemAdviseFlags enabledMemAdviseFlags{}; StackVec memoryToUnmap; + uint32_t numHandles = 0u; void *mmapPtr = nullptr; size_t mmapSize = 0u; diff --git a/shared/source/os_interface/linux/drm_memory_manager.cpp b/shared/source/os_interface/linux/drm_memory_manager.cpp index f9f94a86de..9ce4228199 100644 --- a/shared/source/os_interface/linux/drm_memory_manager.cpp +++ b/shared/source/os_interface/linux/drm_memory_manager.cpp @@ -20,6 +20,7 @@ #include "shared/source/helpers/ptr_math.h" #include "shared/source/helpers/string.h" #include "shared/source/helpers/surface_format_info.h" +#include "shared/source/memory_manager/allocation_properties.h" #include "shared/source/memory_manager/host_ptr_manager.h" #include "shared/source/memory_manager/memory_banks.h" #include "shared/source/memory_manager/memory_pool.h" @@ -654,6 +655,101 @@ BufferObject *DrmMemoryManager::findAndReferenceSharedBufferObject(int boHandle, return bo; } +GraphicsAllocation *DrmMemoryManager::createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) { + BufferObjects bos; + std::vector sizes; + size_t totalSize = 0; + + std::unique_lock lock(mtx); + + uint32_t i = 0; + + if (handles.size() != 1) { + properties.multiStorageResource = true; + } + + auto &drm = this->getDrm(properties.rootDeviceIndex); + + bool areBosSharedObjects = true; + + for (auto handle : handles) { + drm_prime_handle openFd = {0, 0, 0}; + openFd.fd = handle; + + auto ret = this->getDrm(properties.rootDeviceIndex).ioctl(DRM_IOCTL_PRIME_FD_TO_HANDLE, &openFd); + + if (ret != 0) { + [[maybe_unused]] int err = errno; + PRINT_DEBUG_STRING(DebugManager.flags.PrintDebugMessages.get(), stderr, "ioctl(PRIME_FD_TO_HANDLE) failed with %d. errno=%d(%s)\n", ret, err, strerror(err)); + + return nullptr; + } + + auto boHandle = openFd.handle; + auto bo = findAndReferenceSharedBufferObject(boHandle, properties.rootDeviceIndex); + + if (bo == nullptr) { + areBosSharedObjects = false; + + size_t size = lseekFunction(handle, 0, SEEK_END); + totalSize += size; + + auto patIndex = drm.getPatIndex(nullptr, properties.allocationType, CacheRegion::Default, CachePolicy::WriteBack, false); + + bo = new (std::nothrow) BufferObject(&drm, patIndex, boHandle, size, maxOsContextCount); + bo->setRootDeviceIndex(properties.rootDeviceIndex); + i++; + } + bos.push_back(bo); + sizes.push_back(bo->peekSize()); + } + + auto heapIndex = HeapIndex::HEAP_STANDARD2MB; + auto gpuRange = acquireGpuRange(totalSize, properties.rootDeviceIndex, heapIndex); + + lock.unlock(); + + AllocationData allocationData; + properties.size = totalSize; + getAllocationData(allocationData, properties, nullptr, createStorageInfoFromProperties(properties)); + + auto drmAllocation = new DrmAllocation(properties.rootDeviceIndex, + handles.size(), + properties.allocationType, + bos, + nullptr, + gpuRange, + totalSize, + MemoryPool::LocalMemory); + drmAllocation->storageInfo = allocationData.storageInfo; + + auto gmmHelper = executionEnvironment.rootDeviceEnvironments[properties.rootDeviceIndex]->getGmmHelper(); + for (i = 0u; i < handles.size(); i++) { + auto bo = bos[i]; + StorageInfo limitedStorageInfo = allocationData.storageInfo; + limitedStorageInfo.memoryBanks &= (1u << (i % handles.size())); + auto gmm = new Gmm(gmmHelper, + nullptr, + bo->peekSize(), + 0u, + CacheSettingsHelper::getGmmUsageType(drmAllocation->getAllocationType(), false, *gmmHelper->getHardwareInfo()), + false, + allocationData.storageInfo, + true); + drmAllocation->setGmm(gmm, i); + + if (areBosSharedObjects == false) { + bo->setAddress(gpuRange); + gpuRange += bo->peekSize(); + bo->setUnmapSize(sizes[i]); + pushSharedBufferObject(bo); + } + drmAllocation->getBufferObjectToModify(i) = bo; + } + + return drmAllocation; +} + GraphicsAllocation *DrmMemoryManager::createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) { if (isHostIpcAllocation) { return createUSMHostAllocationFromSharedHandle(handle, properties, false); @@ -1468,6 +1564,7 @@ bool DrmMemoryManager::createDrmAllocation(Drm *drm, DrmAllocation *allocation, allocation->resizeBufferObjects(handles); bos.resize(handles); } + allocation->setNumHandles(handles); for (auto handleId = 0u; handleId < handles; handleId++, currentBank++) { if (currentBank == banksCnt) { diff --git a/shared/source/os_interface/linux/drm_memory_manager.h b/shared/source/os_interface/linux/drm_memory_manager.h index 6c7755cd41..882a776671 100644 --- a/shared/source/os_interface/linux/drm_memory_manager.h +++ b/shared/source/os_interface/linux/drm_memory_manager.h @@ -36,6 +36,7 @@ class DrmMemoryManager : public MemoryManager { void freeGraphicsMemoryImpl(GraphicsAllocation *gfxAllocation, bool isImportedAllocation) override; void handleFenceCompletion(GraphicsAllocation *allocation) override; GraphicsAllocation *createGraphicsAllocationFromExistingStorage(AllocationProperties &properties, void *ptr, MultiGraphicsAllocation &multiGraphicsAllocation) override; + GraphicsAllocation *createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override; GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override; void closeSharedHandle(GraphicsAllocation *gfxAllocation) override; GraphicsAllocation *createPaddedAllocation(GraphicsAllocation *inputGraphicsAllocation, size_t sizeWithPadding) override; @@ -88,7 +89,7 @@ class DrmMemoryManager : public MemoryManager { } protected: - BufferObject *findAndReferenceSharedBufferObject(int boHandle, uint32_t rootDeviceIndex); + MOCKABLE_VIRTUAL BufferObject *findAndReferenceSharedBufferObject(int boHandle, uint32_t rootDeviceIndex); void eraseSharedBufferObject(BufferObject *bo); void pushSharedBufferObject(BufferObject *bo); BufferObject *allocUserptr(uintptr_t address, size_t size, uint64_t flags, uint32_t rootDeviceIndex); diff --git a/shared/source/os_interface/windows/wddm_memory_manager.cpp b/shared/source/os_interface/windows/wddm_memory_manager.cpp index c8e936a61b..2a540a4a07 100644 --- a/shared/source/os_interface/windows/wddm_memory_manager.cpp +++ b/shared/source/os_interface/windows/wddm_memory_manager.cpp @@ -451,6 +451,10 @@ GraphicsAllocation *WddmMemoryManager::createAllocationFromHandle(osHandle handl return allocation.release(); } +GraphicsAllocation *WddmMemoryManager::createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) { + return nullptr; +} + GraphicsAllocation *WddmMemoryManager::createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) { return createAllocationFromHandle(handle, requireSpecificBitness, false, properties.allocationType, properties.rootDeviceIndex); } diff --git a/shared/source/os_interface/windows/wddm_memory_manager.h b/shared/source/os_interface/windows/wddm_memory_manager.h index 6f2fa3fba0..765634bd17 100644 --- a/shared/source/os_interface/windows/wddm_memory_manager.h +++ b/shared/source/os_interface/windows/wddm_memory_manager.h @@ -44,6 +44,7 @@ class WddmMemoryManager : public MemoryManager { void freeGraphicsMemoryImpl(GraphicsAllocation *gfxAllocation, bool isImportedAllocation) override; void handleFenceCompletion(GraphicsAllocation *allocation) override; + GraphicsAllocation *createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override; GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override; GraphicsAllocation *createGraphicsAllocationFromNTHandle(void *handle, uint32_t rootDeviceIndex, AllocationType allocType) override; diff --git a/shared/test/common/fixtures/memory_allocator_multi_device_fixture.h b/shared/test/common/fixtures/memory_allocator_multi_device_fixture.h index 0e833202bb..60dc0dbc28 100644 --- a/shared/test/common/fixtures/memory_allocator_multi_device_fixture.h +++ b/shared/test/common/fixtures/memory_allocator_multi_device_fixture.h @@ -62,3 +62,41 @@ class MemoryAllocatorMultiDeviceFixture : public MemoryManagementFixture, public DebugManagerStateRestore restorer; bool isOsAgnosticMemoryManager; }; + +template +class MemoryAllocatorMultiDeviceAndMultiTileFixture : public MemoryManagementFixture, public MemoryAllocatorMultiDeviceSystemSpecificFixture, public ::testing::TestWithParam { + public: + void SetUp() override { + MemoryManagementFixture::SetUp(); + + isOsAgnosticMemoryManager = GetParam(); + DebugManager.flags.CreateMultipleRootDevices.set(numRootDevices); + DebugManager.flags.CreateMultipleRootDevices.set(numSubDevices); + VariableBackup backup(&ultHwConfig); + ultHwConfig.useMockedPrepareDeviceEnvironmentsFunc = false; + ultHwConfig.forceOsAgnosticMemoryManager = isOsAgnosticMemoryManager; + + executionEnvironment = new MockExecutionEnvironment(defaultHwInfo.get(), true, numRootDevices); + devices = DeviceFactory::createDevices(*executionEnvironment); + memoryManager = executionEnvironment->memoryManager.get(); + + if (!isOsAgnosticMemoryManager) { + MemoryAllocatorMultiDeviceSystemSpecificFixture::SetUp(*executionEnvironment); + } + } + + void TearDown() override { + if (!isOsAgnosticMemoryManager) { + MemoryAllocatorMultiDeviceSystemSpecificFixture::TearDown(*executionEnvironment); + } + } + + uint32_t getNumRootDevices() { return numRootDevices; } + + protected: + std::vector> devices; + ExecutionEnvironment *executionEnvironment = nullptr; + MemoryManager *memoryManager = nullptr; + DebugManagerStateRestore restorer; + bool isOsAgnosticMemoryManager; +}; diff --git a/shared/test/common/mocks/linux/mock_drm_memory_manager.cpp b/shared/test/common/mocks/linux/mock_drm_memory_manager.cpp index a909df8ffe..c15ccbda25 100644 --- a/shared/test/common/mocks/linux/mock_drm_memory_manager.cpp +++ b/shared/test/common/mocks/linux/mock_drm_memory_manager.cpp @@ -53,6 +53,7 @@ TestedDrmMemoryManager::TestedDrmMemoryManager(bool enableLocalMemory, lseekCalledCount = 0; closeInputFd = 0; closeCalledCount = 0; + this->executionEnvironment = &executionEnvironment; } void TestedDrmMemoryManager::injectPinBB(BufferObject *newPinBB, uint32_t rootDeviceIndex) { diff --git a/shared/test/common/mocks/linux/mock_drm_memory_manager.h b/shared/test/common/mocks/linux/mock_drm_memory_manager.h index fc4615f29f..30fae56279 100644 --- a/shared/test/common/mocks/linux/mock_drm_memory_manager.h +++ b/shared/test/common/mocks/linux/mock_drm_memory_manager.h @@ -8,6 +8,7 @@ #pragma once #include "shared/source/os_interface/linux/drm_memory_manager.h" #include "shared/test/common/mocks/mock_memory_manager.h" +#include "shared/test/common/os_interface/linux/device_command_stream_fixture.h" #include @@ -112,6 +113,15 @@ class TestedDrmMemoryManager : public MemoryManagerCreate { void forceLimitedRangeAllocator(uint64_t range); void overrideGfxPartition(GfxPartition *newGfxPartition); + BufferObject *findAndReferenceSharedBufferObject(int boHandle, uint32_t rootDeviceIndex) override { + if (failOnfindAndReferenceSharedBufferObject) { + DrmMockCustom drmMock(*executionEnvironment->rootDeviceEnvironments[rootDeviceIndex]); + auto patIndex = drmMock.getPatIndex(nullptr, AllocationType::BUFFER, CacheRegion::Default, CachePolicy::WriteBack, false); + return new (std::nothrow) BufferObject(&drmMock, patIndex, boHandle, 4096u, 2u); + } + return MemoryManagerCreate::findAndReferenceSharedBufferObject(boHandle, rootDeviceIndex); + } + DrmAllocation *allocate32BitGraphicsMemory(uint32_t rootDeviceIndex, size_t size, const void *ptr, AllocationType allocationType); ~TestedDrmMemoryManager() override; size_t peekSharedBosSize() { @@ -153,6 +163,10 @@ class TestedDrmMemoryManager : public MemoryManagerCreate { uint32_t alignedFreeWrapperCalled = 0u; uint32_t callsToCloseSharedHandle = 0; + bool failOnfindAndReferenceSharedBufferObject = false; + + ExecutionEnvironment *executionEnvironment = nullptr; + protected: std::mutex unreferenceMtx; std::mutex releaseGpuRangeMtx; diff --git a/shared/test/common/mocks/mock_memory_manager.h b/shared/test/common/mocks/mock_memory_manager.h index 5a70e50c6f..b3f6afadf5 100644 --- a/shared/test/common/mocks/mock_memory_manager.h +++ b/shared/test/common/mocks/mock_memory_manager.h @@ -302,6 +302,10 @@ class FailMemoryManager : public MockMemoryManager { return nullptr; } + GraphicsAllocation *createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { + return nullptr; + } + GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { return nullptr; } diff --git a/shared/test/common/os_interface/linux/device_command_stream_fixture.cpp b/shared/test/common/os_interface/linux/device_command_stream_fixture.cpp index c5b5f18e16..6013a9e038 100644 --- a/shared/test/common/os_interface/linux/device_command_stream_fixture.cpp +++ b/shared/test/common/os_interface/linux/device_command_stream_fixture.cpp @@ -109,6 +109,9 @@ int DrmMockCustom::ioctl(unsigned long request, void *arg) { primeToHandleParams->handle = outputHandle; inputFd = primeToHandleParams->fd; ioctl_cnt.primeFdToHandle++; + if (failOnPrimeFdToHandle == true) { + return -1; + } } break; case DRM_IOCTL_PRIME_HANDLE_TO_FD: { auto *handleToPrimeParams = (drm_prime_handle *)arg; diff --git a/shared/test/common/os_interface/linux/device_command_stream_fixture.h b/shared/test/common/os_interface/linux/device_command_stream_fixture.h index 0e57d65b58..83157cbcfe 100644 --- a/shared/test/common/os_interface/linux/device_command_stream_fixture.h +++ b/shared/test/common/os_interface/linux/device_command_stream_fixture.h @@ -212,6 +212,7 @@ class DrmMockCustom : public Drm { __u64 mmapOffsetExpected = 0; __u64 mmapOffsetFlags = 0; bool failOnMmapOffset = false; + bool failOnPrimeFdToHandle = false; int errnoValue = 0; diff --git a/shared/test/unit_test/device/neo_device_tests.cpp b/shared/test/unit_test/device/neo_device_tests.cpp index 8da941aaec..a406331f81 100644 --- a/shared/test/unit_test/device/neo_device_tests.cpp +++ b/shared/test/unit_test/device/neo_device_tests.cpp @@ -282,6 +282,7 @@ TEST_F(DeviceGetCapsTest, givenFlagEnabled64kbPagesWhenCallConstructorMemoryMana MockMemoryManager(ExecutionEnvironment &executionEnvironment) : MemoryManager(executionEnvironment) {} void addAllocationToHostPtrManager(GraphicsAllocation *memory) override{}; void removeAllocationFromHostPtrManager(GraphicsAllocation *memory) override{}; + GraphicsAllocation *createGraphicsAllocationFromMultipleSharedHandles(std::vector handles, AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { return nullptr; } GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override { return nullptr; }; GraphicsAllocation *createGraphicsAllocationFromNTHandle(void *handle, uint32_t rootDeviceIndex, AllocationType allocType) override { return nullptr; }; AllocationStatus populateOsHandles(OsHandleStorage &handleStorage, uint32_t rootDeviceIndex) override { return AllocationStatus::Success; }; diff --git a/shared/test/unit_test/memory_manager/graphics_allocation_tests.cpp b/shared/test/unit_test/memory_manager/graphics_allocation_tests.cpp index d0c1aeeb24..944c3982b4 100644 --- a/shared/test/unit_test/memory_manager/graphics_allocation_tests.cpp +++ b/shared/test/unit_test/memory_manager/graphics_allocation_tests.cpp @@ -216,6 +216,17 @@ TEST(GraphicsAllocationTest, givenDefaultGraphicsAllocationWhenInternalHandleIsB EXPECT_EQ(0llu, graphicsAllocation.peekInternalHandle(nullptr)); } +TEST(GraphicsAllocationTest, givenDefaultGraphicsAllocationWhenGettingNumHandlesThenZeroIsReturned) { + MockGraphicsAllocation graphicsAllocation; + EXPECT_EQ(0u, graphicsAllocation.getNumHandles()); +} + +TEST(GraphicsAllocationTest, givenDefaultGraphicsAllocationWhenGettingNumHandlesAfterSettingNonZeroNumberThenZeroIsReturned) { + MockGraphicsAllocation graphicsAllocation; + graphicsAllocation.setNumHandles(64u); + EXPECT_EQ(0u, graphicsAllocation.getNumHandles()); +} + TEST(GraphicsAllocationTest, givenGraphicsAllocationWhenQueryingUsedPageSizeThenCorrectSizeForMemoryPoolUsedIsReturned) { MemoryPool::Type page4kPools[] = {MemoryPool::MemoryNull,