mirror of
https://github.com/intel/compute-runtime.git
synced 2026-01-08 22:12:59 +08:00
feature: Support for opaque IPC handles on Windows and Linux
- Added support for creating and managing opaque IPC NT handles in the WDDM layer. - Introduced a new flag `shareableWithoutNTHandle` to indicate if memory can be shared without an NT handle. - Updated the `isShareableMemory` method to accommodate this new flag. - Added debug variable EnableShareableWithoutNTHandle to control the behavior of sharing memory without NT handles until requested. - Updated Linux path to enable sharing DMA Buf FDs between processes for use in pidfd_getfd Related-To: NEO-15345 , NEO-15346 , NEO-15347, NEO-10380 Signed-off-by: Neil R. Spruit <neil.r.spruit@intel.com>
This commit is contained in:
committed by
Compute-Runtime-Automation
parent
274c5043b9
commit
46b1b2783b
@@ -8,6 +8,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "shared/source/memory_manager/allocation_type.h"
|
||||
#include "shared/source/memory_manager/graphics_allocation.h"
|
||||
#include "shared/source/unified_memory/unified_memory.h"
|
||||
|
||||
#include "level_zero/core/source/helpers/api_handle_helper.h"
|
||||
@@ -30,6 +31,45 @@ struct Image;
|
||||
|
||||
class ContextExt;
|
||||
|
||||
#pragma pack(1)
|
||||
struct IpcMemoryData {
|
||||
uint64_t handle = 0;
|
||||
uint64_t poolOffset = 0;
|
||||
uint8_t type = 0;
|
||||
};
|
||||
#pragma pack()
|
||||
static_assert(sizeof(IpcMemoryData) <= ZE_MAX_IPC_HANDLE_SIZE, "IpcMemoryData is bigger than ZE_MAX_IPC_HANDLE_SIZE");
|
||||
|
||||
enum class IpcHandleType : uint8_t {
|
||||
fdHandle = 0,
|
||||
ntHandle = 1,
|
||||
maxHandle
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct IpcOpaqueMemoryData {
|
||||
union IpcHandle {
|
||||
int fd;
|
||||
uint64_t reserved;
|
||||
};
|
||||
IpcHandle handle = {};
|
||||
uint64_t poolOffset = 0;
|
||||
unsigned int processId = 0;
|
||||
IpcHandleType type = IpcHandleType::maxHandle;
|
||||
uint8_t memoryType = 0;
|
||||
};
|
||||
#pragma pack()
|
||||
static_assert(sizeof(IpcOpaqueMemoryData) <= ZE_MAX_IPC_HANDLE_SIZE, "IpcOpaqueMemoryData is bigger than ZE_MAX_IPC_HANDLE_SIZE");
|
||||
|
||||
struct IpcHandleTracking {
|
||||
uint64_t refcnt = 0;
|
||||
NEO::GraphicsAllocation *alloc = nullptr;
|
||||
uint32_t handleId = 0;
|
||||
uint64_t handle = 0;
|
||||
uint64_t ptr = 0;
|
||||
struct IpcMemoryData ipcData = {};
|
||||
};
|
||||
|
||||
struct Context : _ze_context_handle_t {
|
||||
inline static ze_memory_type_t parseUSMType(InternalMemoryType memoryType) {
|
||||
switch (memoryType) {
|
||||
@@ -170,8 +210,10 @@ struct Context : _ze_context_handle_t {
|
||||
ze_ipc_mem_handle_t *pIpcHandle) = 0;
|
||||
virtual ze_result_t putVirtualAddressSpaceIpcHandle(ze_ipc_mem_handle_t ipcHandle) = 0;
|
||||
virtual ze_result_t lockMemory(ze_device_handle_t hDevice, void *ptr, size_t size) = 0;
|
||||
virtual bool isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice) = 0;
|
||||
virtual void *getMemHandlePtr(ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, ze_ipc_memory_flags_t flags) = 0;
|
||||
virtual bool isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice, bool shareableWithoutNTHandle) = 0;
|
||||
virtual void *getMemHandlePtr(ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, unsigned int processId, ze_ipc_memory_flags_t flags) = 0;
|
||||
virtual void getDataFromIpcHandle(ze_device_handle_t hDevice, const ze_ipc_mem_handle_t ipcHandle, uint64_t &handle, uint8_t &type, unsigned int &processId, uint64_t &poolOffset) = 0;
|
||||
virtual bool isOpaqueHandleSupported(IpcHandleType *handleType) = 0;
|
||||
|
||||
virtual ze_result_t getPitchFor2dImage(
|
||||
ze_device_handle_t hDevice,
|
||||
|
||||
@@ -9,14 +9,17 @@
|
||||
|
||||
#include "shared/source/command_container/implicit_scaling.h"
|
||||
#include "shared/source/command_stream/command_stream_receiver.h"
|
||||
#include "shared/source/execution_environment/execution_environment.h"
|
||||
#include "shared/source/execution_environment/root_device_environment.h"
|
||||
#include "shared/source/helpers/aligned_memory.h"
|
||||
#include "shared/source/helpers/driver_model_type.h"
|
||||
#include "shared/source/helpers/gfx_core_helper.h"
|
||||
#include "shared/source/helpers/ptr_math.h"
|
||||
#include "shared/source/memory_manager/allocation_properties.h"
|
||||
#include "shared/source/memory_manager/memory_manager.h"
|
||||
#include "shared/source/memory_manager/memory_operations_handler.h"
|
||||
#include "shared/source/memory_manager/unified_memory_manager.h"
|
||||
#include "shared/source/os_interface/os_interface.h"
|
||||
#include "shared/source/utilities/cpu_info.h"
|
||||
|
||||
#include "level_zero/core/source/cmdlist/cmdlist.h"
|
||||
@@ -75,15 +78,15 @@ ContextImp::ContextImp(DriverHandle *driverHandle) {
|
||||
}
|
||||
contextSettings.enableSvmHeapReservation = platformSupportSvmHeapReservation;
|
||||
|
||||
bool pidfdOrSocket = true;
|
||||
bool useOpaqueHandle = true;
|
||||
for (auto &device : this->driverHandle->devices) {
|
||||
auto &productHelper = device->getNEODevice()->getProductHelper();
|
||||
if (!productHelper.isPidFdOrSocketForIpcSupported()) {
|
||||
pidfdOrSocket = false;
|
||||
useOpaqueHandle = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
contextSettings.enablePidfdOrSockets = pidfdOrSocket;
|
||||
contextSettings.enablePidfdOrSockets = useOpaqueHandle;
|
||||
}
|
||||
|
||||
ContextImp::~ContextImp() {
|
||||
@@ -135,6 +138,7 @@ ze_result_t ContextImp::allocHostMem(const ze_host_mem_alloc_desc_t *hostDesc,
|
||||
*ptr = getMemHandlePtr(this->devices.begin()->second,
|
||||
lookupTable.sharedHandleType.fd,
|
||||
NEO::AllocationType::bufferHostMemory,
|
||||
0u,
|
||||
flags);
|
||||
if (nullptr == *ptr) {
|
||||
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
|
||||
@@ -143,7 +147,7 @@ ze_result_t ContextImp::allocHostMem(const ze_host_mem_alloc_desc_t *hostDesc,
|
||||
UNRECOVERABLE_IF(!lookupTable.sharedHandleType.isNTHandle);
|
||||
*ptr = this->driverHandle->importNTHandle(this->devices.begin()->second,
|
||||
lookupTable.sharedHandleType.ntHandle,
|
||||
NEO::AllocationType::bufferHostMemory);
|
||||
NEO::AllocationType::bufferHostMemory, 0);
|
||||
if (*ptr == nullptr) {
|
||||
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
@@ -266,6 +270,7 @@ ze_result_t ContextImp::allocDeviceMem(ze_device_handle_t hDevice,
|
||||
*ptr = getMemHandlePtr(hDevice,
|
||||
lookupTable.sharedHandleType.fd,
|
||||
NEO::AllocationType::buffer,
|
||||
0u,
|
||||
flags);
|
||||
if (nullptr == *ptr) {
|
||||
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
|
||||
@@ -274,7 +279,8 @@ ze_result_t ContextImp::allocDeviceMem(ze_device_handle_t hDevice,
|
||||
UNRECOVERABLE_IF(!lookupTable.sharedHandleType.isNTHandle);
|
||||
*ptr = this->driverHandle->importNTHandle(hDevice,
|
||||
lookupTable.sharedHandleType.ntHandle,
|
||||
NEO::AllocationType::buffer);
|
||||
NEO::AllocationType::buffer,
|
||||
0);
|
||||
if (*ptr == nullptr) {
|
||||
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
@@ -289,7 +295,10 @@ ze_result_t ContextImp::allocDeviceMem(ze_device_handle_t hDevice,
|
||||
|
||||
deviceBitfields[rootDeviceIndex] = neoDevice->getDeviceBitfield();
|
||||
NEO::SVMAllocsManager::UnifiedMemoryProperties unifiedMemoryProperties(InternalMemoryType::deviceUnifiedMemory, alignment, this->driverHandle->rootDeviceIndices, deviceBitfields);
|
||||
unifiedMemoryProperties.allocationFlags.flags.shareable = isShareableMemory(deviceMemDesc->pNext, static_cast<uint32_t>(lookupTable.exportMemory), neoDevice);
|
||||
if (NEO::debugManager.flags.EnableShareableWithoutNTHandle.get()) {
|
||||
unifiedMemoryProperties.allocationFlags.flags.shareableWithoutNTHandle = 1;
|
||||
}
|
||||
unifiedMemoryProperties.allocationFlags.flags.shareable = isShareableMemory(deviceMemDesc->pNext, static_cast<uint32_t>(lookupTable.exportMemory), neoDevice, unifiedMemoryProperties.allocationFlags.flags.shareableWithoutNTHandle);
|
||||
unifiedMemoryProperties.device = neoDevice;
|
||||
unifiedMemoryProperties.allocationFlags.flags.compressedHint = isAllocationSuitableForCompression(lookupTable, *device, size);
|
||||
|
||||
@@ -799,7 +808,8 @@ ze_result_t ContextImp::getIpcMemHandlesImpl(const void *ptr,
|
||||
ipcType = InternalIpcMemoryType::hostUnifiedMemory;
|
||||
}
|
||||
|
||||
bool pidfdOrSocket = contextSettings.enablePidfdOrSockets;
|
||||
IpcHandleType handleType = IpcHandleType::maxHandle;
|
||||
bool useOpaqueHandle = isOpaqueHandleSupported(&handleType);
|
||||
uint32_t loopCount = numIpcHandles ? *numIpcHandles : 1u;
|
||||
for (uint32_t i = 0u; i < loopCount; i++) {
|
||||
uint64_t handle = 0;
|
||||
@@ -810,12 +820,12 @@ ze_result_t ContextImp::getIpcMemHandlesImpl(const void *ptr,
|
||||
|
||||
memoryManager->registerIpcExportedAllocation(alloc);
|
||||
|
||||
if (pidfdOrSocket) {
|
||||
if (useOpaqueHandle) {
|
||||
IpcOpaqueMemoryData &ipcData = *reinterpret_cast<IpcOpaqueMemoryData *>(pIpcHandles[i].data);
|
||||
setIPCHandleData<IpcOpaqueMemoryData>(alloc, handle, ipcData, reinterpret_cast<uint64_t>(ptr), static_cast<uint8_t>(ipcType), usmPool);
|
||||
setIPCHandleData<IpcOpaqueMemoryData>(alloc, handle, ipcData, reinterpret_cast<uint64_t>(ptr), static_cast<uint8_t>(ipcType), usmPool, handleType);
|
||||
} else {
|
||||
IpcMemoryData &ipcData = *reinterpret_cast<IpcMemoryData *>(pIpcHandles[i].data);
|
||||
setIPCHandleData<IpcMemoryData>(alloc, handle, ipcData, reinterpret_cast<uint64_t>(ptr), static_cast<uint8_t>(ipcType), usmPool);
|
||||
setIPCHandleData<IpcMemoryData>(alloc, handle, ipcData, reinterpret_cast<uint64_t>(ptr), static_cast<uint8_t>(ipcType), usmPool, handleType);
|
||||
}
|
||||
}
|
||||
return ZE_RESULT_SUCCESS;
|
||||
@@ -837,11 +847,12 @@ ze_result_t ContextImp::openIpcMemHandle(ze_device_handle_t hDevice,
|
||||
const ze_ipc_mem_handle_t &pIpcHandle,
|
||||
ze_ipc_memory_flags_t flags,
|
||||
void **ptr) {
|
||||
using IpcDataT = IpcMemoryData;
|
||||
const IpcDataT &ipcData = *reinterpret_cast<const IpcDataT *>(pIpcHandle.data);
|
||||
uint64_t handle;
|
||||
uint8_t type;
|
||||
unsigned int processId;
|
||||
uint64_t poolOffset;
|
||||
|
||||
uint64_t handle = ipcData.handle;
|
||||
uint8_t type = ipcData.type;
|
||||
getDataFromIpcHandle(hDevice, pIpcHandle, handle, type, processId, poolOffset);
|
||||
|
||||
NEO::AllocationType allocationType = NEO::AllocationType::unknown;
|
||||
if (type == static_cast<uint8_t>(InternalIpcMemoryType::deviceUnifiedMemory)) {
|
||||
@@ -855,12 +866,13 @@ ze_result_t ContextImp::openIpcMemHandle(ze_device_handle_t hDevice,
|
||||
*ptr = getMemHandlePtr(hDevice,
|
||||
handle,
|
||||
allocationType,
|
||||
processId,
|
||||
flags);
|
||||
if (nullptr == *ptr) {
|
||||
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*ptr = ptrOffset(*ptr, ipcData.poolOffset);
|
||||
*ptr = ptrOffset(*ptr, poolOffset);
|
||||
|
||||
return ZE_RESULT_SUCCESS;
|
||||
}
|
||||
@@ -873,12 +885,15 @@ ze_result_t ContextImp::openIpcMemHandles(ze_device_handle_t hDevice,
|
||||
std::vector<NEO::osHandle> handles;
|
||||
handles.reserve(numIpcHandles);
|
||||
|
||||
using IpcDataT = IpcMemoryData;
|
||||
for (uint32_t i = 0; i < numIpcHandles; i++) {
|
||||
const IpcDataT &ipcData = *reinterpret_cast<const IpcDataT *>(pIpcHandles[i].data);
|
||||
uint64_t handle = ipcData.handle;
|
||||
uint64_t handle;
|
||||
uint8_t type;
|
||||
unsigned int processId;
|
||||
[[maybe_unused]] uint64_t poolOffset;
|
||||
|
||||
if (ipcData.type != static_cast<uint8_t>(InternalIpcMemoryType::deviceUnifiedMemory)) {
|
||||
getDataFromIpcHandle(hDevice, pIpcHandles[i], handle, type, processId, poolOffset);
|
||||
|
||||
if (type != static_cast<uint8_t>(InternalIpcMemoryType::deviceUnifiedMemory)) {
|
||||
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,8 +174,10 @@ struct ContextImp : Context, NEO::NonCopyableAndNonMovableClass {
|
||||
ContextSettings contextSettings;
|
||||
|
||||
bool isDeviceDefinedForThisContext(Device *inDevice);
|
||||
bool isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice) override;
|
||||
void *getMemHandlePtr(ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, ze_ipc_memory_flags_t flags) override;
|
||||
bool isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice, bool shareableWithoutNTHandle) override;
|
||||
void *getMemHandlePtr(ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, unsigned int processId, ze_ipc_memory_flags_t flags) override;
|
||||
void getDataFromIpcHandle(ze_device_handle_t hDevice, const ze_ipc_mem_handle_t ipcHandle, uint64_t &handle, uint8_t &type, unsigned int &processId, uint64_t &poolOffset) override;
|
||||
bool isOpaqueHandleSupported(IpcHandleType *handleType) override;
|
||||
|
||||
void initDeviceHandles(uint32_t numDevices, ze_device_handle_t *deviceHandles) {
|
||||
this->numDevices = numDevices;
|
||||
@@ -207,19 +209,25 @@ struct ContextImp : Context, NEO::NonCopyableAndNonMovableClass {
|
||||
protected:
|
||||
ze_result_t getIpcMemHandlesImpl(const void *ptr, uint32_t *numIpcHandles, ze_ipc_mem_handle_t *pIpcHandles);
|
||||
template <typename IpcDataT>
|
||||
void setIPCHandleData(NEO::GraphicsAllocation *graphicsAllocation, uint64_t handle, IpcDataT &ipcData, uint64_t ptrAddress, uint8_t type, NEO::UsmMemAllocPool *usmPool) {
|
||||
void setIPCHandleData(NEO::GraphicsAllocation *graphicsAllocation, uint64_t handle, IpcDataT &ipcData, uint64_t ptrAddress, uint8_t type, NEO::UsmMemAllocPool *usmPool, IpcHandleType handleType) {
|
||||
std::map<uint64_t, IpcHandleTracking *>::iterator ipcHandleIterator;
|
||||
|
||||
ipcData = {};
|
||||
if constexpr (std::is_same_v<IpcDataT, IpcMemoryData>) {
|
||||
ipcData.handle = handle;
|
||||
ipcData.type = type;
|
||||
} else if constexpr (std::is_same_v<IpcDataT, IpcOpaqueMemoryData>) {
|
||||
}
|
||||
if constexpr (std::is_same_v<IpcDataT, IpcOpaqueMemoryData>) {
|
||||
ipcData.memoryType = type;
|
||||
ipcData.processId = NEO::SysCalls::getCurrentProcessId();
|
||||
ipcData.type = IpcHandleType::fdHandle;
|
||||
ipcData.type = handleType;
|
||||
if (handleType == IpcHandleType::ntHandle) {
|
||||
ipcData.handle.reserved = handle;
|
||||
} else if (handleType == IpcHandleType::fdHandle) {
|
||||
// For fdHandle, we store the handle as an int
|
||||
ipcData.handle.fd = static_cast<int>(handle);
|
||||
}
|
||||
}
|
||||
|
||||
if (usmPool) {
|
||||
ipcData.poolOffset = usmPool->getOffsetInPool(addrToPtr(ptrAddress));
|
||||
|
||||
@@ -12,9 +12,23 @@
|
||||
#include "level_zero/core/source/context/context_imp.h"
|
||||
#include "level_zero/core/source/device/device.h"
|
||||
#include "level_zero/core/source/driver/driver_handle_imp.h"
|
||||
|
||||
#include <sys/prctl.h>
|
||||
namespace L0 {
|
||||
|
||||
bool ContextImp::isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice) {
|
||||
bool ContextImp::isOpaqueHandleSupported(IpcHandleType *handleType) {
|
||||
bool useOpaqueHandle = contextSettings.enablePidfdOrSockets;
|
||||
*handleType = IpcHandleType::fdHandle;
|
||||
if (useOpaqueHandle) {
|
||||
if (NEO::SysCalls::prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) == -1) {
|
||||
PRINT_DEBUG_STRING(NEO::debugManager.flags.PrintDebugMessages.get(), stderr, "prctl Syscall for PR_SET_PTRACER, PR_SET_PTRACER_ANY failed, using fallback mechanism for IPC handle exchange\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return useOpaqueHandle;
|
||||
}
|
||||
|
||||
bool ContextImp::isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice, bool shareableWithoutNTHandle) {
|
||||
if (exportableMemory) {
|
||||
return true;
|
||||
}
|
||||
@@ -22,31 +36,48 @@ bool ContextImp::isShareableMemory(const void *exportDesc, bool exportableMemory
|
||||
return false;
|
||||
}
|
||||
|
||||
void *ContextImp::getMemHandlePtr(ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, ze_ipc_memory_flags_t flags) {
|
||||
void *ContextImp::getMemHandlePtr(ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, unsigned int processId, ze_ipc_memory_flags_t flags) {
|
||||
auto neoDevice = Device::fromHandle(hDevice)->getNEODevice();
|
||||
auto &productHelper = neoDevice->getProductHelper();
|
||||
bool useOpaqueHandle = contextSettings.enablePidfdOrSockets;
|
||||
uint64_t importHandle = handle;
|
||||
|
||||
bool pidfdOrSocket = false;
|
||||
pidfdOrSocket = productHelper.isPidFdOrSocketForIpcSupported();
|
||||
|
||||
if (pidfdOrSocket) {
|
||||
if (useOpaqueHandle) {
|
||||
// With pidfd approach extract parent pid and target fd before importing handle
|
||||
pid_t exporterPid = 0;
|
||||
pid_t exporterPid = static_cast<pid_t>(processId);
|
||||
unsigned int flags = 0u;
|
||||
int pidfd = NEO::SysCalls::pidfdopen(exporterPid, flags);
|
||||
if (pidfd == -1) {
|
||||
PRINT_DEBUG_STRING(NEO::debugManager.flags.PrintDebugMessages.get(), stderr, "pidfd_open Syscall failed, using fallback mechanism for IPC handle exchange\n");
|
||||
} else {
|
||||
unsigned int flags = 0u;
|
||||
int newfd = NEO::SysCalls::pidfdgetfd(pidfd, 0, flags);
|
||||
int newfd = NEO::SysCalls::pidfdgetfd(pidfd, static_cast<int>(handle), flags);
|
||||
if (newfd < 0) {
|
||||
PRINT_DEBUG_STRING(NEO::debugManager.flags.PrintDebugMessages.get(), stderr, "pidfd_getfd Syscall failed, using fallback mechanism for IPC handle exchange\n");
|
||||
} else {
|
||||
importHandle = static_cast<uint64_t>(newfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NEO::SvmAllocationData allocDataInternal(neoDevice->getRootDeviceIndex());
|
||||
return this->driverHandle->importFdHandle(neoDevice, flags, handle, allocationType, nullptr, nullptr, allocDataInternal);
|
||||
return this->driverHandle->importFdHandle(neoDevice, flags, importHandle, allocationType, nullptr, nullptr, allocDataInternal);
|
||||
}
|
||||
|
||||
void ContextImp::getDataFromIpcHandle(ze_device_handle_t hDevice, const ze_ipc_mem_handle_t ipcHandle, uint64_t &handle, uint8_t &type, unsigned int &processId, uint64_t &poolOffset) {
|
||||
bool useOpaqueHandle = contextSettings.enablePidfdOrSockets;
|
||||
|
||||
if (useOpaqueHandle) {
|
||||
const IpcOpaqueMemoryData *ipcData = reinterpret_cast<const IpcOpaqueMemoryData *>(ipcHandle.data);
|
||||
handle = static_cast<uint64_t>(ipcData->handle.fd);
|
||||
type = ipcData->memoryType;
|
||||
processId = ipcData->processId;
|
||||
poolOffset = ipcData->poolOffset;
|
||||
} else {
|
||||
const IpcMemoryData *ipcData = reinterpret_cast<const IpcMemoryData *>(ipcHandle.data);
|
||||
handle = ipcData->handle;
|
||||
type = ipcData->type;
|
||||
poolOffset = ipcData->poolOffset;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace L0
|
||||
|
||||
@@ -1,24 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2024 Intel Corporation
|
||||
* Copyright (C) 2022-2025 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/device/device.h"
|
||||
#include "shared/source/execution_environment/execution_environment.h"
|
||||
#include "shared/source/execution_environment/root_device_environment.h"
|
||||
#include "shared/source/helpers/driver_model_type.h"
|
||||
#include "shared/source/memory_manager/memory_manager.h"
|
||||
#include "shared/source/memory_manager/unified_memory_manager.h"
|
||||
#include "shared/source/os_interface/linux/sys_calls.h"
|
||||
#include "shared/source/os_interface/os_interface.h"
|
||||
|
||||
#include "level_zero/core/source/context/context_imp.h"
|
||||
#include "level_zero/core/source/device/device.h"
|
||||
#include "level_zero/core/source/driver/driver_handle_imp.h"
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
namespace L0 {
|
||||
|
||||
bool ContextImp::isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice) {
|
||||
bool ContextImp::isOpaqueHandleSupported(IpcHandleType *handleType) {
|
||||
bool useOpaqueHandle = contextSettings.enablePidfdOrSockets;
|
||||
NEO::DriverModelType driverModelType = NEO::DriverModelType::unknown;
|
||||
auto rootDeviceEnvironment = this->getDriverHandle()->getMemoryManager()->peekExecutionEnvironment().rootDeviceEnvironments[0].get();
|
||||
if (rootDeviceEnvironment->osInterface) {
|
||||
driverModelType = rootDeviceEnvironment->osInterface->getDriverModel()->getDriverModelType();
|
||||
}
|
||||
if (driverModelType == NEO::DriverModelType::wddm) {
|
||||
*handleType = IpcHandleType::ntHandle;
|
||||
useOpaqueHandle = true;
|
||||
} else {
|
||||
*handleType = IpcHandleType::fdHandle;
|
||||
if (useOpaqueHandle) {
|
||||
if (NEO::SysCalls::prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) == -1) {
|
||||
PRINT_DEBUG_STRING(NEO::debugManager.flags.PrintDebugMessages.get(), stderr, "prctl Syscall for PR_SET_PTRACER, PR_SET_PTRACER_ANY failed, using fallback mechanism for IPC handle exchange\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return useOpaqueHandle;
|
||||
}
|
||||
|
||||
bool ContextImp::isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice, bool shareableWithoutNTHandle) {
|
||||
if (exportableMemory) {
|
||||
return true;
|
||||
}
|
||||
@@ -35,9 +61,11 @@ bool ContextImp::isShareableMemory(const void *exportDesc, bool exportableMemory
|
||||
void *ContextImp::getMemHandlePtr(ze_device_handle_t hDevice,
|
||||
uint64_t handle,
|
||||
NEO::AllocationType allocationType,
|
||||
unsigned int processId,
|
||||
ze_ipc_memory_flags_t flags) {
|
||||
L0::Device *device = L0::Device::fromHandle(hDevice);
|
||||
auto neoDevice = device->getNEODevice();
|
||||
bool useOpaqueHandle = contextSettings.enablePidfdOrSockets;
|
||||
NEO::DriverModelType driverType = NEO::DriverModelType::unknown;
|
||||
if (neoDevice->getRootDeviceEnvironment().osInterface) {
|
||||
driverType = neoDevice->getRootDeviceEnvironment().osInterface->getDriverModel()->getDriverModelType();
|
||||
@@ -46,13 +74,34 @@ void *ContextImp::getMemHandlePtr(ze_device_handle_t hDevice,
|
||||
if (isNTHandle) {
|
||||
return this->driverHandle->importNTHandle(hDevice,
|
||||
reinterpret_cast<void *>(handle),
|
||||
allocationType);
|
||||
allocationType,
|
||||
processId);
|
||||
} else if (driverType == NEO::DriverModelType::drm) {
|
||||
auto neoDevice = Device::fromHandle(hDevice)->getNEODevice();
|
||||
|
||||
NEO::SvmAllocationData allocDataInternal(neoDevice->getRootDeviceIndex());
|
||||
uint64_t importHandle = handle;
|
||||
if (useOpaqueHandle) {
|
||||
// With pidfd approach extract parent pid and target fd before importing handle
|
||||
pid_t exporterPid = static_cast<pid_t>(processId);
|
||||
unsigned int flags = 0u;
|
||||
int pidfd = NEO::SysCalls::pidfdopen(exporterPid, flags);
|
||||
if (pidfd == -1) {
|
||||
PRINT_DEBUG_STRING(NEO::debugManager.flags.PrintDebugMessages.get(), stderr, "pidfd_open Syscall failed, using fallback mechanism for IPC handle exchange\n");
|
||||
} else {
|
||||
unsigned int flags = 0u;
|
||||
int newfd = NEO::SysCalls::pidfdgetfd(pidfd, static_cast<int>(handle), flags);
|
||||
if (newfd < 0) {
|
||||
PRINT_DEBUG_STRING(NEO::debugManager.flags.PrintDebugMessages.get(), stderr, "pidfd_getfd Syscall failed, using fallback mechanism for IPC handle exchange\n");
|
||||
} else {
|
||||
importHandle = static_cast<uint64_t>(newfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this->driverHandle->importFdHandle(neoDevice,
|
||||
flags,
|
||||
handle,
|
||||
importHandle,
|
||||
allocationType,
|
||||
nullptr,
|
||||
nullptr,
|
||||
@@ -62,4 +111,30 @@ void *ContextImp::getMemHandlePtr(ze_device_handle_t hDevice,
|
||||
}
|
||||
}
|
||||
|
||||
void ContextImp::getDataFromIpcHandle(ze_device_handle_t hDevice, const ze_ipc_mem_handle_t ipcHandle, uint64_t &handle, uint8_t &type, unsigned int &processId, uint64_t &poolOffset) {
|
||||
bool useOpaqueHandle = contextSettings.enablePidfdOrSockets;
|
||||
L0::Device *device = L0::Device::fromHandle(hDevice);
|
||||
auto neoDevice = device->getNEODevice();
|
||||
NEO::DriverModelType driverModelType = NEO::DriverModelType::unknown;
|
||||
if (neoDevice->getRootDeviceEnvironment().osInterface) {
|
||||
driverModelType = neoDevice->getRootDeviceEnvironment().osInterface->getDriverModel()->getDriverModelType();
|
||||
}
|
||||
if (driverModelType == NEO::DriverModelType::wddm) {
|
||||
useOpaqueHandle = true;
|
||||
}
|
||||
|
||||
if (useOpaqueHandle) {
|
||||
const IpcOpaqueMemoryData *ipcData = reinterpret_cast<const IpcOpaqueMemoryData *>(ipcHandle.data);
|
||||
handle = static_cast<uint64_t>(ipcData->handle.fd);
|
||||
type = ipcData->memoryType;
|
||||
processId = ipcData->processId;
|
||||
poolOffset = ipcData->poolOffset;
|
||||
} else {
|
||||
const IpcMemoryData *ipcData = reinterpret_cast<const IpcMemoryData *>(ipcHandle.data);
|
||||
handle = ipcData->handle;
|
||||
type = ipcData->type;
|
||||
poolOffset = ipcData->poolOffset;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace L0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2024 Intel Corporation
|
||||
* Copyright (C) 2022-2025 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@@ -10,16 +10,33 @@
|
||||
|
||||
namespace L0 {
|
||||
|
||||
bool ContextImp::isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice) {
|
||||
bool ContextImp::isOpaqueHandleSupported(IpcHandleType *handleType) {
|
||||
*handleType = IpcHandleType::ntHandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextImp::isShareableMemory(const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice, bool shareableWithoutNTHandle) {
|
||||
if (exportableMemory) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shareableWithoutNTHandle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void *ContextImp::getMemHandlePtr(ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, ze_ipc_memory_flags_t flags) {
|
||||
return this->driverHandle->importNTHandle(hDevice, reinterpret_cast<void *>(handle), allocationType);
|
||||
void *ContextImp::getMemHandlePtr(ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, unsigned int processId, ze_ipc_memory_flags_t flags) {
|
||||
return this->driverHandle->importNTHandle(hDevice, reinterpret_cast<void *>(handle), allocationType, processId);
|
||||
}
|
||||
|
||||
void ContextImp::getDataFromIpcHandle(ze_device_handle_t hDevice, const ze_ipc_mem_handle_t ipcHandle, uint64_t &handle, uint8_t &type, unsigned int &processId, uint64_t &poolOffset) {
|
||||
const IpcOpaqueMemoryData *ipcData = reinterpret_cast<const IpcOpaqueMemoryData *>(ipcHandle.data);
|
||||
handle = static_cast<uint64_t>(ipcData->handle.reserved);
|
||||
type = ipcData->memoryType;
|
||||
processId = ipcData->processId;
|
||||
poolOffset = ipcData->poolOffset;
|
||||
}
|
||||
|
||||
} // namespace L0
|
||||
|
||||
@@ -886,12 +886,13 @@ NEO::GraphicsAllocation *DriverHandleImp::getPeerAllocation(Device *device,
|
||||
return alloc;
|
||||
}
|
||||
|
||||
void *DriverHandleImp::importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType) {
|
||||
void *DriverHandleImp::importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType, uint32_t parentProcessId) {
|
||||
auto neoDevice = Device::fromHandle(hDevice)->getNEODevice();
|
||||
|
||||
bool isHostIpcAllocation = (allocationType == NEO::AllocationType::bufferHostMemory) ? true : false;
|
||||
|
||||
NEO::MemoryManager::OsHandleData osHandleData{handle};
|
||||
osHandleData.parentProcessId = parentProcessId;
|
||||
NEO::AllocationProperties properties{neoDevice->getRootDeviceIndex(),
|
||||
MemoryConstants::pageSize,
|
||||
allocationType,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "shared/source/os_interface/sys_calls_common.h"
|
||||
|
||||
#include "level_zero/api/extensions/public/ze_exp_ext.h"
|
||||
#include "level_zero/core/source/context/context.h"
|
||||
#include "level_zero/core/source/driver/driver_handle.h"
|
||||
#include "level_zero/ze_intel_gpu.h"
|
||||
|
||||
@@ -27,43 +28,6 @@ struct FabricVertex;
|
||||
struct FabricEdge;
|
||||
struct Image;
|
||||
class ExternalSemaphoreController;
|
||||
|
||||
#pragma pack(1)
|
||||
struct IpcMemoryData {
|
||||
uint64_t handle = 0;
|
||||
uint64_t poolOffset = 0;
|
||||
uint8_t type = 0;
|
||||
};
|
||||
#pragma pack()
|
||||
static_assert(sizeof(IpcMemoryData) <= ZE_MAX_IPC_HANDLE_SIZE, "IpcMemoryData is bigger than ZE_MAX_IPC_HANDLE_SIZE");
|
||||
|
||||
enum class IpcHandleType : uint8_t {
|
||||
fdHandle = 0,
|
||||
maxHandle
|
||||
};
|
||||
|
||||
struct IpcOpaqueMemoryData {
|
||||
union IpcHandle {
|
||||
int fd;
|
||||
uint64_t reserved;
|
||||
};
|
||||
IpcHandle handle = {};
|
||||
uint64_t poolOffset = 0;
|
||||
unsigned int processId = 0;
|
||||
IpcHandleType type = IpcHandleType::maxHandle;
|
||||
uint8_t memoryType = 0;
|
||||
};
|
||||
static_assert(sizeof(IpcOpaqueMemoryData) <= ZE_MAX_IPC_HANDLE_SIZE, "IpcOpaqueMemoryData is bigger than ZE_MAX_IPC_HANDLE_SIZE");
|
||||
|
||||
struct IpcHandleTracking {
|
||||
uint64_t refcnt = 0;
|
||||
NEO::GraphicsAllocation *alloc = nullptr;
|
||||
uint32_t handleId = 0;
|
||||
uint64_t handle = 0;
|
||||
uint64_t ptr = 0;
|
||||
struct IpcMemoryData ipcData = {};
|
||||
};
|
||||
|
||||
struct DriverHandleImp : public DriverHandle {
|
||||
~DriverHandleImp() override;
|
||||
DriverHandleImp();
|
||||
@@ -86,7 +50,7 @@ struct DriverHandleImp : public DriverHandle {
|
||||
void setMemoryManager(NEO::MemoryManager *memoryManager) override;
|
||||
MOCKABLE_VIRTUAL void *importFdHandle(NEO::Device *neoDevice, ze_ipc_memory_flags_t flags, uint64_t handle, NEO::AllocationType allocationType, void *basePointer, NEO::GraphicsAllocation **pAlloc, NEO::SvmAllocationData &mappedPeerAllocData);
|
||||
MOCKABLE_VIRTUAL void *importFdHandles(NEO::Device *neoDevice, ze_ipc_memory_flags_t flags, const std::vector<NEO::osHandle> &handles, void *basePointer, NEO::GraphicsAllocation **pAlloc, NEO::SvmAllocationData &mappedPeerAllocData);
|
||||
MOCKABLE_VIRTUAL void *importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType);
|
||||
MOCKABLE_VIRTUAL void *importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType, uint32_t parentProcessId);
|
||||
NEO::SVMAllocsManager *getSvmAllocsManager() override;
|
||||
NEO::StagingBufferManager *getStagingBufferManager() override;
|
||||
ze_result_t initialize(std::vector<std::unique_ptr<NEO::Device>> neoDevices);
|
||||
|
||||
@@ -85,7 +85,7 @@ struct DriverHandleGetMemHandlePtrMock : public L0::DriverHandleImp {
|
||||
return &mockFd;
|
||||
}
|
||||
|
||||
void *importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType) override {
|
||||
void *importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType, uint32_t parentProcessId) override {
|
||||
if (failHandleLookup) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ void MemoryExportImportTest::SetUp() {
|
||||
context->deviceBitfields.insert({neoDevice->getRootDeviceIndex(), neoDevice->getDeviceBitfield()});
|
||||
}
|
||||
|
||||
void *DriverHandleGetMemHandleMock::importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType) {
|
||||
void *DriverHandleGetMemHandleMock::importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType, uint32_t parentProcessId) {
|
||||
if (mockHandle == allocationHandleMap.second) {
|
||||
return allocationHandleMap.first;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ void MemoryExportImportWSLTest::TearDown() {
|
||||
delete currMemoryManager;
|
||||
}
|
||||
|
||||
void *DriverHandleGetWinHandleMock::importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType) {
|
||||
void *DriverHandleGetWinHandleMock::importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType, uint32_t parentProcessId) {
|
||||
if (mockHandle == allocationMap.second) {
|
||||
return allocationMap.first;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ struct MemoryExportImportTest : public ::testing::Test {
|
||||
};
|
||||
|
||||
struct DriverHandleGetMemHandleMock : public L0::DriverHandleImp {
|
||||
void *importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType) override;
|
||||
void *importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType, uint32_t parentProcessId) override;
|
||||
void *importFdHandle(NEO::Device *neoDevice, ze_ipc_memory_flags_t flags, uint64_t handle,
|
||||
NEO::AllocationType allocationType, void *basePointer,
|
||||
NEO::GraphicsAllocation **pAloc, NEO::SvmAllocationData &mappedPeerAllocData) override;
|
||||
@@ -128,7 +128,7 @@ struct MemoryExportImportWSLTest : public ::testing::Test {
|
||||
};
|
||||
|
||||
struct DriverHandleGetWinHandleMock : public L0::DriverHandleImp {
|
||||
void *importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType) override;
|
||||
void *importNTHandle(ze_device_handle_t hDevice, void *handle, NEO::AllocationType allocationType, uint32_t parentProcessId) override;
|
||||
|
||||
uint64_t mockHandle = 57;
|
||||
std::pair<void *, uint64_t> allocationMap;
|
||||
|
||||
@@ -79,15 +79,17 @@ struct Mock<Context> : public Context {
|
||||
ADDMETHOD_NOBASE(getVirtualAddressSpaceIpcHandle, ze_result_t, ZE_RESULT_SUCCESS, (ze_device_handle_t, ze_ipc_mem_handle_t *));
|
||||
ADDMETHOD_NOBASE(putVirtualAddressSpaceIpcHandle, ze_result_t, ZE_RESULT_SUCCESS, (ze_ipc_mem_handle_t ipcHandle));
|
||||
ADDMETHOD_NOBASE(lockMemory, ze_result_t, ZE_RESULT_SUCCESS, (ze_device_handle_t hDevice, void *ptr, size_t size));
|
||||
ADDMETHOD_NOBASE(isShareableMemory, bool, true, (const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice));
|
||||
ADDMETHOD_NOBASE(getMemHandlePtr, void *, nullptr, (ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, ze_ipc_memory_flags_t flags));
|
||||
ADDMETHOD_NOBASE(isShareableMemory, bool, true, (const void *exportDesc, bool exportableMemory, NEO::Device *neoDevice, bool shareableWithoutNTHandle));
|
||||
ADDMETHOD_NOBASE(isOpaqueHandleSupported, bool, true, (IpcHandleType * handleType));
|
||||
ADDMETHOD_NOBASE(getMemHandlePtr, void *, nullptr, (ze_device_handle_t hDevice, uint64_t handle, NEO::AllocationType allocationType, unsigned int processId, ze_ipc_memory_flags_t flags));
|
||||
ADDMETHOD_NOBASE_VOIDRETURN(getDataFromIpcHandle, (ze_device_handle_t hDevice, const ze_ipc_mem_handle_t ipcHandle, uint64_t &handle, uint8_t &type, unsigned int &processId, uint64_t &poolOffset));
|
||||
ADDMETHOD_NOBASE(getPitchFor2dImage, ze_result_t, ZE_RESULT_SUCCESS, (ze_device_handle_t, size_t, size_t, unsigned int, size_t *));
|
||||
ADDMETHOD_NOBASE(getContextExt, ContextExt *, nullptr, ());
|
||||
};
|
||||
|
||||
struct ContextShareableMock : public L0::ContextImp {
|
||||
ContextShareableMock(L0::DriverHandle *driverHandle) : L0::ContextImp(driverHandle) {}
|
||||
bool isShareableMemory(const void *pNext, bool exportableMemory, NEO::Device *neoDevice) override {
|
||||
bool isShareableMemory(const void *pNext, bool exportableMemory, NEO::Device *neoDevice, bool shareableWithoutNTHandle) override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "shared/source/gmm_helper/gmm.h"
|
||||
#include "shared/source/memory_manager/gfx_partition.h"
|
||||
#include "shared/source/os_interface/device_factory.h"
|
||||
#include "shared/source/unified_memory/unified_memory.h"
|
||||
#include "shared/source/utilities/cpu_info.h"
|
||||
#include "shared/test/common/mocks/mock_bindless_heaps_helper.h"
|
||||
#include "shared/test/common/mocks/mock_command_stream_receiver.h"
|
||||
@@ -2797,5 +2798,267 @@ HWTEST_F(ContextTest, givenMakeImageResidentThenMakeImageResidentIsCalledWithFor
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
}
|
||||
|
||||
class ContextWhiteboxForIpcTesting : public ::L0::ContextImp {
|
||||
public:
|
||||
ContextWhiteboxForIpcTesting(L0::DriverHandle *driverHandle) : L0::ContextImp(driverHandle) {}
|
||||
|
||||
using ::L0::ContextImp::setIPCHandleData;
|
||||
};
|
||||
|
||||
TEST_F(ContextTest, whenCallingSetIPCHandleDataWithIpcMemoryDataTypeThenIpcDataIsSetInHandleTracking) {
|
||||
ze_context_handle_t hContext;
|
||||
ze_context_desc_t desc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC, nullptr, 0};
|
||||
|
||||
ze_result_t res = driverHandle->createContext(&desc, 0u, nullptr, &hContext);
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
|
||||
ContextWhiteboxForIpcTesting contextWhitebox(driverHandle.get());
|
||||
|
||||
// Create a mock graphics allocation
|
||||
NEO::MockGraphicsAllocation mockAllocation;
|
||||
|
||||
// Set up test data
|
||||
uint64_t handle = 12345;
|
||||
L0::IpcMemoryData ipcData;
|
||||
ipcData.handle = handle;
|
||||
ipcData.type = static_cast<uint8_t>(InternalMemoryType::deviceUnifiedMemory);
|
||||
ipcData.poolOffset = 0;
|
||||
|
||||
uint64_t ptrAddress = 0x1000;
|
||||
uint8_t type = static_cast<uint8_t>(InternalMemoryType::deviceUnifiedMemory);
|
||||
|
||||
// Verify IPC handle map is initially empty
|
||||
EXPECT_TRUE(driverHandle->getIPCHandleMap().empty());
|
||||
|
||||
// Call setIPCHandleData with IpcMemoryData type
|
||||
contextWhitebox.setIPCHandleData<L0::IpcMemoryData>(&mockAllocation, handle, ipcData, ptrAddress, type, nullptr, L0::IpcHandleType::fdHandle);
|
||||
|
||||
// Verify the handle was added to the IPC handle map
|
||||
auto &ipcHandleMap = driverHandle->getIPCHandleMap();
|
||||
EXPECT_EQ(1u, ipcHandleMap.size());
|
||||
|
||||
// Verify the handle tracking entry
|
||||
auto handleIterator = ipcHandleMap.find(handle);
|
||||
ASSERT_NE(handleIterator, ipcHandleMap.end());
|
||||
|
||||
L0::IpcHandleTracking *handleTracking = handleIterator->second;
|
||||
EXPECT_NE(nullptr, handleTracking);
|
||||
EXPECT_EQ(&mockAllocation, handleTracking->alloc);
|
||||
EXPECT_EQ(1u, handleTracking->refcnt);
|
||||
EXPECT_EQ(ptrAddress, handleTracking->ptr);
|
||||
EXPECT_EQ(handle, handleTracking->handle);
|
||||
|
||||
// Verify that the ipcData field is set
|
||||
EXPECT_EQ(handle, handleTracking->ipcData.handle);
|
||||
EXPECT_EQ(type, handleTracking->ipcData.type);
|
||||
EXPECT_EQ(0u, handleTracking->ipcData.poolOffset);
|
||||
|
||||
// Clean up - remove the entry from the map to avoid issues in teardown
|
||||
delete handleTracking;
|
||||
driverHandle->getIPCHandleMap().clear();
|
||||
|
||||
ContextImp *contextImp = static_cast<ContextImp *>(L0::Context::fromHandle(hContext));
|
||||
res = contextImp->destroy();
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
}
|
||||
|
||||
TEST_F(ContextTest, whenCallingSetIPCHandleDataWithIpcOpaqueMemoryDataTypeThenIpcDataIsNotSetInHandleTracking) {
|
||||
ze_context_handle_t hContext;
|
||||
ze_context_desc_t desc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC, nullptr, 0};
|
||||
|
||||
ze_result_t res = driverHandle->createContext(&desc, 0u, nullptr, &hContext);
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
|
||||
ContextWhiteboxForIpcTesting contextWhitebox(driverHandle.get());
|
||||
|
||||
// Create a mock graphics allocation
|
||||
NEO::MockGraphicsAllocation mockAllocation;
|
||||
|
||||
// Set up test data for IpcOpaqueMemoryData
|
||||
uint64_t handle = 67890;
|
||||
L0::IpcOpaqueMemoryData opaqueIpcData;
|
||||
opaqueIpcData.handle.fd = static_cast<int>(handle);
|
||||
opaqueIpcData.memoryType = static_cast<uint8_t>(InternalMemoryType::sharedUnifiedMemory);
|
||||
opaqueIpcData.processId = 1234;
|
||||
opaqueIpcData.type = L0::IpcHandleType::fdHandle;
|
||||
opaqueIpcData.poolOffset = 0;
|
||||
|
||||
uint64_t ptrAddress = 0x2000;
|
||||
uint8_t type = static_cast<uint8_t>(InternalMemoryType::sharedUnifiedMemory);
|
||||
|
||||
// Verify IPC handle map is initially empty
|
||||
EXPECT_TRUE(driverHandle->getIPCHandleMap().empty());
|
||||
|
||||
// Call setIPCHandleData with IpcOpaqueMemoryData type
|
||||
contextWhitebox.setIPCHandleData<L0::IpcOpaqueMemoryData>(&mockAllocation, handle, opaqueIpcData, ptrAddress, type, nullptr, L0::IpcHandleType::fdHandle);
|
||||
|
||||
// Verify the handle was added to the IPC handle map
|
||||
auto &ipcHandleMap = driverHandle->getIPCHandleMap();
|
||||
EXPECT_EQ(1u, ipcHandleMap.size());
|
||||
|
||||
// Verify the handle tracking entry
|
||||
auto handleIterator = ipcHandleMap.find(handle);
|
||||
ASSERT_NE(handleIterator, ipcHandleMap.end());
|
||||
|
||||
L0::IpcHandleTracking *handleTracking = handleIterator->second;
|
||||
EXPECT_NE(nullptr, handleTracking);
|
||||
EXPECT_EQ(&mockAllocation, handleTracking->alloc);
|
||||
EXPECT_EQ(1u, handleTracking->refcnt);
|
||||
EXPECT_EQ(ptrAddress, handleTracking->ptr);
|
||||
EXPECT_EQ(handle, handleTracking->handle);
|
||||
|
||||
// Verify that the ipcData field is NOT set when using IpcOpaqueMemoryData
|
||||
// The ipcData field should retain its default/empty values since the constexpr condition is false
|
||||
EXPECT_EQ(0u, handleTracking->ipcData.handle); // Should be default value (0)
|
||||
EXPECT_EQ(0u, handleTracking->ipcData.type); // Should be default value (0)
|
||||
EXPECT_EQ(0u, handleTracking->ipcData.poolOffset); // Should be default value (0)
|
||||
|
||||
// Clean up - remove the entry from the map to avoid issues in teardown
|
||||
delete handleTracking;
|
||||
driverHandle->getIPCHandleMap().clear();
|
||||
|
||||
ContextImp *contextImp = static_cast<ContextImp *>(L0::Context::fromHandle(hContext));
|
||||
res = contextImp->destroy();
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
}
|
||||
|
||||
TEST_F(ContextTest, whenCallingSetIPCHandleDataWithInvalidIpcHandleTypeThenHandleUnionIsNotSet) {
|
||||
ze_context_handle_t hContext;
|
||||
ze_context_desc_t desc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC, nullptr, 0};
|
||||
|
||||
ze_result_t res = driverHandle->createContext(&desc, 0u, nullptr, &hContext);
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
|
||||
ContextWhiteboxForIpcTesting contextWhitebox(driverHandle.get());
|
||||
|
||||
// Create a mock graphics allocation
|
||||
NEO::MockGraphicsAllocation mockAllocation;
|
||||
|
||||
// Set up test data with invalid IpcHandleType
|
||||
uint64_t handle = 11111;
|
||||
L0::IpcOpaqueMemoryData opaqueIpcData;
|
||||
uint64_t ptrAddress = 0x3000;
|
||||
uint8_t type = static_cast<uint8_t>(InternalMemoryType::deviceUnifiedMemory);
|
||||
|
||||
// Test with maxHandle (invalid but defined)
|
||||
L0::IpcHandleType invalidHandleType1 = L0::IpcHandleType::maxHandle;
|
||||
|
||||
// Verify IPC handle map is initially empty
|
||||
EXPECT_TRUE(driverHandle->getIPCHandleMap().empty());
|
||||
|
||||
// Call setIPCHandleData with invalid handle type (maxHandle)
|
||||
contextWhitebox.setIPCHandleData<L0::IpcOpaqueMemoryData>(&mockAllocation, handle, opaqueIpcData, ptrAddress, type, nullptr, invalidHandleType1);
|
||||
|
||||
// Verify the handle was added to the IPC handle map
|
||||
auto &ipcHandleMap = driverHandle->getIPCHandleMap();
|
||||
EXPECT_EQ(1u, ipcHandleMap.size());
|
||||
|
||||
// Verify the IpcOpaqueMemoryData values
|
||||
EXPECT_EQ(type, opaqueIpcData.memoryType);
|
||||
EXPECT_EQ(invalidHandleType1, opaqueIpcData.type);
|
||||
EXPECT_NE(0u, opaqueIpcData.processId); // Should be set to current process ID
|
||||
|
||||
// Clean up
|
||||
auto handleIterator = ipcHandleMap.find(handle);
|
||||
ASSERT_NE(handleIterator, ipcHandleMap.end());
|
||||
delete handleIterator->second;
|
||||
driverHandle->getIPCHandleMap().clear();
|
||||
|
||||
// Test with completely invalid handle type (beyond enum range)
|
||||
handle = 22222;
|
||||
opaqueIpcData = {}; // Reset
|
||||
L0::IpcHandleType invalidHandleType2 = static_cast<L0::IpcHandleType>(255);
|
||||
|
||||
contextWhitebox.setIPCHandleData<L0::IpcOpaqueMemoryData>(&mockAllocation, handle, opaqueIpcData, ptrAddress, type, nullptr, invalidHandleType2);
|
||||
|
||||
// Verify the handle was added to the IPC handle map
|
||||
EXPECT_EQ(1u, ipcHandleMap.size());
|
||||
|
||||
// Verify the IpcOpaqueMemoryData values
|
||||
EXPECT_EQ(type, opaqueIpcData.memoryType);
|
||||
EXPECT_EQ(invalidHandleType2, opaqueIpcData.type);
|
||||
EXPECT_NE(0u, opaqueIpcData.processId); // Should be set to current process ID
|
||||
|
||||
// Clean up
|
||||
handleIterator = ipcHandleMap.find(handle);
|
||||
ASSERT_NE(handleIterator, ipcHandleMap.end());
|
||||
delete handleIterator->second;
|
||||
driverHandle->getIPCHandleMap().clear();
|
||||
|
||||
ContextImp *contextImp = static_cast<ContextImp *>(L0::Context::fromHandle(hContext));
|
||||
res = contextImp->destroy();
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
}
|
||||
|
||||
TEST_F(ContextTest, whenCallingSetIPCHandleDataWithNtHandleTypeThenHandleUnionIsSetCorrectly) {
|
||||
ze_context_handle_t hContext;
|
||||
ze_context_desc_t desc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC, nullptr, 0};
|
||||
|
||||
ze_result_t res = driverHandle->createContext(&desc, 0u, nullptr, &hContext);
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
|
||||
ContextWhiteboxForIpcTesting contextWhitebox(driverHandle.get());
|
||||
|
||||
// Create a mock graphics allocation
|
||||
NEO::MockGraphicsAllocation mockAllocation;
|
||||
|
||||
// Set up test data for ntHandle
|
||||
uint64_t handle = 98765;
|
||||
L0::IpcOpaqueMemoryData opaqueIpcData;
|
||||
opaqueIpcData.handle.reserved = handle;
|
||||
opaqueIpcData.memoryType = static_cast<uint8_t>(InternalMemoryType::deviceUnifiedMemory);
|
||||
opaqueIpcData.processId = 5678;
|
||||
opaqueIpcData.type = L0::IpcHandleType::ntHandle;
|
||||
opaqueIpcData.poolOffset = 0;
|
||||
|
||||
uint64_t ptrAddress = 0x4000;
|
||||
uint8_t type = static_cast<uint8_t>(InternalMemoryType::deviceUnifiedMemory);
|
||||
|
||||
// Verify IPC handle map is initially empty
|
||||
EXPECT_TRUE(driverHandle->getIPCHandleMap().empty());
|
||||
|
||||
// Call setIPCHandleData with ntHandle type
|
||||
contextWhitebox.setIPCHandleData<L0::IpcOpaqueMemoryData>(&mockAllocation, handle, opaqueIpcData, ptrAddress, type, nullptr, L0::IpcHandleType::ntHandle);
|
||||
|
||||
// Verify the handle was added to the IPC handle map
|
||||
auto &ipcHandleMap = driverHandle->getIPCHandleMap();
|
||||
EXPECT_EQ(1u, ipcHandleMap.size());
|
||||
|
||||
// Verify the handle tracking entry
|
||||
auto handleIterator = ipcHandleMap.find(handle);
|
||||
ASSERT_NE(handleIterator, ipcHandleMap.end());
|
||||
|
||||
L0::IpcHandleTracking *handleTracking = handleIterator->second;
|
||||
EXPECT_NE(nullptr, handleTracking);
|
||||
EXPECT_EQ(&mockAllocation, handleTracking->alloc);
|
||||
EXPECT_EQ(1u, handleTracking->refcnt);
|
||||
EXPECT_EQ(ptrAddress, handleTracking->ptr);
|
||||
EXPECT_EQ(handle, handleTracking->handle);
|
||||
|
||||
// Verify that the ipcData field is NOT set when using IpcOpaqueMemoryData
|
||||
// The ipcData field should retain its default/empty values since the constexpr condition is false
|
||||
EXPECT_EQ(0u, handleTracking->ipcData.handle); // Should be default value (0)
|
||||
EXPECT_EQ(0u, handleTracking->ipcData.type); // Should be default value (0)
|
||||
EXPECT_EQ(0u, handleTracking->ipcData.poolOffset); // Should be default value (0)
|
||||
|
||||
// Verify the IpcOpaqueMemoryData values are set correctly
|
||||
EXPECT_EQ(type, opaqueIpcData.memoryType);
|
||||
EXPECT_EQ(L0::IpcHandleType::ntHandle, opaqueIpcData.type);
|
||||
uint64_t reservedValue = 0;
|
||||
memcpy(&reservedValue, &opaqueIpcData.handle.reserved, sizeof(reservedValue));
|
||||
EXPECT_EQ(handle, reservedValue);
|
||||
unsigned int processID = 0;
|
||||
memcpy(&processID, &opaqueIpcData.processId, sizeof(processID));
|
||||
EXPECT_NE(0u, processID); // Should be set to current process ID
|
||||
|
||||
// Clean up - remove the entry from the map to avoid issues in teardown
|
||||
delete handleTracking;
|
||||
driverHandle->getIPCHandleMap().clear();
|
||||
|
||||
ContextImp *contextImp = static_cast<ContextImp *>(L0::Context::fromHandle(hContext));
|
||||
res = contextImp->destroy();
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
}
|
||||
|
||||
} // namespace ult
|
||||
} // namespace L0
|
||||
|
||||
@@ -41,8 +41,8 @@ TEST_F(ContextIsShareable, whenCallingisSharedMemoryThenCorrectResultIsReturned)
|
||||
|
||||
bool exportableMemoryFalse = false;
|
||||
bool exportableMemoryTrue = true;
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryTrue, contextImp->isShareableMemory(nullptr, exportableMemoryTrue, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice, false));
|
||||
EXPECT_EQ(exportableMemoryTrue, contextImp->isShareableMemory(nullptr, exportableMemoryTrue, neoDevice, false));
|
||||
|
||||
res = contextImp->destroy();
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
@@ -56,7 +56,7 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithValidHandleThenSuccess
|
||||
|
||||
// Test Successfully returning fd Handle
|
||||
fixtureMemoryManager->ntHandle = false;
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithInvalidHandleThenNullptrIsReturned) {
|
||||
@@ -68,19 +68,20 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithInvalidHandleThenNullp
|
||||
|
||||
// Test Failing returning fd Handle
|
||||
fixtureMemoryManager->ntHandle = false;
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndSyscallsReturnSuccessThenValidHandleIsReturned) {
|
||||
DebugManagerStateRestore restorer;
|
||||
debugManager.flags.EnablePidFdOrSocketsForIpc.set(1);
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
VariableBackup<decltype(SysCalls::pidfdopenCalled)> pidfdOpenCalledBackup(&NEO::SysCalls::pidfdopenCalled, 0u);
|
||||
VariableBackup<decltype(SysCalls::pidfdgetfdCalled)> pidfdGetFdCalledBackup(&NEO::SysCalls::pidfdgetfdCalled, 0u);
|
||||
|
||||
uint64_t handle = 57;
|
||||
|
||||
// Test Successfully returning fd Handle
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdopenCalled);
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdgetfdCalled);
|
||||
}
|
||||
@@ -88,6 +89,7 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndSyscalls
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndPidfdOpenSyscallReturnFailThenPidfdGetNotCalled) {
|
||||
DebugManagerStateRestore restorer;
|
||||
debugManager.flags.EnablePidFdOrSocketsForIpc.set(1);
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
VariableBackup<decltype(SysCalls::pidfdopenCalled)> pidfdOpenCalledBackup(&NEO::SysCalls::pidfdopenCalled, 0u);
|
||||
VariableBackup<decltype(SysCalls::pidfdgetfdCalled)> pidfdGetFdCalledBackup(&NEO::SysCalls::pidfdgetfdCalled, 0u);
|
||||
@@ -97,7 +99,7 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndPidfdOpe
|
||||
|
||||
uint64_t handle = 57;
|
||||
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdopenCalled);
|
||||
EXPECT_EQ(0, NEO::SysCalls::pidfdgetfdCalled);
|
||||
}
|
||||
@@ -105,6 +107,7 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndPidfdOpe
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndPidfdGetSyscallReturnFailThenCorrectHandleIsReturned) {
|
||||
DebugManagerStateRestore restorer;
|
||||
debugManager.flags.EnablePidFdOrSocketsForIpc.set(1);
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
VariableBackup<decltype(SysCalls::pidfdopenCalled)> pidfdOpenCalledBackup(&NEO::SysCalls::pidfdopenCalled, 0u);
|
||||
VariableBackup<decltype(SysCalls::pidfdgetfdCalled)> pidfdGetFdCalledBackup(&NEO::SysCalls::pidfdgetfdCalled, 0u);
|
||||
@@ -113,7 +116,7 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndPidfdGet
|
||||
});
|
||||
uint64_t handle = 57;
|
||||
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdopenCalled);
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdgetfdCalled);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/os_interface/linux/sys_calls.h"
|
||||
#include "shared/test/common/helpers/variable_backup.h"
|
||||
#include "shared/test/common/mocks/mock_device.h"
|
||||
#include "shared/test/common/mocks/mock_driver_model.h"
|
||||
#include "shared/test/common/mocks/mock_memory_manager.h"
|
||||
#include "shared/test/common/os_interface/linux/sys_calls_linux_ult.h"
|
||||
#include "shared/test/common/test_macros/test.h"
|
||||
|
||||
#include "level_zero/core/source/context/context.h"
|
||||
#include "level_zero/core/source/context/context_imp.h"
|
||||
#include "level_zero/core/test/unit_tests/fixtures/device_fixture.h"
|
||||
|
||||
@@ -33,17 +37,17 @@ TEST_F(ContextIsShareable, whenCallingisSharedMemoryThenCorrectResultIsReturned)
|
||||
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModel>());
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryTrue, contextImp->isShareableMemory(nullptr, exportableMemoryTrue, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice, false));
|
||||
EXPECT_EQ(exportableMemoryTrue, contextImp->isShareableMemory(nullptr, exportableMemoryTrue, neoDevice, false));
|
||||
// exportDesc set && neoDevice is NOT WDDM
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(&desc, exportableMemoryFalse, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(&desc, exportableMemoryFalse, neoDevice, false));
|
||||
// exportDesc unset && neoDevice is NOT WDDM
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice, false));
|
||||
// exportDesc unset && neoDevice is WDDM
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelWDDM>());
|
||||
EXPECT_EQ(exportableMemoryTrue, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryTrue, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice, false));
|
||||
// exportDesc is set && Exportable Memory is False && neoDevice is WDDM
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(&desc, exportableMemoryFalse, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(&desc, exportableMemoryFalse, neoDevice, false));
|
||||
|
||||
res = contextImp->destroy();
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
@@ -57,7 +61,7 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithValidNTHandleThenSucce
|
||||
|
||||
// Test Successfully returning NT Handle
|
||||
fixtureMemoryManager->ntHandle = true;
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithInvalidHandleThenNullptrIsReturned) {
|
||||
@@ -69,11 +73,11 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithInvalidHandleThenNullp
|
||||
|
||||
// Test Failing returning NT Handle
|
||||
fixtureMemoryManager->ntHandle = true;
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
|
||||
// Test Failing returning fd Handle
|
||||
fixtureMemoryManager->ntHandle = false;
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithDRMDriverTypeWithNonNTHandleThenSuccessIsReturned) {
|
||||
@@ -84,7 +88,7 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithDRMDriverTypeWithNonNT
|
||||
|
||||
// Test Successfully returning fd Handle
|
||||
fixtureMemoryManager->ntHandle = false;
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithWDDMDriverTypeWithNonNTHandleThenNullPtrIsReturned) {
|
||||
@@ -95,7 +99,418 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithWDDMDriverTypeWithNonN
|
||||
|
||||
// Test Successfully returning fd Handle
|
||||
fixtureMemoryManager->ntHandle = false;
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndPidfdOpenSyscallReturnFailThenPidfdGetNotCalled) {
|
||||
// Enable pidfd/sockets for IPC
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
// Set up DRM driver model to use pidfd method
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelDRM>());
|
||||
|
||||
MemoryManagerMemHandleMock *fixtureMemoryManager = static_cast<MemoryManagerMemHandleMock *>(currMemoryManager);
|
||||
fixtureMemoryManager->ntHandle = false;
|
||||
|
||||
VariableBackup<decltype(NEO::SysCalls::pidfdopenCalled)> pidfdOpenCalledBackup(&NEO::SysCalls::pidfdopenCalled, 0u);
|
||||
VariableBackup<decltype(NEO::SysCalls::pidfdgetfdCalled)> pidfdGetFdCalledBackup(&NEO::SysCalls::pidfdgetfdCalled, 0u);
|
||||
VariableBackup<decltype(NEO::SysCalls::sysCallsPidfdOpen)> mockPidfdOpen(&NEO::SysCalls::sysCallsPidfdOpen, [](pid_t, unsigned int) -> int {
|
||||
return -1;
|
||||
});
|
||||
|
||||
uint64_t handle = 57;
|
||||
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdopenCalled);
|
||||
EXPECT_EQ(0, NEO::SysCalls::pidfdgetfdCalled);
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndPidfdGetSyscallReturnFailThenCorrectHandleIsReturned) {
|
||||
// Enable pidfd/sockets for IPC
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
// Set up DRM driver model to use pidfd method
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelDRM>());
|
||||
|
||||
MemoryManagerMemHandleMock *fixtureMemoryManager = static_cast<MemoryManagerMemHandleMock *>(currMemoryManager);
|
||||
fixtureMemoryManager->ntHandle = false;
|
||||
|
||||
VariableBackup<decltype(NEO::SysCalls::pidfdopenCalled)> pidfdOpenCalledBackup(&NEO::SysCalls::pidfdopenCalled, 0u);
|
||||
VariableBackup<decltype(NEO::SysCalls::pidfdgetfdCalled)> pidfdGetFdCalledBackup(&NEO::SysCalls::pidfdgetfdCalled, 0u);
|
||||
VariableBackup<decltype(NEO::SysCalls::sysCallsPidfdGetfd)> mockPidfdGet(&NEO::SysCalls::sysCallsPidfdGetfd, [](int, int, unsigned int) -> int {
|
||||
return -1;
|
||||
});
|
||||
uint64_t handle = 57;
|
||||
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdopenCalled);
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdgetfdCalled);
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndPidfdGetSyscallFailsWithNegativeValueThenFallbackHandleIsUsed) {
|
||||
// Enable pidfd/sockets for IPC
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
// Set up DRM driver model to use pidfd method
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelDRM>());
|
||||
|
||||
MemoryManagerMemHandleMock *fixtureMemoryManager = static_cast<MemoryManagerMemHandleMock *>(currMemoryManager);
|
||||
fixtureMemoryManager->ntHandle = false;
|
||||
|
||||
uint64_t originalHandle = 42;
|
||||
static bool pidfdGetFdCalled = false;
|
||||
pidfdGetFdCalled = false;
|
||||
|
||||
VariableBackup<decltype(NEO::SysCalls::pidfdopenCalled)> pidfdOpenCalledBackup(&NEO::SysCalls::pidfdopenCalled, 0u);
|
||||
VariableBackup<decltype(NEO::SysCalls::pidfdgetfdCalled)> pidfdGetFdCalledBackup(&NEO::SysCalls::pidfdgetfdCalled, 0u);
|
||||
|
||||
// Mock pidfd_open to succeed
|
||||
VariableBackup<decltype(NEO::SysCalls::sysCallsPidfdOpen)> mockPidfdOpen(&NEO::SysCalls::sysCallsPidfdOpen, [](pid_t, unsigned int) -> int {
|
||||
return 100; // Valid pidfd
|
||||
});
|
||||
|
||||
// Mock pidfd_getfd to fail with different negative values
|
||||
VariableBackup<decltype(NEO::SysCalls::sysCallsPidfdGetfd)> mockPidfdGet(&NEO::SysCalls::sysCallsPidfdGetfd, [](int pidfd, int fd, unsigned int flags) -> int {
|
||||
pidfdGetFdCalled = true;
|
||||
EXPECT_EQ(100, pidfd); // Should receive the pidfd from pidfd_open
|
||||
EXPECT_EQ(42, fd); // Should receive the original handle
|
||||
EXPECT_EQ(0u, flags); // Flags should be 0
|
||||
return -2; // Fail with a different negative value
|
||||
});
|
||||
|
||||
void *result = context->getMemHandlePtr(device, originalHandle, NEO::AllocationType::buffer, 0u, 0);
|
||||
|
||||
EXPECT_NE(nullptr, result);
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdopenCalled);
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdgetfdCalled);
|
||||
EXPECT_TRUE(pidfdGetFdCalled);
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithPidfdMethodAndPidfdGetSyscallReturnsZeroThenSuccessfulHandleIsUsed) {
|
||||
// Enable pidfd/sockets for IPC
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
// Set up DRM driver model to use pidfd method
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelDRM>());
|
||||
|
||||
MemoryManagerMemHandleMock *fixtureMemoryManager = static_cast<MemoryManagerMemHandleMock *>(currMemoryManager);
|
||||
fixtureMemoryManager->ntHandle = false;
|
||||
|
||||
uint64_t originalHandle = 123;
|
||||
static bool pidfdGetFdCalled = false;
|
||||
pidfdGetFdCalled = false;
|
||||
|
||||
VariableBackup<decltype(NEO::SysCalls::pidfdopenCalled)> pidfdOpenCalledBackup(&NEO::SysCalls::pidfdopenCalled, 0u);
|
||||
VariableBackup<decltype(NEO::SysCalls::pidfdgetfdCalled)> pidfdGetFdCalledBackup(&NEO::SysCalls::pidfdgetfdCalled, 0u);
|
||||
|
||||
// Mock pidfd_open to succeed
|
||||
VariableBackup<decltype(NEO::SysCalls::sysCallsPidfdOpen)> mockPidfdOpen(&NEO::SysCalls::sysCallsPidfdOpen, [](pid_t, unsigned int) -> int {
|
||||
return 200; // Valid pidfd
|
||||
});
|
||||
|
||||
// Mock pidfd_getfd to return 0 (which is a valid fd but edge case)
|
||||
VariableBackup<decltype(NEO::SysCalls::sysCallsPidfdGetfd)> mockPidfdGet(&NEO::SysCalls::sysCallsPidfdGetfd, [](int pidfd, int fd, unsigned int flags) -> int {
|
||||
pidfdGetFdCalled = true;
|
||||
EXPECT_EQ(200, pidfd);
|
||||
EXPECT_EQ(123, fd);
|
||||
EXPECT_EQ(0u, flags);
|
||||
return 0; // Return 0 (valid fd)
|
||||
});
|
||||
|
||||
void *result = context->getMemHandlePtr(device, originalHandle, NEO::AllocationType::buffer, 0u, 0);
|
||||
|
||||
EXPECT_NE(nullptr, result);
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdopenCalled);
|
||||
EXPECT_EQ(1, NEO::SysCalls::pidfdgetfdCalled);
|
||||
EXPECT_TRUE(pidfdGetFdCalled);
|
||||
}
|
||||
|
||||
using GetDataFromIpcHandleTest = Test<GetMemHandlePtrTestFixture>;
|
||||
|
||||
TEST_F(GetDataFromIpcHandleTest, whenCallingGetDataFromIpcHandleWithOpaqueHandleEnabledThenOpaqueDataIsExtracted) {
|
||||
// Enable opaque handles
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
ze_ipc_mem_handle_t ipcHandle = {};
|
||||
IpcOpaqueMemoryData *opaqueData = reinterpret_cast<IpcOpaqueMemoryData *>(ipcHandle.data);
|
||||
opaqueData->handle.fd = 123;
|
||||
opaqueData->memoryType = 42;
|
||||
opaqueData->processId = 456;
|
||||
opaqueData->poolOffset = 789;
|
||||
|
||||
uint64_t handle = 0;
|
||||
uint8_t type = 0;
|
||||
unsigned int processId = 0;
|
||||
uint64_t poolOffset = 0;
|
||||
|
||||
context->getDataFromIpcHandle(device, ipcHandle, handle, type, processId, poolOffset);
|
||||
|
||||
EXPECT_EQ(123u, handle);
|
||||
EXPECT_EQ(42u, type);
|
||||
EXPECT_EQ(456u, processId);
|
||||
EXPECT_EQ(789u, poolOffset);
|
||||
}
|
||||
|
||||
TEST_F(GetDataFromIpcHandleTest, whenCallingGetDataFromIpcHandleWithOpaqueHandleDisabledThenRegularDataIsExtracted) {
|
||||
// Disable opaque handles
|
||||
context->contextSettings.enablePidfdOrSockets = false;
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelDRM>());
|
||||
|
||||
ze_ipc_mem_handle_t ipcHandle = {};
|
||||
IpcMemoryData *regularData = reinterpret_cast<IpcMemoryData *>(ipcHandle.data);
|
||||
regularData->handle = 987;
|
||||
regularData->type = 65;
|
||||
regularData->poolOffset = 321;
|
||||
|
||||
uint64_t handle = 0;
|
||||
uint8_t type = 0;
|
||||
unsigned int processId = 0;
|
||||
uint64_t poolOffset = 0;
|
||||
|
||||
context->getDataFromIpcHandle(device, ipcHandle, handle, type, processId, poolOffset);
|
||||
|
||||
EXPECT_EQ(987u, handle);
|
||||
EXPECT_EQ(65u, type);
|
||||
EXPECT_EQ(321u, poolOffset);
|
||||
// processId should remain 0 for regular data
|
||||
EXPECT_EQ(0u, processId);
|
||||
}
|
||||
|
||||
TEST_F(GetDataFromIpcHandleTest, whenCallingGetDataFromIpcHandleWithWDDMDriverThenOpaqueHandleIsForced) {
|
||||
// Initially disable opaque handles
|
||||
context->contextSettings.enablePidfdOrSockets = false;
|
||||
// Set WDDM driver model which should force opaque handles
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelWDDM>());
|
||||
|
||||
ze_ipc_mem_handle_t ipcHandle = {};
|
||||
IpcOpaqueMemoryData *opaqueData = reinterpret_cast<IpcOpaqueMemoryData *>(ipcHandle.data);
|
||||
opaqueData->handle.fd = 555;
|
||||
opaqueData->memoryType = 77;
|
||||
opaqueData->processId = 888;
|
||||
opaqueData->poolOffset = 999;
|
||||
|
||||
uint64_t handle = 0;
|
||||
uint8_t type = 0;
|
||||
unsigned int processId = 0;
|
||||
uint64_t poolOffset = 0;
|
||||
|
||||
context->getDataFromIpcHandle(device, ipcHandle, handle, type, processId, poolOffset);
|
||||
|
||||
// Should extract opaque data even though enablePidfdOrSockets was false
|
||||
EXPECT_EQ(555u, handle);
|
||||
EXPECT_EQ(77u, type);
|
||||
EXPECT_EQ(888u, processId);
|
||||
EXPECT_EQ(999u, poolOffset);
|
||||
}
|
||||
|
||||
TEST_F(GetDataFromIpcHandleTest, whenCallingGetDataFromIpcHandleWithNullOSInterfaceThenRegularDataIsExtracted) {
|
||||
// Disable opaque handles and set null osInterface
|
||||
context->contextSettings.enablePidfdOrSockets = false;
|
||||
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset();
|
||||
|
||||
ze_ipc_mem_handle_t ipcHandle = {};
|
||||
IpcMemoryData *regularData = reinterpret_cast<IpcMemoryData *>(ipcHandle.data);
|
||||
regularData->handle = 111;
|
||||
regularData->type = 22;
|
||||
regularData->poolOffset = 333;
|
||||
|
||||
uint64_t handle = 0;
|
||||
uint8_t type = 0;
|
||||
unsigned int processId = 0;
|
||||
uint64_t poolOffset = 0;
|
||||
|
||||
context->getDataFromIpcHandle(device, ipcHandle, handle, type, processId, poolOffset);
|
||||
|
||||
EXPECT_EQ(111u, handle);
|
||||
EXPECT_EQ(22u, type);
|
||||
EXPECT_EQ(333u, poolOffset);
|
||||
EXPECT_EQ(0u, processId);
|
||||
}
|
||||
|
||||
TEST_F(GetDataFromIpcHandleTest, whenCallingGetDataFromIpcHandleWithZeroValuesThenZeroValuesAreExtracted) {
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
ze_ipc_mem_handle_t ipcHandle = {};
|
||||
// All values should be zero by default
|
||||
|
||||
uint64_t handle = 999; // Initialize with non-zero to verify it gets overwritten
|
||||
uint8_t type = 99;
|
||||
unsigned int processId = 888;
|
||||
uint64_t poolOffset = 777;
|
||||
|
||||
context->getDataFromIpcHandle(device, ipcHandle, handle, type, processId, poolOffset);
|
||||
|
||||
EXPECT_EQ(0u, handle);
|
||||
EXPECT_EQ(0u, type);
|
||||
EXPECT_EQ(0u, processId);
|
||||
EXPECT_EQ(0u, poolOffset);
|
||||
}
|
||||
|
||||
inline int mockPrctl(int option, unsigned long arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
using IsOpaqueHandleSupportedTest = Test<GetMemHandlePtrTestFixture>;
|
||||
|
||||
TEST_F(IsOpaqueHandleSupportedTest, whenCallingIsOpaqueHandleSupportedWithWDDMDriverThenTrueIsReturnedAndHandleTypeIsNT) {
|
||||
// Set WDDM driver model on the execution environment that the context will actually use
|
||||
auto &executionEnvironment = driverHandle->getMemoryManager()->peekExecutionEnvironment();
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelWDDM>());
|
||||
|
||||
// Disable opaque handles in settings (should be overridden by WDDM)
|
||||
context->contextSettings.enablePidfdOrSockets = false;
|
||||
|
||||
IpcHandleType handleType = IpcHandleType::maxHandle;
|
||||
bool result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(IpcHandleType::ntHandle, handleType);
|
||||
}
|
||||
|
||||
TEST_F(IsOpaqueHandleSupportedTest, whenCallingIsOpaqueHandleSupportedWithDRMDriverAndOpaqueEnabledThenTrueIsReturnedAndHandleTypeIsFd) {
|
||||
// Set DRM driver model on the execution environment that the context will actually use
|
||||
auto &executionEnvironment = driverHandle->getMemoryManager()->peekExecutionEnvironment();
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelDRM>());
|
||||
VariableBackup<decltype(NEO::SysCalls::sysCallsPrctl)> sysCallsPrctlBackup{&NEO::SysCalls::sysCallsPrctl, mockPrctl};
|
||||
|
||||
// Enable opaque handles in settings
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
IpcHandleType handleType = IpcHandleType::maxHandle;
|
||||
bool result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(IpcHandleType::fdHandle, handleType);
|
||||
}
|
||||
|
||||
TEST_F(IsOpaqueHandleSupportedTest, whenCallingIsOpaqueHandleSupportedWithDRMDriverAndOpaqueDisabledThenFalseIsReturnedAndHandleTypeIsFd) {
|
||||
// Set DRM driver model on the execution environment that the context will actually use
|
||||
auto &executionEnvironment = driverHandle->getMemoryManager()->peekExecutionEnvironment();
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelDRM>());
|
||||
VariableBackup<decltype(NEO::SysCalls::sysCallsPrctl)> sysCallsPrctlBackup{&NEO::SysCalls::sysCallsPrctl, mockPrctl};
|
||||
|
||||
// Disable opaque handles in settings
|
||||
context->contextSettings.enablePidfdOrSockets = false;
|
||||
|
||||
IpcHandleType handleType = IpcHandleType::maxHandle;
|
||||
bool result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_EQ(IpcHandleType::fdHandle, handleType);
|
||||
}
|
||||
|
||||
TEST_F(IsOpaqueHandleSupportedTest, whenCallingIsOpaqueHandleSupportedWithNullOSInterfaceThenSettingsValueIsReturnedAndHandleTypeIsFd) {
|
||||
// Set null OS interface (unknown driver model) on the execution environment that the context will actually use
|
||||
auto &executionEnvironment = driverHandle->getMemoryManager()->peekExecutionEnvironment();
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface.reset();
|
||||
|
||||
// Test with opaque handles enabled
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
IpcHandleType handleType = IpcHandleType::maxHandle;
|
||||
bool result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(IpcHandleType::fdHandle, handleType);
|
||||
|
||||
// Test with opaque handles disabled
|
||||
context->contextSettings.enablePidfdOrSockets = false;
|
||||
handleType = IpcHandleType::maxHandle;
|
||||
result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_EQ(IpcHandleType::fdHandle, handleType);
|
||||
}
|
||||
|
||||
TEST_F(IsOpaqueHandleSupportedTest, whenCallingIsOpaqueHandleSupportedWithUnknownDriverModelThenSettingsValueIsReturnedAndHandleTypeIsFd) {
|
||||
// Set mock driver model (unknown type) on the execution environment that the context will actually use
|
||||
auto &executionEnvironment = driverHandle->getMemoryManager()->peekExecutionEnvironment();
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModel>());
|
||||
|
||||
// Test with opaque handles enabled
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
IpcHandleType handleType = IpcHandleType::maxHandle;
|
||||
bool result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(IpcHandleType::fdHandle, handleType);
|
||||
|
||||
// Test with opaque handles disabled
|
||||
context->contextSettings.enablePidfdOrSockets = false;
|
||||
handleType = IpcHandleType::maxHandle;
|
||||
result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_EQ(IpcHandleType::fdHandle, handleType);
|
||||
}
|
||||
|
||||
TEST_F(IsOpaqueHandleSupportedTest, whenCallingIsOpaqueHandleSupportedMultipleTimesWithSameConfigurationThenConsistentResultsAreReturned) {
|
||||
// Set WDDM driver model on the execution environment that the context will actually use
|
||||
auto &executionEnvironment = driverHandle->getMemoryManager()->peekExecutionEnvironment();
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelWDDM>());
|
||||
|
||||
context->contextSettings.enablePidfdOrSockets = false;
|
||||
|
||||
// Call multiple times and verify consistent results
|
||||
for (int i = 0; i < 3; i++) {
|
||||
IpcHandleType handleType = IpcHandleType::maxHandle;
|
||||
bool result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(IpcHandleType::ntHandle, handleType);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IsOpaqueHandleSupportedTest, whenCallingIsOpaqueHandleSupportedWithDRMDriverAndOpaqueEnabledThenPrctlIsCalledSuccessfully) {
|
||||
// Set DRM driver model on the execution environment that the context will actually use
|
||||
auto &executionEnvironment = driverHandle->getMemoryManager()->peekExecutionEnvironment();
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelDRM>());
|
||||
VariableBackup<decltype(NEO::SysCalls::sysCallsPrctl)> sysCallsPrctlBackup{&NEO::SysCalls::sysCallsPrctl, mockPrctl};
|
||||
|
||||
// Enable opaque handles in settings (this will trigger the prctl call)
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
IpcHandleType handleType = IpcHandleType::maxHandle;
|
||||
bool result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(IpcHandleType::fdHandle, handleType);
|
||||
}
|
||||
|
||||
TEST_F(IsOpaqueHandleSupportedTest, whenCallingIsOpaqueHandleSupportedWithDRMDriverAndOpaqueEnabledAndPrctlFailsThenFalseIsReturnedAndHandleTypeIsFd) {
|
||||
// Set DRM driver model on the execution environment that the context will actually use
|
||||
auto &executionEnvironment = driverHandle->getMemoryManager()->peekExecutionEnvironment();
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface());
|
||||
executionEnvironment.rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique<NEO::MockDriverModelDRM>());
|
||||
|
||||
// Enable opaque handles in settings (this will trigger the prctl call)
|
||||
context->contextSettings.enablePidfdOrSockets = true;
|
||||
|
||||
// Save original sysCallsPrctl and override to simulate failure
|
||||
auto originalSysCallsPrctl = NEO::SysCalls::sysCallsPrctl;
|
||||
NEO::SysCalls::sysCallsPrctl = [](int, unsigned long) -> int {
|
||||
return -1; // Simulate failure
|
||||
};
|
||||
|
||||
IpcHandleType handleType = IpcHandleType::maxHandle;
|
||||
bool result = context->isOpaqueHandleSupported(&handleType);
|
||||
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_EQ(IpcHandleType::fdHandle, handleType);
|
||||
|
||||
// Restore original sysCallsPrctl
|
||||
NEO::SysCalls::sysCallsPrctl = originalSysCallsPrctl;
|
||||
}
|
||||
|
||||
} // namespace ult
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2023 Intel Corporation
|
||||
* Copyright (C) 2020-2025 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@@ -39,8 +39,8 @@ TEST_F(ContextIsShareable, whenCallingisSharedMemoryThenCorrectResultIsReturned)
|
||||
|
||||
bool exportableMemoryFalse = false;
|
||||
bool exportableMemoryTrue = true;
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryTrue, contextImp->isShareableMemory(nullptr, exportableMemoryTrue, neoDevice));
|
||||
EXPECT_EQ(exportableMemoryFalse, contextImp->isShareableMemory(nullptr, exportableMemoryFalse, neoDevice, false));
|
||||
EXPECT_EQ(exportableMemoryTrue, contextImp->isShareableMemory(nullptr, exportableMemoryTrue, neoDevice, false));
|
||||
|
||||
res = contextImp->destroy();
|
||||
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
|
||||
@@ -54,7 +54,7 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithValidHandleThenSuccess
|
||||
|
||||
// Test Successfully returning NT Handle
|
||||
fixtureMemoryManager->ntHandle = true;
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_NE(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
}
|
||||
|
||||
TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithInvalidHandleThenNullptrIsReturned) {
|
||||
@@ -66,7 +66,7 @@ TEST_F(GetMemHandlePtrTest, whenCallingGetMemHandlePtrWithInvalidHandleThenNullp
|
||||
|
||||
// Test Failing returning NT Handle
|
||||
fixtureMemoryManager->ntHandle = true;
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0));
|
||||
EXPECT_EQ(nullptr, context->getMemHandlePtr(device, handle, NEO::AllocationType::buffer, 0u, 0));
|
||||
}
|
||||
|
||||
} // namespace ult
|
||||
|
||||
@@ -358,7 +358,7 @@ HWTEST_F(ImportNTHandleWithMockMemoryManager, givenCallToImportNTHandleWithHostB
|
||||
|
||||
uint64_t imageHandle = 0x1;
|
||||
NEO::AllocationType allocationType = NEO::AllocationType::bufferHostMemory;
|
||||
void *ptr = driverHandle->importNTHandle(device->toHandle(), &imageHandle, allocationType);
|
||||
void *ptr = driverHandle->importNTHandle(device->toHandle(), &imageHandle, allocationType, 0u);
|
||||
EXPECT_NE(ptr, nullptr);
|
||||
|
||||
auto allocData = driverHandle->svmAllocsManager->getSVMAlloc(ptr);
|
||||
@@ -376,7 +376,7 @@ HWTEST_F(ImportNTHandleWithMockMemoryManager, givenCallToImportNTHandleWithBuffe
|
||||
|
||||
uint64_t imageHandle = 0x1;
|
||||
NEO::AllocationType allocationType = NEO::AllocationType::buffer;
|
||||
void *ptr = driverHandle->importNTHandle(device->toHandle(), &imageHandle, allocationType);
|
||||
void *ptr = driverHandle->importNTHandle(device->toHandle(), &imageHandle, allocationType, 0u);
|
||||
EXPECT_NE(ptr, nullptr);
|
||||
|
||||
auto allocData = driverHandle->svmAllocsManager->getSVMAlloc(ptr);
|
||||
|
||||
@@ -5879,7 +5879,7 @@ struct ContextMultiDeviceMock : public L0::ContextImp {
|
||||
alignedFree(const_cast<void *>(ptr));
|
||||
return ZE_RESULT_SUCCESS;
|
||||
}
|
||||
bool isShareableMemory(const void *pNext, bool exportableMemory, NEO::Device *neoDevice) override {
|
||||
bool isShareableMemory(const void *pNext, bool exportableMemory, NEO::Device *neoDevice, bool shareableWithoutNTHandle) override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,6 +30,7 @@ struct AllocUsmPoolMemoryTest : public ::testing::Test {
|
||||
NEO::debugManager.flags.EnableHostUsmAllocationPool.set(hostUsmPoolFlag);
|
||||
NEO::debugManager.flags.EnableDeviceUsmAllocationPool.set(deviceUsmPoolFlag);
|
||||
NEO::debugManager.flags.ExperimentalUSMAllocationReuseVersion.set(poolingVersionFlag);
|
||||
NEO::debugManager.flags.EnableShareableWithoutNTHandle.set(false);
|
||||
|
||||
executionEnvironment = new NEO::ExecutionEnvironment();
|
||||
executionEnvironment->prepareRootDeviceEnvironments(numRootDevices);
|
||||
|
||||
@@ -78,6 +78,7 @@ DECLARE_DEBUG_VARIABLE(bool, DisableForceToStateless, false, "Do not force state
|
||||
DECLARE_DEBUG_VARIABLE(bool, ForceTheoreticalMaxWorkGroupCount, false, "Do not apply any limitation to max cooperative/concurrent work-group count queries")
|
||||
DECLARE_DEBUG_VARIABLE(bool, AppendMemoryPrefetchForKmdMigratedSharedAllocations, true, "Allow prefetching shared memory to the device associated with the specified command list")
|
||||
DECLARE_DEBUG_VARIABLE(bool, ForceMemoryPrefetchForKmdMigratedSharedAllocations, false, "Force prefetch of shared memory in command queue execute command lists")
|
||||
DECLARE_DEBUG_VARIABLE(bool, EnableShareableWithoutNTHandle, true, "Enable creating shareable allocations without NT handle on Windows")
|
||||
DECLARE_DEBUG_VARIABLE(bool, ClKhrExternalMemoryExtension, true, "Enable cl_khr_external_memory extension")
|
||||
DECLARE_DEBUG_VARIABLE(bool, WaitForMemoryRelease, false, "Wait for memory release when out of memory")
|
||||
DECLARE_DEBUG_VARIABLE(bool, RemoveRestrictionsOnNumberOfThreadsInGpgpuThreadGroup, 0, "0 - default disabled, 1- remove restrictions on NumberOfThreadsInGpgpuThreadGroup in INTERFACE_DESCRIPTOR_DATA")
|
||||
|
||||
@@ -28,7 +28,8 @@ struct AllocationProperties {
|
||||
uint32_t forceSystemMemory : 1;
|
||||
uint32_t preferCompressed : 1;
|
||||
uint32_t cantBeReadOnly : 1;
|
||||
uint32_t reserved : 18;
|
||||
uint32_t shareableWithoutNTHandle : 1;
|
||||
uint32_t reserved : 16;
|
||||
} flags;
|
||||
uint32_t allFlags = 0;
|
||||
};
|
||||
@@ -112,7 +113,8 @@ struct AllocationData {
|
||||
uint32_t isUSMDeviceMemory : 1;
|
||||
uint32_t zeroMemory : 1;
|
||||
uint32_t cantBeReadOnly : 1;
|
||||
uint32_t reserved : 15;
|
||||
uint32_t shareableWithoutNTHandle : 1;
|
||||
uint32_t reserved : 14;
|
||||
} flags;
|
||||
uint32_t allFlags = 0;
|
||||
};
|
||||
|
||||
@@ -643,6 +643,7 @@ bool MemoryManager::getAllocationData(AllocationData &allocationData, const Allo
|
||||
allocationData.forceKMDAllocation = properties.forceKMDAllocation;
|
||||
allocationData.makeGPUVaDifferentThanCPUPtr = properties.makeGPUVaDifferentThanCPUPtr;
|
||||
allocationData.flags.shareable = properties.flags.shareable;
|
||||
allocationData.flags.shareableWithoutNTHandle = properties.flags.shareableWithoutNTHandle;
|
||||
allocationData.flags.isUSMDeviceMemory = properties.flags.isUSMDeviceAllocation;
|
||||
allocationData.flags.requiresCpuAccess = GraphicsAllocation::isCpuAccessRequired(properties.allocationType);
|
||||
allocationData.flags.allocateMemory = properties.flags.allocateMemory;
|
||||
|
||||
@@ -111,6 +111,7 @@ class MemoryManager {
|
||||
struct OsHandleData {
|
||||
osHandle handle;
|
||||
uint32_t arrayIndex;
|
||||
uint32_t parentProcessId = 0;
|
||||
|
||||
OsHandleData(uint64_t handle, uint32_t arrayIndex = 0) : handle(static_cast<osHandle>(handle)), arrayIndex(arrayIndex){};
|
||||
OsHandleData(void *handle, uint32_t arrayIndex = 0) : handle(toOsHandle(handle)), arrayIndex(arrayIndex){};
|
||||
|
||||
@@ -506,6 +506,7 @@ void *SVMAllocsManager::createUnifiedMemoryAllocation(size_t size,
|
||||
unifiedMemoryProperties.alignment = alignUpNonZero<size_t>(memoryProperties.alignment, pageSizeForAlignment);
|
||||
unifiedMemoryProperties.flags.isUSMDeviceAllocation = false;
|
||||
unifiedMemoryProperties.flags.shareable = memoryProperties.allocationFlags.flags.shareable;
|
||||
unifiedMemoryProperties.flags.shareableWithoutNTHandle = memoryProperties.allocationFlags.flags.shareableWithoutNTHandle;
|
||||
unifiedMemoryProperties.cacheRegion = MemoryPropertiesHelper::getCacheRegion(memoryProperties.allocationFlags);
|
||||
unifiedMemoryProperties.flags.uncacheable = memoryProperties.allocationFlags.flags.locallyUncachedResource;
|
||||
unifiedMemoryProperties.flags.preferCompressed = compressionEnabled || memoryProperties.allocationFlags.flags.compressedHint;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2021 Intel Corporation
|
||||
* Copyright (C) 2019-2025 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@@ -30,6 +30,7 @@ struct MemoryFlags {
|
||||
uint32_t resource48Bit : 1;
|
||||
uint32_t compressedHint : 1;
|
||||
uint32_t uncompressedHint : 1;
|
||||
uint32_t shareableWithoutNTHandle : 1;
|
||||
};
|
||||
|
||||
struct MemoryAllocFlags {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <iostream>
|
||||
#include <poll.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -59,6 +60,8 @@ long sysconf(int name);
|
||||
int mkfifo(const char *pathname, mode_t mode);
|
||||
int pidfdopen(pid_t pid, unsigned int flags);
|
||||
int pidfdgetfd(int pidfd, int targetfd, unsigned int flags);
|
||||
int prctl(int option, unsigned long arg);
|
||||
char **getEnviron();
|
||||
|
||||
} // namespace SysCalls
|
||||
} // namespace NEO
|
||||
|
||||
@@ -205,6 +205,10 @@ int pidfdgetfd(int pidfd, int targetfd, unsigned int flags) {
|
||||
return static_cast<int>(retval);
|
||||
}
|
||||
|
||||
int prctl(int option, unsigned long arg) {
|
||||
return ::prctl(option, arg);
|
||||
}
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence) noexcept {
|
||||
return ::lseek(fd, offset, whence);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,14 @@ unsigned int getCurrentProcessId() {
|
||||
return GetCurrentProcessId();
|
||||
}
|
||||
|
||||
BOOL duplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) {
|
||||
return DuplicateHandle(hSourceProcessHandle, hSourceHandle, hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions);
|
||||
}
|
||||
|
||||
HANDLE openProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) {
|
||||
return OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
|
||||
}
|
||||
|
||||
unsigned long getNumThreads() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ BOOL findNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData);
|
||||
BOOL findClose(HANDLE hFindFile);
|
||||
DWORD getFileAttributesA(LPCSTR lpFileName);
|
||||
DWORD setFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod);
|
||||
BOOL duplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
|
||||
HANDLE openProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
|
||||
|
||||
void setProcessPowerThrottlingState(ProcessPowerThrottlingState state);
|
||||
void setThreadPriority(ThreadPriority priority);
|
||||
|
||||
@@ -18,4 +18,8 @@ bool Wddm::getReadOnlyFlagValue(const void *cpuPtr) const {
|
||||
bool Wddm::isReadOnlyFlagFallbackSupported() const {
|
||||
return false;
|
||||
}
|
||||
HANDLE Wddm::getSharedHandle(const MemoryManager::OsHandleData &osHandleData) {
|
||||
HANDLE sharedNtHandle = reinterpret_cast<HANDLE>(static_cast<uintptr_t>(osHandleData.handle));
|
||||
return sharedNtHandle;
|
||||
}
|
||||
} // namespace NEO
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "shared/source/os_interface/windows/gdi_interface.h"
|
||||
#include "shared/source/os_interface/windows/sys_calls.h"
|
||||
#include "shared/source/os_interface/windows/wddm/wddm.h"
|
||||
|
||||
namespace NEO {
|
||||
@@ -23,4 +24,41 @@ bool Wddm::getReadOnlyFlagValue(const void *cpuPtr) const {
|
||||
bool Wddm::isReadOnlyFlagFallbackSupported() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE Wddm::getSharedHandle(const MemoryManager::OsHandleData &osHandleData) {
|
||||
HANDLE sharedNtHandle = reinterpret_cast<HANDLE>(static_cast<uintptr_t>(osHandleData.handle));
|
||||
if (osHandleData.parentProcessId != 0) {
|
||||
// Open the parent process handle with required access rights
|
||||
HANDLE parentProcessHandle = NEO::SysCalls::openProcess(PROCESS_DUP_HANDLE, FALSE, static_cast<DWORD>(osHandleData.parentProcessId));
|
||||
if (parentProcessHandle == nullptr) {
|
||||
DEBUG_BREAK_IF(true);
|
||||
return sharedNtHandle;
|
||||
}
|
||||
|
||||
// Duplicate the handle from the parent process to the current process
|
||||
// This is necessary to ensure that the handle can be used in the current process context
|
||||
// We use GENERIC_READ | GENERIC_WRITE to ensure we can perform operations on the handle
|
||||
HANDLE duplicatedHandle = nullptr;
|
||||
BOOL duplicateResult = NEO::SysCalls::duplicateHandle(
|
||||
parentProcessHandle,
|
||||
reinterpret_cast<HANDLE>(static_cast<uintptr_t>(osHandleData.handle)),
|
||||
GetCurrentProcess(),
|
||||
&duplicatedHandle,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FALSE,
|
||||
0);
|
||||
|
||||
// Close the parent process handle as we no longer need it
|
||||
// The duplicated handle will be used for further operations
|
||||
NEO::SysCalls::closeHandle(parentProcessHandle);
|
||||
|
||||
if (!duplicateResult) {
|
||||
DEBUG_BREAK_IF(true);
|
||||
return sharedNtHandle;
|
||||
}
|
||||
sharedNtHandle = duplicatedHandle;
|
||||
}
|
||||
return sharedNtHandle;
|
||||
}
|
||||
|
||||
} // namespace NEO
|
||||
|
||||
@@ -664,6 +664,10 @@ bool Wddm::isReadOnlyFlagFallbackAvailable(const D3DKMT_CREATEALLOCATION &create
|
||||
}
|
||||
|
||||
NTSTATUS Wddm::createAllocation(const void *cpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResourceHandle, uint64_t *outSharedHandle) {
|
||||
return createAllocation(cpuPtr, gmm, outHandle, outResourceHandle, outSharedHandle, true);
|
||||
}
|
||||
|
||||
NTSTATUS Wddm::createAllocation(const void *cpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResourceHandle, uint64_t *outSharedHandle, bool createNTHandle) {
|
||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
D3DDDI_ALLOCATIONINFO2 allocationInfo = {};
|
||||
D3DKMT_CREATEALLOCATION createAllocation = {};
|
||||
@@ -704,7 +708,7 @@ NTSTATUS Wddm::createAllocation(const void *cpuPtr, const Gmm *gmm, D3DKMT_HANDL
|
||||
|
||||
outHandle = allocationInfo.hAllocation;
|
||||
outResourceHandle = createAllocation.hResource;
|
||||
if (outSharedHandle) {
|
||||
if (outSharedHandle && createNTHandle) {
|
||||
HANDLE ntSharedHandle = NULL;
|
||||
status = this->createNTHandle(&outResourceHandle, &ntSharedHandle);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
@@ -922,7 +926,8 @@ bool Wddm::verifyNTHandle(HANDLE handle) {
|
||||
bool Wddm::openNTHandle(const MemoryManager::OsHandleData &osHandleData, WddmAllocation *alloc) {
|
||||
D3DKMT_QUERYRESOURCEINFOFROMNTHANDLE queryResourceInfoFromNtHandle = {};
|
||||
queryResourceInfoFromNtHandle.hDevice = device;
|
||||
queryResourceInfoFromNtHandle.hNtHandle = reinterpret_cast<HANDLE>(static_cast<uintptr_t>(osHandleData.handle));
|
||||
HANDLE sharedNtHandle = this->getSharedHandle(osHandleData);
|
||||
queryResourceInfoFromNtHandle.hNtHandle = sharedNtHandle;
|
||||
[[maybe_unused]] auto status = getGdi()->queryResourceInfoFromNtHandle(&queryResourceInfoFromNtHandle);
|
||||
DEBUG_BREAK_IF(status != STATUS_SUCCESS);
|
||||
|
||||
@@ -938,7 +943,7 @@ bool Wddm::openNTHandle(const MemoryManager::OsHandleData &osHandleData, WddmAll
|
||||
D3DKMT_OPENRESOURCEFROMNTHANDLE openResourceFromNtHandle = {};
|
||||
|
||||
openResourceFromNtHandle.hDevice = device;
|
||||
openResourceFromNtHandle.hNtHandle = reinterpret_cast<HANDLE>(static_cast<uintptr_t>(osHandleData.handle));
|
||||
openResourceFromNtHandle.hNtHandle = sharedNtHandle;
|
||||
openResourceFromNtHandle.NumAllocations = queryResourceInfoFromNtHandle.NumAllocations;
|
||||
openResourceFromNtHandle.pOpenAllocationInfo2 = allocationInfo2.get();
|
||||
openResourceFromNtHandle.pTotalPrivateDriverDataBuffer = allocPrivateData.get();
|
||||
|
||||
@@ -74,6 +74,7 @@ class Wddm : public DriverModel {
|
||||
MOCKABLE_VIRTUAL uint64_t freeGmmGpuVirtualAddress(Gmm *gmm, D3DGPU_VIRTUAL_ADDRESS &gpuPtr, uint64_t size);
|
||||
MOCKABLE_VIRTUAL bool freeGpuVirtualAddress(D3DGPU_VIRTUAL_ADDRESS &gpuPtr, uint64_t size);
|
||||
MOCKABLE_VIRTUAL NTSTATUS createAllocation(const void *cpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResourceHandle, uint64_t *outSharedHandle);
|
||||
MOCKABLE_VIRTUAL NTSTATUS createAllocation(const void *cpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResourceHandle, uint64_t *outSharedHandle, bool createNTHandle);
|
||||
MOCKABLE_VIRTUAL bool createAllocation(const Gmm *gmm, D3DKMT_HANDLE &outHandle);
|
||||
MOCKABLE_VIRTUAL NTSTATUS createAllocationsAndMapGpuVa(OsHandleStorage &osHandles);
|
||||
MOCKABLE_VIRTUAL bool destroyAllocations(const D3DKMT_HANDLE *handles, uint32_t allocationCount, D3DKMT_HANDLE resourceHandle);
|
||||
@@ -91,6 +92,7 @@ class Wddm : public DriverModel {
|
||||
MOCKABLE_VIRTUAL bool destroyContext(D3DKMT_HANDLE context);
|
||||
MOCKABLE_VIRTUAL bool queryAdapterInfo();
|
||||
MOCKABLE_VIRTUAL NTSTATUS createNTHandle(const D3DKMT_HANDLE *resourceHandle, HANDLE *ntHandle);
|
||||
MOCKABLE_VIRTUAL HANDLE getSharedHandle(const MemoryManager::OsHandleData &osHandleData);
|
||||
|
||||
MOCKABLE_VIRTUAL bool submit(uint64_t commandBuffer, size_t size, void *commandHeader, WddmSubmitArguments &submitArguments);
|
||||
MOCKABLE_VIRTUAL bool waitFromCpu(uint64_t lastFenceValue, const MonitoredFence &monitoredFence, bool busyWait);
|
||||
|
||||
@@ -90,6 +90,9 @@ class WddmAllocation : public GraphicsAllocation {
|
||||
void setMakeResidentBeforeLockRequired(bool makeResidentBeforeLockRequired) { this->makeResidentBeforeLockRequired = makeResidentBeforeLockRequired; }
|
||||
bool isAllocInFrontWindowPool() const { return allocInFrontWindowPool; }
|
||||
void setAllocInFrontWindowPool(bool allocInFrontWindowPool) { this->allocInFrontWindowPool = allocInFrontWindowPool; }
|
||||
bool isShareable() const { return shareable; }
|
||||
bool isShareableWithoutNTHandle() const { return shareableWithoutNTHandle; }
|
||||
void setShareableWithoutNTHandle(bool shareableWithoutNTHandle) { this->shareableWithoutNTHandle = shareableWithoutNTHandle; }
|
||||
bool isPhysicalMemoryReservation() const { return physicalMemoryReservation; }
|
||||
void setPhysicalMemoryReservation(bool physicalMemoryReservation) { this->physicalMemoryReservation = physicalMemoryReservation; }
|
||||
bool isMappedPhysicalMemoryReservation() const { return mappedPhysicalMemoryReservation; }
|
||||
@@ -125,5 +128,6 @@ class WddmAllocation : public GraphicsAllocation {
|
||||
bool physicalMemoryReservation = false;
|
||||
bool mappedPhysicalMemoryReservation = false;
|
||||
bool makeResidentBeforeLockRequired = false;
|
||||
bool shareableWithoutNTHandle = false;
|
||||
};
|
||||
} // namespace NEO
|
||||
|
||||
@@ -147,6 +147,7 @@ GraphicsAllocation *WddmMemoryManager::allocatePhysicalDeviceMemory(const Alloca
|
||||
1u, // numGmms
|
||||
allocationData.type, nullptr, 0, allocationData.size, nullptr,
|
||||
MemoryPool::systemCpuInaccessible, allocationData.flags.shareable, maxOsContextCount);
|
||||
allocation->setShareableWithoutNTHandle(allocationData.flags.shareableWithoutNTHandle);
|
||||
allocation->setDefaultGmm(gmm.get());
|
||||
if (!createPhysicalAllocation(allocation.get())) {
|
||||
return nullptr;
|
||||
@@ -175,6 +176,7 @@ GraphicsAllocation *WddmMemoryManager::allocateMemoryByKMD(const AllocationData
|
||||
1u, // numGmms
|
||||
allocationData.type, nullptr, 0, allocationData.size, nullptr,
|
||||
MemoryPool::systemCpuInaccessible, allocationData.flags.shareable, maxOsContextCount);
|
||||
allocation->setShareableWithoutNTHandle(allocationData.flags.shareableWithoutNTHandle);
|
||||
allocation->setDefaultGmm(gmm.get());
|
||||
void *requiredGpuVa = nullptr;
|
||||
adjustGpuPtrToHostAddressSpace(*allocation.get(), requiredGpuVa);
|
||||
@@ -616,7 +618,6 @@ bool WddmMemoryManager::isNTHandle(osHandle handle, uint32_t rootDeviceIndex) {
|
||||
|
||||
GraphicsAllocation *WddmMemoryManager::createGraphicsAllocationFromSharedHandle(const OsHandleData &osHandleData, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation, bool reuseSharedAllocation, void *mapPointer) {
|
||||
auto allocation = std::make_unique<WddmAllocation>(properties.rootDeviceIndex, 1u /*num gmms*/, properties.allocationType, nullptr, 0, osHandleData.handle, MemoryPool::systemCpuInaccessible, maxOsContextCount, 0llu);
|
||||
|
||||
bool status;
|
||||
if (verifyHandle(osHandleData.handle, properties.rootDeviceIndex, false))
|
||||
status = getWddm(properties.rootDeviceIndex).openSharedHandle(osHandleData, allocation.get());
|
||||
@@ -1131,10 +1132,11 @@ bool WddmMemoryManager::mapMultiHandleAllocationWithRetry(WddmAllocation *alloca
|
||||
bool WddmMemoryManager::createGpuAllocationsWithRetry(WddmAllocation *allocation) {
|
||||
for (auto handleId = 0u; handleId < allocation->getNumGmms(); handleId++) {
|
||||
auto gmm = allocation->getGmm(handleId);
|
||||
auto status = getWddm(allocation->getRootDeviceIndex()).createAllocation(allocation->getUnderlyingBuffer(), gmm, allocation->getHandleToModify(handleId), allocation->getResourceHandleToModify(), allocation->getSharedHandleToModify());
|
||||
bool createNTHandle = allocation->isShareable() && !allocation->isShareableWithoutNTHandle();
|
||||
auto status = getWddm(allocation->getRootDeviceIndex()).createAllocation(allocation->getUnderlyingBuffer(), gmm, allocation->getHandleToModify(handleId), allocation->getResourceHandleToModify(), allocation->getSharedHandleToModify(), createNTHandle);
|
||||
if (status == STATUS_GRAPHICS_NO_VIDEO_MEMORY && deferredDeleter) {
|
||||
deferredDeleter->drain(true, false);
|
||||
status = getWddm(allocation->getRootDeviceIndex()).createAllocation(allocation->getUnderlyingBuffer(), gmm, allocation->getHandleToModify(handleId), allocation->getResourceHandleToModify(), allocation->getSharedHandleToModify());
|
||||
status = getWddm(allocation->getRootDeviceIndex()).createAllocation(allocation->getUnderlyingBuffer(), gmm, allocation->getHandleToModify(handleId), allocation->getResourceHandleToModify(), allocation->getSharedHandleToModify(), createNTHandle);
|
||||
}
|
||||
if (status != STATUS_SUCCESS) {
|
||||
getWddm(allocation->getRootDeviceIndex()).destroyAllocations(&allocation->getHandles()[0], handleId, allocation->getResourceHandle());
|
||||
@@ -1368,6 +1370,7 @@ GraphicsAllocation *WddmMemoryManager::allocatePhysicalLocalDeviceMemory(const A
|
||||
|
||||
auto wddmAllocation = std::make_unique<WddmAllocation>(allocationData.rootDeviceIndex, singleBankAllocation ? numGmms : numBanks,
|
||||
allocationData.type, nullptr, 0, sizeAligned, nullptr, MemoryPool::localMemory, allocationData.flags.shareable, maxOsContextCount);
|
||||
wddmAllocation->setShareableWithoutNTHandle(allocationData.flags.shareableWithoutNTHandle);
|
||||
if (singleBankAllocation) {
|
||||
if (numGmms > 1) {
|
||||
splitGmmsInAllocation(gmmHelper, wddmAllocation.get(), alignment, chunkSize, const_cast<StorageInfo &>(allocationData.storageInfo));
|
||||
@@ -1463,6 +1466,7 @@ GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemoryInDevicePool(const
|
||||
|
||||
auto wddmAllocation = std::make_unique<WddmAllocation>(allocationData.rootDeviceIndex, singleBankAllocation ? numGmms : numBanks,
|
||||
allocationData.type, nullptr, 0, sizeAligned, nullptr, MemoryPool::localMemory, allocationData.flags.shareable, maxOsContextCount);
|
||||
wddmAllocation->setShareableWithoutNTHandle(allocationData.flags.shareableWithoutNTHandle);
|
||||
if (singleBankAllocation) {
|
||||
if (numGmms > 1) {
|
||||
splitGmmsInAllocation(gmmHelper, wddmAllocation.get(), alignment, chunkSize, const_cast<StorageInfo &>(allocationData.storageInfo));
|
||||
|
||||
@@ -141,6 +141,30 @@ NTSTATUS WddmMock::createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D
|
||||
return createAllocationStatus;
|
||||
}
|
||||
|
||||
NTSTATUS WddmMock::createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResourceHandle, uint64_t *outSharedHandle, bool createNTHandle) {
|
||||
createAllocationResult.called++;
|
||||
if (failCreateAllocation) {
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
if (callBaseDestroyAllocations) {
|
||||
createAllocationStatus = Wddm::createAllocation(alignedCpuPtr, gmm, outHandle, outResourceHandle, outSharedHandle, createNTHandle);
|
||||
createAllocationResult.success = createAllocationStatus == STATUS_SUCCESS;
|
||||
if (createAllocationStatus != STATUS_SUCCESS) {
|
||||
destroyAllocationResult.called++;
|
||||
}
|
||||
} else {
|
||||
createAllocationResult.success = true;
|
||||
outHandle = ALLOCATION_HANDLE;
|
||||
outResourceHandle = ALLOCATION_HANDLE;
|
||||
if (outSharedHandle && !createNTHandle) {
|
||||
// For shared allocations without NT handle, set a special value
|
||||
*outSharedHandle = 1u;
|
||||
}
|
||||
return createAllocationStatus;
|
||||
}
|
||||
return createAllocationStatus;
|
||||
}
|
||||
|
||||
bool WddmMock::createAllocation64k(WddmAllocation *wddmAllocation) {
|
||||
if (wddmAllocation) {
|
||||
return createAllocation(wddmAllocation->getDefaultGmm(), wddmAllocation->getHandleToModify(0u));
|
||||
|
||||
@@ -82,6 +82,7 @@ class WddmMock : public Wddm {
|
||||
bool mapGpuVirtualAddress(WddmAllocation *allocation);
|
||||
bool freeGpuVirtualAddress(D3DGPU_VIRTUAL_ADDRESS &gpuPtr, uint64_t size) override;
|
||||
NTSTATUS createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResource, uint64_t *outSharedHandle) override;
|
||||
NTSTATUS createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResource, uint64_t *outSharedHandle, bool createNTHandle) override;
|
||||
bool createAllocation(const Gmm *gmm, D3DKMT_HANDLE &outHandle) override;
|
||||
bool destroyAllocations(const D3DKMT_HANDLE *handles, uint32_t allocationCount, D3DKMT_HANDLE resourceHandle) override;
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ int readdirCalled = 0;
|
||||
int closedirCalled = 0;
|
||||
int pidfdopenCalled = 0;
|
||||
int pidfdgetfdCalled = 0;
|
||||
int prctlCalled = 0;
|
||||
int fsyncCalled = 0;
|
||||
int fsyncArgPassed = 0;
|
||||
int fsyncRetVal = 0;
|
||||
@@ -116,6 +117,7 @@ int (*sysCallsClosedir)(DIR *dir) = nullptr;
|
||||
int (*sysCallsGetDevicePath)(int deviceFd, char *buf, size_t &bufSize) = nullptr;
|
||||
int (*sysCallsPidfdOpen)(pid_t pid, unsigned int flags) = nullptr;
|
||||
int (*sysCallsPidfdGetfd)(int pidfd, int fd, unsigned int flags) = nullptr;
|
||||
int (*sysCallsPrctl)(int option, unsigned long arg) = nullptr;
|
||||
off_t lseekReturn = 4096u;
|
||||
std::atomic<int> lseekCalledCount(0);
|
||||
long sysconfReturn = 1ull << 30;
|
||||
@@ -555,6 +557,15 @@ int pidfdgetfd(int pid, int targetfd, unsigned int flags) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prctl(int option, unsigned long arg) {
|
||||
prctlCalled++;
|
||||
if (sysCallsPrctl != nullptr) {
|
||||
return sysCallsPrctl(option, arg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char **getEnviron() {
|
||||
return NEO::ULT::getCurrentEnviron();
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ extern int (*sysCallsGetDevicePath)(int deviceFd, char *buf, size_t &bufSize);
|
||||
extern int (*sysCallsClose)(int fileDescriptor);
|
||||
extern int (*sysCallsPidfdOpen)(pid_t pid, unsigned int flags);
|
||||
extern int (*sysCallsPidfdGetfd)(int pidfd, int fd, unsigned int flags);
|
||||
extern int (*sysCallsPrctl)(int option, unsigned long arg);
|
||||
|
||||
extern bool allowFakeDevicePath;
|
||||
extern int flockRetVal;
|
||||
@@ -93,6 +94,7 @@ extern bool failAccess;
|
||||
extern int setErrno;
|
||||
extern int pidfdopenCalled;
|
||||
extern int pidfdgetfdCalled;
|
||||
extern int prctlCalled;
|
||||
|
||||
extern std::vector<void *> mmapVector;
|
||||
extern std::vector<void *> mmapCapturedExtendedPointers;
|
||||
|
||||
@@ -67,6 +67,8 @@ extern CONFIGRET (*sysCallsCmGetDeviceInterfaceListSize)(PULONG pulLen, LPGUID i
|
||||
extern CONFIGRET (*sysCallsCmGetDeviceInterfaceList)(LPGUID interfaceClassGuid, DEVINSTID_W pDeviceID, PZZWSTR buffer, ULONG bufferLen, ULONG ulFlags);
|
||||
extern LPVOID (*sysCallsHeapAlloc)(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
|
||||
extern BOOL (*sysCallsHeapFree)(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
|
||||
extern BOOL (*sysCallsDuplicateHandle)(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
|
||||
extern HANDLE (*sysCallsOpenProcess)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
|
||||
|
||||
extern BOOL (*sysCallsGetModuleHandleExW)(DWORD dwFlags, LPCWSTR lpModuleName, HMODULE *phModule);
|
||||
extern DWORD (*sysCallsGetModuleFileNameW)(HMODULE hModule, LPWSTR lpFilename, DWORD nSize);
|
||||
|
||||
@@ -120,6 +120,12 @@ LPVOID(*sysCallsHeapAlloc)
|
||||
BOOL(*sysCallsHeapFree)
|
||||
(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) = nullptr;
|
||||
|
||||
BOOL(*sysCallsDuplicateHandle)
|
||||
(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) = nullptr;
|
||||
|
||||
HANDLE(*sysCallsOpenProcess)
|
||||
(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) = nullptr;
|
||||
|
||||
void exit(int code) {
|
||||
}
|
||||
|
||||
@@ -344,6 +350,20 @@ BOOL heapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
|
||||
return HeapFree(hHeap, dwFlags, lpMem);
|
||||
}
|
||||
|
||||
BOOL duplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) {
|
||||
if (sysCallsDuplicateHandle != nullptr) {
|
||||
return sysCallsDuplicateHandle(hSourceProcessHandle, hSourceHandle, hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HANDLE openProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) {
|
||||
if (sysCallsOpenProcess != nullptr) {
|
||||
return sysCallsOpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LSTATUS regOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) {
|
||||
if (regOpenKeySuccessCount > 0) {
|
||||
regOpenKeySuccessCount--;
|
||||
|
||||
@@ -664,4 +664,5 @@ SplitBcsAggregatedEventsMode = -1
|
||||
SplitBcsRequiredTileCount = -1
|
||||
SplitBcsRequiredEnginesCount = -1
|
||||
SplitBcsTransferDirectionMask = -1
|
||||
EnableShareableWithoutNTHandle = -1
|
||||
# Please don't edit below this line
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2024 Intel Corporation
|
||||
* Copyright (C) 2021-2025 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@@ -73,7 +73,44 @@ TEST_F(WdmmSharedTests, WhenCreatingSharedAllocationAndGetNTHandleFailedThenAllo
|
||||
Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), nullptr, 20, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements);
|
||||
|
||||
EXPECT_NE(STATUS_SUCCESS, wddm->createAllocation(nullptr, &gmm, handle, resourceHandle, &ntHandle));
|
||||
EXPECT_EQ(wddm->destroyAllocationResult.called++, 1u);
|
||||
EXPECT_EQ(wddm->destroyAllocationResult.called++, 2u);
|
||||
EXPECT_EQ(handle, 0u);
|
||||
EXPECT_EQ(resourceHandle, 0u);
|
||||
}
|
||||
|
||||
TEST_F(WdmmSharedTests, WhenCreatingSharedAllocationWithShareableWithoutNTHandleFlagThenNTHandleIsNotCreated) {
|
||||
init();
|
||||
|
||||
D3DKMT_HANDLE handle = 32u;
|
||||
D3DKMT_HANDLE resourceHandle = 32u;
|
||||
uint64_t ntHandle = 0u;
|
||||
GmmRequirements gmmRequirements{};
|
||||
gmmRequirements.allowLargePages = true;
|
||||
gmmRequirements.preferCompressed = true;
|
||||
Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), nullptr, 20, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements);
|
||||
|
||||
// Test with createNTHandle = false (shareableWithoutNTHandle = true)
|
||||
EXPECT_EQ(STATUS_SUCCESS, wddm->createAllocation(nullptr, &gmm, handle, resourceHandle, &ntHandle, false));
|
||||
EXPECT_NE(handle, 0u);
|
||||
EXPECT_NE(resourceHandle, 0u);
|
||||
EXPECT_EQ(ntHandle, 0u); // Should be set to 1 to indicate shared resource without NT handle
|
||||
EXPECT_EQ(wddm->destroyAllocationResult.called, 0u);
|
||||
}
|
||||
|
||||
TEST_F(WdmmSharedTests, WhenCreatingSharedAllocationWithNormalShareableFlagThenNTHandleCreationIsAttempted) {
|
||||
init();
|
||||
|
||||
D3DKMT_HANDLE handle = 32u;
|
||||
D3DKMT_HANDLE resourceHandle = 32u;
|
||||
uint64_t ntHandle = 0u;
|
||||
GmmRequirements gmmRequirements{};
|
||||
gmmRequirements.allowLargePages = true;
|
||||
gmmRequirements.preferCompressed = true;
|
||||
Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), nullptr, 20, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements);
|
||||
|
||||
// Test with createNTHandle = true (shareableWithoutNTHandle = false)
|
||||
EXPECT_NE(STATUS_SUCCESS, wddm->createAllocation(nullptr, &gmm, handle, resourceHandle, &ntHandle, true));
|
||||
EXPECT_EQ(wddm->destroyAllocationResult.called, 2u); // Should be called because NT handle creation failed
|
||||
EXPECT_EQ(handle, 0u);
|
||||
EXPECT_EQ(resourceHandle, 0u);
|
||||
}
|
||||
|
||||
@@ -1200,6 +1200,15 @@ TEST_F(WddmTests, givenPageAlignedReadOnlyMemoryPassedToCreateAllocationsAndMapG
|
||||
EXPECT_FALSE(readWriteExistingSysMemSupportedForTest);
|
||||
}
|
||||
|
||||
TEST_F(WddmTests, givenOsHandleDataWithoutOpaqueInformationWhenGettingSharedHandleThenReturnOriginalHandle) {
|
||||
uint64_t originalHandle = 0x12345678;
|
||||
MemoryManager::OsHandleData osHandleData(originalHandle);
|
||||
|
||||
HANDLE sharedHandle = wddm->getSharedHandle(osHandleData);
|
||||
|
||||
EXPECT_EQ(reinterpret_cast<HANDLE>(static_cast<uintptr_t>(originalHandle)), sharedHandle);
|
||||
}
|
||||
|
||||
TEST_F(WddmTests, whenThereIsNoExisitngSysMemoryThenReadOnlyFallbackIsNotAvailable) {
|
||||
D3DKMT_CREATEALLOCATION createAllocation{};
|
||||
D3DDDI_ALLOCATIONINFO2 allocationInfo2{};
|
||||
@@ -1231,4 +1240,156 @@ TEST_F(WddmTests, givenSysMemoryPointerAndReadOnlyFlagNotSetInCreateAllocationFl
|
||||
auto readOnlyFallbackSupported = wddm->isReadOnlyFlagFallbackSupported();
|
||||
EXPECT_EQ(readOnlyFallbackSupported, wddm->isReadOnlyFlagFallbackAvailable(createAllocation));
|
||||
}
|
||||
|
||||
// Mock class for testing createNTHandle scenarios
|
||||
class WddmCreateNTHandleMock : public WddmMock {
|
||||
public:
|
||||
using WddmMock::WddmMock;
|
||||
|
||||
NTSTATUS createNTHandle(const D3DKMT_HANDLE *resourceHandle, HANDLE *ntHandle) override {
|
||||
createNTHandleCalled = true;
|
||||
lastResourceHandle = resourceHandle ? *resourceHandle : 0;
|
||||
|
||||
if (shouldCreateNTHandleFail) {
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
*ntHandle = reinterpret_cast<HANDLE>(0x12345678);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
bool createNTHandleCalled = false;
|
||||
D3DKMT_HANDLE lastResourceHandle = 0;
|
||||
bool shouldCreateNTHandleFail = false;
|
||||
};
|
||||
|
||||
class WddmCreateAllocationNTHandleTests : public WddmTestWithMockGdiDll {
|
||||
public:
|
||||
void SetUp() override {
|
||||
WddmTestWithMockGdiDll::SetUp();
|
||||
|
||||
// Replace the wddm with our mock
|
||||
mockWddm = new WddmCreateNTHandleMock(*rootDeviceEnvironment);
|
||||
auto wddmMockInterface = new WddmMockInterface20(*mockWddm);
|
||||
mockWddm->wddmInterface.reset(wddmMockInterface);
|
||||
rootDeviceEnvironment->osInterface = std::make_unique<OSInterface>();
|
||||
rootDeviceEnvironment->osInterface->setDriverModel(std::unique_ptr<DriverModel>(mockWddm));
|
||||
rootDeviceEnvironment->memoryOperationsInterface = std::make_unique<WddmMemoryOperationsHandler>(mockWddm);
|
||||
|
||||
// Initialize the mock WDDM
|
||||
mockWddm->init();
|
||||
}
|
||||
|
||||
void initGmm() {
|
||||
GmmRequirements gmmRequirements{};
|
||||
gmmRequirements.allowLargePages = true;
|
||||
gmmRequirements.preferCompressed = true;
|
||||
gmm = std::make_unique<Gmm>(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(),
|
||||
nullptr, 20, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, StorageInfo{}, gmmRequirements);
|
||||
}
|
||||
|
||||
WddmCreateNTHandleMock *mockWddm = nullptr;
|
||||
std::unique_ptr<Gmm> gmm;
|
||||
};
|
||||
|
||||
TEST_F(WddmCreateAllocationNTHandleTests, givenOutSharedHandleAndCreateNTHandleTrueThenCreateNTHandleIsCalled) {
|
||||
initGmm();
|
||||
|
||||
D3DKMT_HANDLE handle = 0;
|
||||
D3DKMT_HANDLE resourceHandle = 0;
|
||||
uint64_t sharedHandle = 0;
|
||||
|
||||
// Test the condition: outSharedHandle && createNTHandle (both true)
|
||||
auto result = mockWddm->createAllocation(nullptr, gmm.get(), handle, resourceHandle, &sharedHandle, true);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, result);
|
||||
EXPECT_TRUE(mockWddm->createNTHandleCalled);
|
||||
EXPECT_NE(0u, handle);
|
||||
EXPECT_NE(0u, resourceHandle);
|
||||
EXPECT_NE(0u, sharedHandle);
|
||||
|
||||
// Cleanup
|
||||
EXPECT_TRUE(mockWddm->destroyAllocations(&handle, 1, resourceHandle));
|
||||
}
|
||||
|
||||
TEST_F(WddmCreateAllocationNTHandleTests, givenOutSharedHandleNullAndCreateNTHandleTrueThenCreateNTHandleIsNotCalled) {
|
||||
initGmm();
|
||||
|
||||
D3DKMT_HANDLE handle = 0;
|
||||
D3DKMT_HANDLE resourceHandle = 0;
|
||||
|
||||
// Test the condition: outSharedHandle is null, createNTHandle is true
|
||||
auto result = mockWddm->createAllocation(nullptr, gmm.get(), handle, resourceHandle, nullptr, true);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, result);
|
||||
EXPECT_FALSE(mockWddm->createNTHandleCalled);
|
||||
EXPECT_NE(0u, handle);
|
||||
// When outSharedHandle is null, CreateResource flag is FALSE, so resourceHandle stays 0
|
||||
EXPECT_EQ(0u, resourceHandle);
|
||||
|
||||
// Cleanup only the handle (no resource handle to clean up)
|
||||
EXPECT_TRUE(mockWddm->destroyAllocations(&handle, 1, 0));
|
||||
}
|
||||
|
||||
TEST_F(WddmCreateAllocationNTHandleTests, givenOutSharedHandleAndCreateNTHandleFalseThenCreateNTHandleIsNotCalled) {
|
||||
initGmm();
|
||||
|
||||
D3DKMT_HANDLE handle = 0;
|
||||
D3DKMT_HANDLE resourceHandle = 0;
|
||||
uint64_t sharedHandle = 0;
|
||||
|
||||
// Test the condition: outSharedHandle is valid, createNTHandle is false
|
||||
auto result = mockWddm->createAllocation(nullptr, gmm.get(), handle, resourceHandle, &sharedHandle, false);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, result);
|
||||
EXPECT_FALSE(mockWddm->createNTHandleCalled);
|
||||
EXPECT_NE(0u, handle);
|
||||
EXPECT_NE(0u, resourceHandle);
|
||||
EXPECT_EQ(0u, sharedHandle); // Should remain 0 since no NT handle was created
|
||||
|
||||
// Cleanup
|
||||
EXPECT_TRUE(mockWddm->destroyAllocations(&handle, 1, resourceHandle));
|
||||
}
|
||||
|
||||
TEST_F(WddmCreateAllocationNTHandleTests, givenCreateNTHandleFailsThenAllocationIsDestroyedAndHandlesAreReset) {
|
||||
initGmm();
|
||||
|
||||
D3DKMT_HANDLE handle = 0;
|
||||
D3DKMT_HANDLE resourceHandle = 0;
|
||||
uint64_t sharedHandle = 0;
|
||||
|
||||
// Set up the mock to fail createNTHandle
|
||||
mockWddm->shouldCreateNTHandleFail = true;
|
||||
|
||||
// Test the condition: outSharedHandle && createNTHandle (both true) but createNTHandle fails
|
||||
auto result = mockWddm->createAllocation(nullptr, gmm.get(), handle, resourceHandle, &sharedHandle, true);
|
||||
|
||||
EXPECT_NE(STATUS_SUCCESS, result);
|
||||
EXPECT_TRUE(mockWddm->createNTHandleCalled);
|
||||
EXPECT_EQ(0u, handle); // Should be reset to NULL_HANDLE
|
||||
EXPECT_EQ(0u, resourceHandle); // Should be reset to NULL_HANDLE
|
||||
// sharedHandle value is not modified on failure in this path
|
||||
}
|
||||
|
||||
TEST_F(WddmCreateAllocationNTHandleTests, givenCreateNTHandleSucceedsThenSharedHandleIsSet) {
|
||||
initGmm();
|
||||
|
||||
D3DKMT_HANDLE handle = 0;
|
||||
D3DKMT_HANDLE resourceHandle = 0;
|
||||
uint64_t sharedHandle = 0;
|
||||
|
||||
// Test successful createNTHandle path
|
||||
auto result = mockWddm->createAllocation(nullptr, gmm.get(), handle, resourceHandle, &sharedHandle, true);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, result);
|
||||
EXPECT_TRUE(mockWddm->createNTHandleCalled);
|
||||
EXPECT_EQ(mockWddm->lastResourceHandle, resourceHandle);
|
||||
EXPECT_NE(0u, handle);
|
||||
EXPECT_NE(0u, resourceHandle);
|
||||
EXPECT_EQ(0x12345678u, sharedHandle); // Should be set to the mock handle value
|
||||
|
||||
// Cleanup
|
||||
EXPECT_TRUE(mockWddm->destroyAllocations(&handle, 1, resourceHandle));
|
||||
}
|
||||
|
||||
} // namespace NEO
|
||||
|
||||
@@ -33,6 +33,9 @@ extern SysCalls::ProcessPowerThrottlingState setProcessPowerThrottlingStateLastV
|
||||
extern size_t setThreadPriorityCalled;
|
||||
extern SysCalls::ThreadPriority setThreadPriorityLastValue;
|
||||
extern MEMORY_BASIC_INFORMATION virtualQueryMemoryBasicInformation;
|
||||
extern size_t closeHandleCalled;
|
||||
extern BOOL (*sysCallsDuplicateHandle)(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
|
||||
extern HANDLE (*sysCallsOpenProcess)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
|
||||
} // namespace SysCalls
|
||||
extern uint32_t numRootDevicesToEnum;
|
||||
extern bool gCreateAllocation2FailOnReadOnlyAllocation;
|
||||
@@ -461,3 +464,99 @@ TEST_F(WddmTestWithMockGdiDll, whenGettingReadOnlyFlagThenReturnTrueOnlyForPageM
|
||||
TEST_F(WddmTestWithMockGdiDll, whenGettingReadOnlyFlagFallbackSupportThenTrueIsReturned) {
|
||||
EXPECT_TRUE(wddm->isReadOnlyFlagFallbackSupported());
|
||||
}
|
||||
|
||||
TEST_F(WddmTestWithMockGdiDll, givenOsHandleDataWithoutParentProcessWhenGettingSharedHandleThenReturnOriginalHandle) {
|
||||
uint64_t originalHandle = 0x12345678;
|
||||
MemoryManager::OsHandleData osHandleData(originalHandle);
|
||||
|
||||
HANDLE sharedHandle = wddm->getSharedHandle(osHandleData);
|
||||
|
||||
EXPECT_EQ(reinterpret_cast<HANDLE>(static_cast<uintptr_t>(originalHandle)), sharedHandle);
|
||||
}
|
||||
|
||||
TEST_F(WddmTestWithMockGdiDll, givenOsHandleDataWithParentProcessWhenGettingSharedHandleThenDuplicateHandleFromParentProcess) {
|
||||
uint64_t originalHandle = 0x12345678;
|
||||
uint32_t parentProcessId = 1234;
|
||||
MemoryManager::OsHandleData osHandleData(originalHandle);
|
||||
osHandleData.parentProcessId = parentProcessId;
|
||||
|
||||
HANDLE mockDuplicatedHandle = reinterpret_cast<HANDLE>(0x8888);
|
||||
|
||||
// Mock openProcess to return a valid handle
|
||||
SysCalls::sysCallsOpenProcess = [](DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) -> HANDLE {
|
||||
EXPECT_EQ(static_cast<DWORD>(PROCESS_DUP_HANDLE), dwDesiredAccess);
|
||||
EXPECT_EQ(FALSE, bInheritHandle);
|
||||
EXPECT_EQ(1234u, dwProcessId);
|
||||
return reinterpret_cast<HANDLE>(0x9999);
|
||||
};
|
||||
|
||||
// Mock duplicateHandle to succeed
|
||||
SysCalls::sysCallsDuplicateHandle = [](HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) -> BOOL {
|
||||
EXPECT_EQ(reinterpret_cast<HANDLE>(0x9999), hSourceProcessHandle);
|
||||
EXPECT_EQ(reinterpret_cast<HANDLE>(static_cast<uintptr_t>(0x12345678)), hSourceHandle);
|
||||
EXPECT_EQ(GetCurrentProcess(), hTargetProcessHandle);
|
||||
EXPECT_EQ(GENERIC_READ | GENERIC_WRITE, dwDesiredAccess);
|
||||
EXPECT_EQ(FALSE, bInheritHandle);
|
||||
EXPECT_EQ(0u, dwOptions);
|
||||
*lpTargetHandle = reinterpret_cast<HANDLE>(0x8888);
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
size_t closeHandleCallsBefore = SysCalls::closeHandleCalled;
|
||||
|
||||
HANDLE sharedHandle = wddm->getSharedHandle(osHandleData);
|
||||
|
||||
EXPECT_EQ(mockDuplicatedHandle, sharedHandle);
|
||||
EXPECT_EQ(closeHandleCallsBefore + 1, SysCalls::closeHandleCalled); // Parent process handle should be closed
|
||||
|
||||
// Cleanup
|
||||
SysCalls::sysCallsOpenProcess = nullptr;
|
||||
SysCalls::sysCallsDuplicateHandle = nullptr;
|
||||
}
|
||||
|
||||
TEST_F(WddmTestWithMockGdiDll, givenOsHandleDataWithParentProcessWhenOpenProcessFailsThenReturnOriginalHandle) {
|
||||
uint64_t originalHandle = 0x12345678;
|
||||
uint32_t parentProcessId = 1234;
|
||||
MemoryManager::OsHandleData osHandleData(originalHandle);
|
||||
osHandleData.parentProcessId = parentProcessId;
|
||||
|
||||
// Mock openProcess to fail
|
||||
SysCalls::sysCallsOpenProcess = [](DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) -> HANDLE {
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
HANDLE sharedHandle = wddm->getSharedHandle(osHandleData);
|
||||
|
||||
EXPECT_EQ(reinterpret_cast<HANDLE>(static_cast<uintptr_t>(originalHandle)), sharedHandle);
|
||||
|
||||
// Cleanup
|
||||
SysCalls::sysCallsOpenProcess = nullptr;
|
||||
}
|
||||
|
||||
TEST_F(WddmTestWithMockGdiDll, givenOsHandleDataWithParentProcessWhenDuplicateHandleFailsThenReturnOriginalHandle) {
|
||||
uint64_t originalHandle = 0x12345678;
|
||||
uint32_t parentProcessId = 1234;
|
||||
MemoryManager::OsHandleData osHandleData(originalHandle);
|
||||
osHandleData.parentProcessId = parentProcessId;
|
||||
|
||||
// Mock openProcess to succeed
|
||||
SysCalls::sysCallsOpenProcess = [](DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) -> HANDLE {
|
||||
return reinterpret_cast<HANDLE>(0x9999);
|
||||
};
|
||||
|
||||
// Mock duplicateHandle to fail
|
||||
SysCalls::sysCallsDuplicateHandle = [](HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) -> BOOL {
|
||||
return FALSE;
|
||||
};
|
||||
|
||||
size_t closeHandleCallsBefore = SysCalls::closeHandleCalled;
|
||||
|
||||
HANDLE sharedHandle = wddm->getSharedHandle(osHandleData);
|
||||
|
||||
EXPECT_EQ(reinterpret_cast<HANDLE>(static_cast<uintptr_t>(originalHandle)), sharedHandle);
|
||||
EXPECT_EQ(closeHandleCallsBefore + 1, SysCalls::closeHandleCalled); // Parent process handle should still be closed
|
||||
|
||||
// Cleanup
|
||||
SysCalls::sysCallsOpenProcess = nullptr;
|
||||
SysCalls::sysCallsDuplicateHandle = nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user