Make IPC events available for P2P operations

Signed-off-by: Jaime Arteaga <jaime.a.arteaga.molina@intel.com>
This commit is contained in:
Jaime Arteaga 2021-10-12 03:26:35 +00:00 committed by Compute-Runtime-Automation
parent 75b7adbe95
commit e0a093b87a
5 changed files with 537 additions and 13 deletions

View File

@ -424,7 +424,9 @@ ze_result_t EventPoolImp::getIpcHandle(ze_ipc_event_pool_handle_t *pIpcHandle) {
// First four bytes (which is of size sizeof(int)) of it contain the file descriptor // First four bytes (which is of size sizeof(int)) of it contain the file descriptor
// associated with the dma-buf, // associated with the dma-buf,
// Rest is payload to communicate extra info to the other processes. // Rest is payload to communicate extra info to the other processes.
// For the event pool, this contains the number of events the pool has. // For the event pool, this contains:
// - the number of events the pool has.
// - the id for the device used during pool creation
uint64_t handle = this->eventPoolAllocations->getDefaultGraphicsAllocation()->peekInternalHandle(this->context->getDriverHandle()->getMemoryManager()); uint64_t handle = this->eventPoolAllocations->getDefaultGraphicsAllocation()->peekInternalHandle(this->context->getDriverHandle()->getMemoryManager());
@ -432,17 +434,24 @@ ze_result_t EventPoolImp::getIpcHandle(ze_ipc_event_pool_handle_t *pIpcHandle) {
memcpy_s(pIpcHandle->data + sizeof(int), sizeof(this->numEvents), &this->numEvents, sizeof(this->numEvents)); memcpy_s(pIpcHandle->data + sizeof(int), sizeof(this->numEvents), &this->numEvents, sizeof(this->numEvents));
uint32_t rootDeviceIndex = this->getDevice()->getRootDeviceIndex();
memcpy_s(pIpcHandle->data + sizeof(int) + sizeof(this->numEvents),
sizeof(rootDeviceIndex), &rootDeviceIndex, sizeof(rootDeviceIndex));
return ZE_RESULT_SUCCESS; return ZE_RESULT_SUCCESS;
} }
ze_result_t ContextImp::openEventPoolIpcHandle(ze_ipc_event_pool_handle_t hIpc, ze_result_t ContextImp::openEventPoolIpcHandle(ze_ipc_event_pool_handle_t hIpc,
ze_event_pool_handle_t *phEventPool) { ze_event_pool_handle_t *phEventPool) {
uint64_t handle = 0u; uint64_t handle = 0u;
memcpy_s(&handle, sizeof(handle), hIpc.data, sizeof(handle)); memcpy_s(&handle, sizeof(int), hIpc.data, sizeof(int));
uint32_t numEvents = 0; size_t numEvents = 0;
memcpy_s(&numEvents, sizeof(numEvents), hIpc.data + sizeof(int), sizeof(int)); memcpy_s(&numEvents, sizeof(numEvents), hIpc.data + sizeof(int), sizeof(numEvents));
uint32_t rootDeviceIndex = std::numeric_limits<uint32_t>::max();
memcpy_s(&rootDeviceIndex, sizeof(rootDeviceIndex),
hIpc.data + sizeof(int) + sizeof(numEvents), sizeof(rootDeviceIndex));
Device *device = this->devices.begin()->second; Device *device = this->devices.begin()->second;
auto neoDevice = device->getNEODevice(); auto neoDevice = device->getNEODevice();
@ -451,17 +460,17 @@ ze_result_t ContextImp::openEventPoolIpcHandle(ze_ipc_event_pool_handle_t hIpc,
const uint32_t eventAlignment = static_cast<uint32_t>(hwHelper.getTimestampPacketAllocatorAlignment()); const uint32_t eventAlignment = static_cast<uint32_t>(hwHelper.getTimestampPacketAllocatorAlignment());
uint32_t eventSize = static_cast<uint32_t>(alignUp(EventPacketsCount::eventPackets * hwHelper.getSingleTimestampPacketSize(), eventAlignment)); uint32_t eventSize = static_cast<uint32_t>(alignUp(EventPacketsCount::eventPackets * hwHelper.getSingleTimestampPacketSize(), eventAlignment));
size_t alignedSize = alignUp<size_t>(numEvents * eventSize, MemoryConstants::pageSize64k); size_t alignedSize = alignUp<size_t>(numEvents * eventSize, MemoryConstants::pageSize64k);
NEO::AllocationProperties unifiedMemoryProperties{neoDevice->getRootDeviceIndex(), NEO::AllocationProperties unifiedMemoryProperties{rootDeviceIndex,
alignedSize, alignedSize,
NEO::GraphicsAllocation::AllocationType::BUFFER_HOST_MEMORY, NEO::GraphicsAllocation::AllocationType::BUFFER_HOST_MEMORY,
systemMemoryBitfield}; systemMemoryBitfield};
unifiedMemoryProperties.subDevicesBitfield = neoDevice->getDeviceBitfield(); unifiedMemoryProperties.subDevicesBitfield = neoDevice->getDeviceBitfield();
NEO::GraphicsAllocation *alloc = auto memoryManager = this->getDriverHandle()->getMemoryManager();
this->getDriverHandle()->getMemoryManager()->createGraphicsAllocationFromSharedHandle(osHandle, NEO::GraphicsAllocation *alloc = memoryManager->createGraphicsAllocationFromSharedHandle(osHandle,
unifiedMemoryProperties, unifiedMemoryProperties,
false, false,
true); true);
if (alloc == nullptr) { if (alloc == nullptr) {
return ZE_RESULT_ERROR_INVALID_ARGUMENT; return ZE_RESULT_ERROR_INVALID_ARGUMENT;
@ -470,7 +479,8 @@ ze_result_t ContextImp::openEventPoolIpcHandle(ze_ipc_event_pool_handle_t hIpc,
ze_event_pool_desc_t desc = {}; ze_event_pool_desc_t desc = {};
auto eventPool = new EventPoolImp(&desc); auto eventPool = new EventPoolImp(&desc);
eventPool->context = this; eventPool->context = this;
eventPool->eventPoolAllocations = std::make_unique<NEO::MultiGraphicsAllocation>(0u); eventPool->eventPoolAllocations =
std::make_unique<NEO::MultiGraphicsAllocation>(static_cast<uint32_t>(this->rootDeviceIndices.size()));
eventPool->eventPoolAllocations->addAllocation(alloc); eventPool->eventPoolAllocations->addAllocation(alloc);
eventPool->eventPoolPtr = reinterpret_cast<void *>(alloc->getUnderlyingBuffer()); eventPool->eventPoolPtr = reinterpret_cast<void *>(alloc->getUnderlyingBuffer());
eventPool->devices.push_back(device); eventPool->devices.push_back(device);
@ -478,6 +488,31 @@ ze_result_t ContextImp::openEventPoolIpcHandle(ze_ipc_event_pool_handle_t hIpc,
eventPool->setEventSize(eventSize); eventPool->setEventSize(eventSize);
eventPool->setEventAlignment(eventAlignment); eventPool->setEventAlignment(eventAlignment);
for (auto currDeviceIndex : this->rootDeviceIndices) {
if (currDeviceIndex == rootDeviceIndex) {
continue;
}
unifiedMemoryProperties.rootDeviceIndex = currDeviceIndex;
unifiedMemoryProperties.flags.isUSMHostAllocation = true;
unifiedMemoryProperties.flags.forceSystemMemory = true;
unifiedMemoryProperties.flags.allocateMemory = false;
auto graphicsAllocation = memoryManager->createGraphicsAllocationFromExistingStorage(unifiedMemoryProperties,
eventPool->eventPoolPtr,
eventPool->getAllocation());
if (!graphicsAllocation) {
for (auto gpuAllocation : eventPool->getAllocation().getGraphicsAllocations()) {
memoryManager->freeGraphicsMemory(gpuAllocation);
}
memoryManager->freeGraphicsMemory(alloc);
delete eventPool;
return ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}
eventPool->eventPoolAllocations->addAllocation(graphicsAllocation);
}
*phEventPool = eventPool; *phEventPool = eventPool;
return ZE_RESULT_SUCCESS; return ZE_RESULT_SUCCESS;

View File

@ -54,6 +54,20 @@ inline bool isParamEnabled(int argc, char *argv[], const char *shortName, const
return false; return false;
} }
inline int getParamValue(int argc, char *argv[], const char *shortName, const char *longName, int defaultValue) {
char **arg = &argv[1];
char **argE = &argv[argc];
for (; arg != argE; ++arg) {
if ((0 == strcmp(*arg, shortName)) || (0 == strcmp(*arg, longName))) {
arg++;
return atoi(*arg);
}
}
return defaultValue;
}
inline bool isVerbose(int argc, char *argv[]) { inline bool isVerbose(int argc, char *argv[]) {
bool enabled = isParamEnabled(argc, argv, "-v", "--verbose"); bool enabled = isParamEnabled(argc, argv, "-v", "--verbose");
if (enabled == false) { if (enabled == false) {

View File

@ -0,0 +1,411 @@
/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "zello_common.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
extern bool verbose;
bool verbose = false;
uint8_t uinitializedPattern = 1;
uint8_t expectedPattern = 7;
size_t allocSize = 4096 + 7; // +7 to break alignment and make it harder
uint32_t serverDevice = 0;
uint32_t clientDevice = 1;
static int sendmsg_fd(int socket, int fd, char *payload, size_t payloadLen) {
char sendBuf[sizeof(ze_ipc_mem_handle_t)] = {};
char cmsgBuf[CMSG_SPACE(sizeof(ze_ipc_mem_handle_t))];
struct iovec msgBuffer;
msgBuffer.iov_base = payload;
msgBuffer.iov_len = payloadLen;
struct msghdr msgHeader = {};
msgHeader.msg_iov = &msgBuffer;
msgHeader.msg_iovlen = 1;
msgHeader.msg_control = cmsgBuf;
msgHeader.msg_controllen = CMSG_LEN(sizeof(fd));
struct cmsghdr *controlHeader = CMSG_FIRSTHDR(&msgHeader);
controlHeader->cmsg_type = SCM_RIGHTS;
controlHeader->cmsg_level = SOL_SOCKET;
controlHeader->cmsg_len = CMSG_LEN(sizeof(fd));
*(int *)CMSG_DATA(controlHeader) = fd;
ssize_t bytesSent = sendmsg(socket, &msgHeader, 0);
if (bytesSent < 0) {
return -1;
}
return 0;
}
static int recvmsg_fd(int socket, char *payload, size_t payloadLen) {
int fd = -1;
char recvBuf[sizeof(ze_ipc_mem_handle_t)] = {};
char cmsgBuf[CMSG_SPACE(sizeof(ze_ipc_mem_handle_t))];
struct iovec msgBuffer;
msgBuffer.iov_base = payload;
msgBuffer.iov_len = payloadLen;
struct msghdr msgHeader = {};
msgHeader.msg_iov = &msgBuffer;
msgHeader.msg_iovlen = 1;
msgHeader.msg_control = cmsgBuf;
msgHeader.msg_controllen = CMSG_LEN(sizeof(fd));
ssize_t bytesSent = recvmsg(socket, &msgHeader, 0);
if (bytesSent < 0) {
return -1;
}
struct cmsghdr *controlHeader = CMSG_FIRSTHDR(&msgHeader);
memmove(&fd, CMSG_DATA(controlHeader), sizeof(int));
return fd;
}
inline void initializeProcess(ze_context_handle_t &context,
ze_device_handle_t &device,
ze_command_queue_handle_t &cmdQueue,
ze_command_list_handle_t &cmdList,
ze_command_queue_handle_t &cmdQueueCopy,
ze_command_list_handle_t &cmdListCopy,
bool isServer) {
SUCCESS_OR_TERMINATE(zeInit(ZE_INIT_FLAG_GPU_ONLY));
// Retrieve driver
uint32_t driverCount = 0;
SUCCESS_OR_TERMINATE(zeDriverGet(&driverCount, nullptr));
ze_driver_handle_t driverHandle;
SUCCESS_OR_TERMINATE(zeDriverGet(&driverCount, &driverHandle));
ze_context_desc_t contextDesc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC};
SUCCESS_OR_TERMINATE(zeContextCreate(driverHandle, &contextDesc, &context));
// Retrieve device
uint32_t deviceCount = 0;
SUCCESS_OR_TERMINATE(zeDeviceGet(driverHandle, &deviceCount, nullptr));
std::cout << "Number of devices found: " << deviceCount << "\n";
std::vector<ze_device_handle_t> devices(deviceCount);
SUCCESS_OR_TERMINATE(zeDeviceGet(driverHandle, &deviceCount, devices.data()));
// Make the server use device0 and the client device1 if available
if (deviceCount > 1) {
ze_bool_t canAccessPeer = false;
SUCCESS_OR_TERMINATE(zeDeviceCanAccessPeer(devices[0], devices[1], &canAccessPeer));
if (canAccessPeer == false) {
std::cerr << "Two devices found but no P2P capabilities detected\n";
std::terminate();
} else {
std::cerr << "Two devices found and P2P capabilities detected\n";
}
}
if (deviceCount == 1) {
serverDevice = clientDevice = 0;
}
if (isServer == false) {
device = devices[clientDevice];
std::cout << "Client using device " << clientDevice << "\n";
} else {
device = devices[serverDevice];
std::cout << "Server using device " << serverDevice << "\n";
}
// Print some properties
ze_device_properties_t deviceProperties = {ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES};
SUCCESS_OR_TERMINATE(zeDeviceGetProperties(device, &deviceProperties));
std::cout << "Device : \n"
<< " * name : " << deviceProperties.name << "\n"
<< " * vendorId : " << std::hex << deviceProperties.vendorId << "\n";
// Create command queue
uint32_t numQueueGroups = 0;
SUCCESS_OR_TERMINATE(zeDeviceGetCommandQueueGroupProperties(device, &numQueueGroups, nullptr));
if (numQueueGroups == 0) {
std::cerr << "No queue groups found!\n";
std::terminate();
}
std::vector<ze_command_queue_group_properties_t> queueProperties(numQueueGroups);
for (auto &queueProperty : queueProperties) {
queueProperty.stype = ZE_STRUCTURE_TYPE_COMMAND_QUEUE_GROUP_PROPERTIES;
}
SUCCESS_OR_TERMINATE(zeDeviceGetCommandQueueGroupProperties(device, &numQueueGroups,
queueProperties.data()));
ze_command_queue_desc_t cmdQueueDesc = {ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC};
ze_command_queue_desc_t cmdQueueDescCopy = {ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC};
for (uint32_t i = 0; i < numQueueGroups; i++) {
if (queueProperties[i].flags & ZE_COMMAND_QUEUE_GROUP_PROPERTY_FLAG_COMPUTE) {
cmdQueueDesc.ordinal = i;
break;
}
}
std::cout << (isServer ? "Server " : "Client ") << " using queues "
<< cmdQueueDescCopy.ordinal << " and " << cmdQueueDesc.ordinal << "\n";
cmdQueueDesc.index = 0;
cmdQueueDesc.mode = ZE_COMMAND_QUEUE_MODE_ASYNCHRONOUS;
SUCCESS_OR_TERMINATE(zeCommandQueueCreate(context, device, &cmdQueueDesc, &cmdQueue));
cmdQueueDescCopy.index = 0;
cmdQueueDescCopy.mode = ZE_COMMAND_QUEUE_MODE_ASYNCHRONOUS;
SUCCESS_OR_TERMINATE(zeCommandQueueCreate(context, device, &cmdQueueDescCopy, &cmdQueueCopy));
// Create command list
ze_command_list_desc_t cmdListDesc = {ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC};
cmdListDesc.commandQueueGroupOrdinal = cmdQueueDesc.ordinal;
SUCCESS_OR_TERMINATE(zeCommandListCreate(context, device, &cmdListDesc, &cmdList));
ze_command_list_desc_t cmdListDescCopy = {ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC};
cmdListDescCopy.commandQueueGroupOrdinal = cmdQueueDescCopy.ordinal;
SUCCESS_OR_TERMINATE(zeCommandListCreate(context, device, &cmdListDescCopy, &cmdListCopy));
}
void run_client(int commSocket) {
std::cout << "Client process " << std::dec << getpid() << "\n";
ze_context_handle_t context;
ze_device_handle_t device;
ze_command_queue_handle_t cmdQueue;
ze_command_list_handle_t cmdList;
ze_command_queue_handle_t cmdQueueCopy;
ze_command_list_handle_t cmdListCopy;
initializeProcess(context, device, cmdQueue, cmdList, cmdQueueCopy, cmdListCopy, false);
// receieve the IPC handle for the event pool from the other process
ze_ipc_event_pool_handle_t pIpcEventPoolHandle = {};
int dma_buf_fd = recvmsg_fd(commSocket, pIpcEventPoolHandle.data, ZE_MAX_IPC_HANDLE_SIZE);
if (dma_buf_fd < 0) {
std::cerr << "Failing to get IPC event pool handle from server\n";
std::terminate();
}
// get the event pool associated with the IPC handle
ze_event_pool_handle_t eventPool = {};
SUCCESS_OR_TERMINATE(zeEventPoolOpenIpcHandle(context, pIpcEventPoolHandle, &eventPool));
// get the number of events from the payload
uint32_t numEvents = 0;
memcpy(&numEvents, pIpcEventPoolHandle.data + sizeof(int), sizeof(int));
std::vector<ze_event_handle_t> events(numEvents);
uint32_t i = 0;
ze_event_desc_t eventDesc = {ZE_STRUCTURE_TYPE_EVENT_DESC};
eventDesc.signal = ZE_EVENT_SCOPE_FLAG_HOST;
eventDesc.wait = ZE_EVENT_SCOPE_FLAG_HOST;
for (auto &event : events) {
eventDesc.index = i++;
SUCCESS_OR_TERMINATE(zeEventCreate(eventPool, &eventDesc, &event));
SUCCESS_OR_TERMINATE(zeEventHostReset(event));
ze_result_t eventStatus = zeEventQueryStatus(event);
if (eventStatus != ZE_RESULT_NOT_READY) {
std::cerr << "Event reset in clinent failed\n";
std::terminate();
}
}
void *zeBuffer = nullptr;
ze_device_mem_alloc_desc_t deviceDesc = {ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC};
SUCCESS_OR_TERMINATE(zeMemAllocDevice(context, &deviceDesc, allocSize, allocSize, device, &zeBuffer));
SUCCESS_OR_TERMINATE(zeCommandListAppendMemoryFill(cmdList, zeBuffer, reinterpret_cast<void *>(&expectedPattern),
sizeof(expectedPattern), allocSize, nullptr, 0, nullptr));
SUCCESS_OR_TERMINATE(zeCommandListClose(cmdList));
SUCCESS_OR_TERMINATE(zeCommandQueueExecuteCommandLists(cmdQueue, 1, &cmdList, nullptr));
SUCCESS_OR_TERMINATE(zeCommandQueueSynchronize(cmdQueue, std::numeric_limits<uint64_t>::max()));
// get the dma_buf from the other process
ze_ipc_mem_handle_t pIpcHandle;
dma_buf_fd = recvmsg_fd(commSocket, pIpcHandle.data, ZE_MAX_IPC_HANDLE_SIZE);
if (dma_buf_fd < 0) {
std::cerr << "Failing to get dma_buf fd from server\n";
std::terminate();
}
memcpy(&pIpcHandle, static_cast<void *>(&dma_buf_fd), sizeof(dma_buf_fd));
// get a memory pointer to the BO associated with the dma_buf
void *zeIpcBuffer;
SUCCESS_OR_TERMINATE(zeMemOpenIpcHandle(context, device, pIpcHandle, 0u, &zeIpcBuffer));
// Copy from client to server
SUCCESS_OR_TERMINATE(zeCommandListAppendMemoryCopy(cmdListCopy, zeIpcBuffer, zeBuffer, allocSize, events[0], 0, nullptr));
SUCCESS_OR_TERMINATE(zeCommandListClose(cmdListCopy));
SUCCESS_OR_TERMINATE(zeCommandQueueExecuteCommandLists(cmdQueueCopy, 1, &cmdListCopy, nullptr));
SUCCESS_OR_TERMINATE(zeCommandQueueSynchronize(cmdQueueCopy, std::numeric_limits<uint64_t>::max()));
SUCCESS_OR_TERMINATE(zeMemCloseIpcHandle(context, zeIpcBuffer));
SUCCESS_OR_TERMINATE(zeCommandListDestroy(cmdList));
SUCCESS_OR_TERMINATE(zeCommandQueueDestroy(cmdQueue));
SUCCESS_OR_TERMINATE(zeCommandListDestroy(cmdListCopy));
SUCCESS_OR_TERMINATE(zeCommandQueueDestroy(cmdQueueCopy));
SUCCESS_OR_TERMINATE(zeMemFree(context, zeBuffer));
SUCCESS_OR_TERMINATE(zeContextDestroy(context));
}
void run_server(int commSocket, bool &validRet) {
std::cout << "Server process " << std::dec << getpid() << "\n";
ze_context_handle_t context;
ze_device_handle_t device;
ze_command_queue_handle_t cmdQueue;
ze_command_list_handle_t cmdList;
ze_command_queue_handle_t cmdQueueCopy;
ze_command_list_handle_t cmdListCopy;
initializeProcess(context, device, cmdQueue, cmdList, cmdQueueCopy, cmdListCopy, true);
uint32_t numEvents = 2;
ze_event_pool_handle_t eventPool = {};
ze_event_pool_desc_t eventPoolDesc = {ZE_STRUCTURE_TYPE_EVENT_POOL_DESC};
eventPoolDesc.count = numEvents;
eventPoolDesc.flags = {};
SUCCESS_OR_TERMINATE(zeEventPoolCreate(context, &eventPoolDesc, 1, &device, &eventPool));
std::vector<ze_event_handle_t> events(numEvents);
uint32_t i = 0;
ze_event_desc_t eventDesc = {ZE_STRUCTURE_TYPE_EVENT_DESC};
eventDesc.signal = ZE_EVENT_SCOPE_FLAG_HOST;
eventDesc.wait = ZE_EVENT_SCOPE_FLAG_HOST;
for (auto &event : events) {
eventDesc.index = i++;
SUCCESS_OR_TERMINATE(zeEventCreate(eventPool, &eventDesc, &event));
SUCCESS_OR_TERMINATE(zeEventHostReset(event));
ze_result_t eventStatus = zeEventQueryStatus(event);
if (eventStatus != ZE_RESULT_NOT_READY) {
std::cerr << "Event status in server before starting not correct\n";
std::terminate();
}
}
// Get the IPC handle for the event pool
ze_ipc_event_pool_handle_t pIpcEventPoolHandle;
SUCCESS_OR_TERMINATE(zeEventPoolGetIpcHandle(eventPool, &pIpcEventPoolHandle));
// Pass the IPC handle to the other process
int dma_buf_fd;
memcpy(static_cast<void *>(&dma_buf_fd), &pIpcEventPoolHandle, sizeof(dma_buf_fd));
if (sendmsg_fd(commSocket, static_cast<int>(dma_buf_fd), pIpcEventPoolHandle.data, ZE_MAX_IPC_HANDLE_SIZE) < 0) {
std::cerr << "Failing to send IPC event pool handle to client\n";
std::terminate();
}
void *zeBuffer = nullptr;
ze_device_mem_alloc_desc_t deviceDesc = {ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC};
SUCCESS_OR_TERMINATE(zeMemAllocDevice(context, &deviceDesc, allocSize, allocSize, device, &zeBuffer));
// Initialize the IPC buffer
SUCCESS_OR_TERMINATE(zeCommandListAppendMemoryFill(cmdList, zeBuffer, reinterpret_cast<void *>(&uinitializedPattern),
sizeof(uinitializedPattern), allocSize, nullptr, 0, nullptr));
SUCCESS_OR_TERMINATE(zeCommandListClose(cmdList));
SUCCESS_OR_TERMINATE(zeCommandQueueExecuteCommandLists(cmdQueue, 1, &cmdList, nullptr));
SUCCESS_OR_TERMINATE(zeCommandQueueSynchronize(cmdQueue, std::numeric_limits<uint64_t>::max()));
SUCCESS_OR_TERMINATE(zeCommandListReset(cmdList));
// Get a dma_buf for the previously allocated pointer
ze_ipc_mem_handle_t pIpcHandle;
SUCCESS_OR_TERMINATE(zeMemGetIpcHandle(context, zeBuffer, &pIpcHandle));
// Pass the dma_buf to the other process
memcpy(static_cast<void *>(&dma_buf_fd), &pIpcHandle, sizeof(dma_buf_fd));
if (sendmsg_fd(commSocket, static_cast<int>(dma_buf_fd), pIpcHandle.data, ZE_MAX_IPC_HANDLE_SIZE) < 0) {
std::cerr << "Failing to send dma_buf fd to client\n";
std::terminate();
}
char *heapBuffer = new char[allocSize];
for (size_t i = 0; i < allocSize; ++i) {
heapBuffer[i] = expectedPattern;
}
// Wait for child to exit
int child_status;
pid_t clientPId = wait(&child_status);
if (clientPId <= 0) {
std::cerr << "Client terminated abruptly with error code " << strerror(errno) << "\n";
std::terminate();
}
void *validateBuffer = nullptr;
ze_host_mem_alloc_desc_t hostDesc = {ZE_STRUCTURE_TYPE_HOST_MEM_ALLOC_DESC};
SUCCESS_OR_TERMINATE(zeMemAllocShared(context, &deviceDesc, &hostDesc, allocSize, 1, device, &validateBuffer));
SUCCESS_OR_TERMINATE(zeCommandListAppendMemoryFill(cmdList, validateBuffer, reinterpret_cast<void *>(&uinitializedPattern),
sizeof(uinitializedPattern), allocSize, nullptr, 0, nullptr));
SUCCESS_OR_TERMINATE(zeCommandListAppendBarrier(cmdList, nullptr, 0, nullptr));
// Copy from device-allocated memory
SUCCESS_OR_TERMINATE(zeCommandListAppendMemoryCopy(cmdList, validateBuffer, zeBuffer, allocSize,
nullptr, 1, &events[0]));
//nullptr, 0, nullptr));
SUCCESS_OR_TERMINATE(zeCommandListClose(cmdList));
SUCCESS_OR_TERMINATE(zeCommandQueueExecuteCommandLists(cmdQueue, 1, &cmdList, nullptr));
SUCCESS_OR_TERMINATE(zeCommandQueueSynchronize(cmdQueue, std::numeric_limits<uint64_t>::max()));
// Validate stack and buffers have the original data from heapBuffer
validRet = (0 == memcmp(heapBuffer, validateBuffer, allocSize));
delete[] heapBuffer;
SUCCESS_OR_TERMINATE(zeMemFree(context, zeBuffer));
SUCCESS_OR_TERMINATE(zeCommandListDestroy(cmdList));
SUCCESS_OR_TERMINATE(zeCommandQueueDestroy(cmdQueue));
SUCCESS_OR_TERMINATE(zeCommandListDestroy(cmdListCopy));
SUCCESS_OR_TERMINATE(zeCommandQueueDestroy(cmdQueueCopy));
SUCCESS_OR_TERMINATE(zeContextDestroy(context));
}
int main(int argc, char *argv[]) {
verbose = isVerbose(argc, argv);
bool outputValidationSuccessful;
serverDevice = getParamValue(argc, argv, "-s", "--serverdevice", 1);
clientDevice = getParamValue(argc, argv, "-c", "--clientdevice", 0);
int sv[2];
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
perror("socketpair");
exit(1);
}
int child = fork();
if (child < 0) {
perror("fork");
exit(1);
} else if (0 == child) {
close(sv[0]);
run_client(sv[1]);
close(sv[1]);
exit(0);
} else {
close(sv[1]);
run_server(sv[0], outputValidationSuccessful);
close(sv[0]);
}
std::cout << "\nZello IPC P2P With Event Results validation "
<< (outputValidationSuccessful ? "PASSED" : "FAILED")
<< std::endl;
return 0;
}

View File

@ -66,7 +66,7 @@ struct MultiDeviceFixture {
DebugManagerStateRestore restorer; DebugManagerStateRestore restorer;
std::unique_ptr<Mock<L0::DriverHandleImp>> driverHandle; std::unique_ptr<Mock<L0::DriverHandleImp>> driverHandle;
std::vector<NEO::Device *> devices; std::vector<NEO::Device *> devices;
uint32_t numRootDevices = 2u; uint32_t numRootDevices = 4u;
uint32_t numSubDevices = 2u; uint32_t numSubDevices = 2u;
L0::ContextImp *context = nullptr; L0::ContextImp *context = nullptr;
}; };

View File

@ -324,6 +324,70 @@ TEST_F(EventPoolOpenIPCHandleFailTests, givenFailureToAllocateMemoryWhenOpeningI
EXPECT_EQ(res, ZE_RESULT_SUCCESS); EXPECT_EQ(res, ZE_RESULT_SUCCESS);
} }
class MultiDeviceEventPoolOpenIPCHandleFailTestsMemoryManager : public FailMemoryManager {
public:
MultiDeviceEventPoolOpenIPCHandleFailTestsMemoryManager(NEO::ExecutionEnvironment &executionEnvironment) : FailMemoryManager(executionEnvironment) {}
GraphicsAllocation *createGraphicsAllocationFromSharedHandle(osHandle handle, const AllocationProperties &properties, bool requireSpecificBitness, bool isHostIpcAllocation) override {
return &mockAllocation0;
}
GraphicsAllocation *createGraphicsAllocationFromExistingStorage(AllocationProperties &properties, void *ptr, MultiGraphicsAllocation &multiGraphicsAllocation) override {
if (calls == 0) {
calls++;
return &mockAllocation1;
}
return nullptr;
}
void freeGraphicsMemory(GraphicsAllocation *gfxAllocation) override {
}
NEO::MockGraphicsAllocation mockAllocation0;
NEO::MockGraphicsAllocation mockAllocation1;
uint32_t calls = 0;
};
using MultiDeviceEventPoolOpenIPCHandleFailTests = Test<MultiDeviceFixture>;
TEST_F(MultiDeviceEventPoolOpenIPCHandleFailTests,
givenFailureToAllocateMemoryWhenOpeningIpcHandleForEventPoolWithMultipleDevicesThenOutOfHostMemoryIsReturned) {
uint32_t numEvents = 4;
ze_event_pool_desc_t eventPoolDesc = {
ZE_STRUCTURE_TYPE_EVENT_POOL_DESC,
nullptr,
ZE_EVENT_POOL_FLAG_HOST_VISIBLE,
numEvents};
auto deviceHandle = driverHandle->devices[0]->toHandle();
auto eventPool = EventPool::create(driverHandle.get(), context, 1, &deviceHandle, &eventPoolDesc);
EXPECT_NE(nullptr, eventPool);
ze_ipc_event_pool_handle_t ipcHandle = {};
ze_result_t res = eventPool->getIpcHandle(&ipcHandle);
EXPECT_EQ(res, ZE_RESULT_SUCCESS);
{
NEO::MemoryManager *prevMemoryManager = nullptr;
NEO::MemoryManager *currMemoryManager = nullptr;
prevMemoryManager = driverHandle->getMemoryManager();
NEO::MockDevice *neoDevice = static_cast<NEO::MockDevice *>(driverHandle->devices[0]->getNEODevice());
currMemoryManager = new MultiDeviceEventPoolOpenIPCHandleFailTestsMemoryManager(*neoDevice->executionEnvironment);
driverHandle->setMemoryManager(currMemoryManager);
ze_event_pool_handle_t ipcEventPoolHandle = {};
res = context->openEventPoolIpcHandle(ipcHandle, &ipcEventPoolHandle);
EXPECT_EQ(res, ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY);
driverHandle->setMemoryManager(prevMemoryManager);
delete currMemoryManager;
}
res = eventPool->destroy();
EXPECT_EQ(res, ZE_RESULT_SUCCESS);
}
TEST_F(EventPoolCreate, GivenNullptrDeviceAndNumberOfDevicesWhenCreatingEventPoolThenReturnError) { TEST_F(EventPoolCreate, GivenNullptrDeviceAndNumberOfDevicesWhenCreatingEventPoolThenReturnError) {
ze_event_pool_desc_t eventPoolDesc = { ze_event_pool_desc_t eventPoolDesc = {
ZE_STRUCTURE_TYPE_EVENT_POOL_DESC, ZE_STRUCTURE_TYPE_EVENT_POOL_DESC,