Skip to content

Commit 134c718

Browse files
MaciejBielskiCompute-Runtime-Automation
authored andcommittedJan 19, 2024
fix: support zeEventPool IPC handles from single process
For all execution paths where needed, use `BufferObjectHandleWrapper` instances for registration of BO-handles and try to obtain shared ownership. This allows both sides of IPC communication to be implemented in the same process and avoid the double-free problem on a BufferObject of the same handle. Currently there are two pairs of such calls: * `zeEventPoolGetIpcHandle()` + `zeEventPoolOpenIpcHandle()` * `zeMemGetIpcHandle()` + `zeMemOpenIpcHandle()` The capability of executing both sides from the same process is useful for testing but not only. Related-To: NEO-9837 Signed-off-by: Maciej Bielski <maciej.bielski@intel.com>
1 parent b5f698e commit 134c718

File tree

3 files changed

+182
-7
lines changed

3 files changed

+182
-7
lines changed
 

‎level_zero/core/source/event/event.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,13 @@ ze_result_t EventPool::getIpcHandle(ze_ipc_event_pool_handle_t *ipcHandle) {
257257
poolData.maxEventPackets = this->getEventMaxPackets();
258258
poolData.numDevices = static_cast<uint32_t>(this->devices.size());
259259

260-
int retCode = this->eventPoolAllocations->getDefaultGraphicsAllocation()->peekInternalHandle(this->context->getDriverHandle()->getMemoryManager(), poolData.handle);
261-
return retCode == 0 ? ZE_RESULT_SUCCESS : ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
260+
auto memoryManager = this->context->getDriverHandle()->getMemoryManager();
261+
auto allocation = this->eventPoolAllocations->getDefaultGraphicsAllocation();
262+
if (int retCode = allocation->peekInternalHandle(memoryManager, poolData.handle); retCode != 0) {
263+
return ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
264+
}
265+
memoryManager->registerIpcExportedAllocation(allocation);
266+
return ZE_RESULT_SUCCESS;
262267
}
263268

264269
ze_result_t EventPool::openEventPoolIpcHandle(const ze_ipc_event_pool_handle_t &ipcEventPoolHandle, ze_event_pool_handle_t *eventPoolHandle,

‎shared/source/os_interface/linux/drm_memory_manager.cpp

+20-5
Original file line numberDiff line numberDiff line change
@@ -2470,18 +2470,30 @@ DrmAllocation *DrmMemoryManager::createUSMHostAllocationFromSharedHandle(osHandl
24702470
return allocation;
24712471
}
24722472

2473+
auto boHandle = static_cast<int>(openFd.handle);
2474+
auto boHandleWrapper = reuseSharedAllocation ? BufferObjectHandleWrapper{boHandle} : tryToGetBoHandleWrapperWithSharedOwnership(boHandle);
2475+
24732476
const bool useBooMmap = drm.getMemoryInfo() && properties.useMmapObject;
24742477
if (!useBooMmap) {
2475-
auto bo = new BufferObject(properties.rootDeviceIndex, &drm, patIndex, openFd.handle, properties.size, maxOsContextCount);
2478+
auto bo = new BufferObject(properties.rootDeviceIndex, &drm, patIndex, std::move(boHandleWrapper), properties.size, maxOsContextCount);
24762479
bo->setAddress(properties.gpuAddress);
24772480

24782481
auto gmmHelper = getGmmHelper(properties.rootDeviceIndex);
24792482
auto canonizedGpuAddress = gmmHelper->canonize(castToUint64(reinterpret_cast<void *>(bo->peekAddress())));
2480-
return new DrmAllocation(properties.rootDeviceIndex, properties.allocationType, bo, reinterpret_cast<void *>(bo->peekAddress()), bo->peekSize(),
2481-
handle, memoryPool, canonizedGpuAddress);
2483+
auto drmAllocation = std::make_unique<DrmAllocation>(properties.rootDeviceIndex,
2484+
properties.allocationType,
2485+
bo,
2486+
reinterpret_cast<void *>(bo->peekAddress()),
2487+
bo->peekSize(),
2488+
handle,
2489+
memoryPool,
2490+
canonizedGpuAddress);
2491+
if (!reuseSharedAllocation) {
2492+
registerSharedBoHandleAllocation(drmAllocation.get());
2493+
}
2494+
return drmAllocation.release();
24822495
}
24832496

2484-
auto boHandle = openFd.handle;
24852497
BufferObject *bo = nullptr;
24862498
if (reuseSharedAllocation) {
24872499
bo = findAndReferenceSharedBufferObject(boHandle, properties.rootDeviceIndex);
@@ -2494,7 +2506,7 @@ DrmAllocation *DrmMemoryManager::createUSMHostAllocationFromSharedHandle(osHandl
24942506

24952507
memoryPool = MemoryPool::system4KBPages;
24962508
patIndex = drm.getPatIndex(nullptr, properties.allocationType, CacheRegion::defaultRegion, CachePolicy::writeBack, false, MemoryPoolHelper::isSystemMemoryPool(memoryPool));
2497-
bo = new BufferObject(properties.rootDeviceIndex, &drm, patIndex, boHandle, size, maxOsContextCount);
2509+
bo = new BufferObject(properties.rootDeviceIndex, &drm, patIndex, std::move(boHandleWrapper), size, maxOsContextCount);
24982510

24992511
if (properties.allocationType == AllocationType::gpuTimestampDeviceBuffer) {
25002512
cpuPointer = this->mmapFunction(0, size + MemoryConstants::pageSize64k, PROT_NONE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
@@ -2553,6 +2565,9 @@ DrmAllocation *DrmMemoryManager::createUSMHostAllocationFromSharedHandle(osHandl
25532565
return nullptr;
25542566
}
25552567

2568+
if (!reuseSharedAllocation) {
2569+
registerSharedBoHandleAllocation(drmAllocation.get());
2570+
}
25562571
return drmAllocation.release();
25572572
}
25582573

‎shared/test/unit_test/os_interface/linux/drm_memory_manager_tests.cpp

+155
Original file line numberDiff line numberDiff line change
@@ -3858,6 +3858,161 @@ TEST(DrmMemoryManagerFreeGraphicsMemoryUnreferenceTest,
38583858
EXPECT_EQ(expectedOutput.str(), output);
38593859
}
38603860

3861+
struct DrmMemoryManagerWithHostIpcAllocationParamTest : public DrmMemoryManagerFixture, ::testing::TestWithParam<bool> {
3862+
void SetUp() override {
3863+
DrmMemoryManagerFixture::setUp();
3864+
}
3865+
void TearDown() override {
3866+
DrmMemoryManagerFixture::tearDown();
3867+
}
3868+
};
3869+
3870+
TEST_P(DrmMemoryManagerWithHostIpcAllocationParamTest,
3871+
givenIPCBoHandleAndSharedAllocationReuseEnabledWhenAllocationCreatedThenBoHandleSharingIsNotUsed) {
3872+
const bool reuseSharedAllocation = true;
3873+
3874+
mock->ioctlExpected.primeFdToHandle = 1;
3875+
mock->ioctlExpected.gemWait = 1;
3876+
mock->ioctlExpected.gemClose = 1;
3877+
mock->outputHandle = 88u;
3878+
bool isHostIpcAllocation = GetParam();
3879+
AllocationProperties properties(rootDeviceIndex, false, 4096u, AllocationType::sharedBuffer, false, {});
3880+
3881+
osHandle handle1 = 11u;
3882+
auto gfxAllocation1 = memoryManager->createGraphicsAllocationFromSharedHandle(handle1, properties, false, isHostIpcAllocation, reuseSharedAllocation, nullptr);
3883+
DrmAllocation *drmAllocation1 = static_cast<DrmAllocation *>(gfxAllocation1);
3884+
ASSERT_NE(nullptr, drmAllocation1);
3885+
3886+
// BoHandle not registered as shared at all
3887+
auto bo1 = drmAllocation1->getBO();
3888+
EXPECT_NE(bo1, nullptr);
3889+
EXPECT_EQ(static_cast<uint32_t>(bo1->getHandle()), mock->outputHandle);
3890+
EXPECT_FALSE(bo1->isBoHandleShared());
3891+
auto boHandleWrapperIt1 = memoryManager->sharedBoHandles.find(mock->outputHandle);
3892+
EXPECT_EQ(boHandleWrapperIt1, std::end(memoryManager->sharedBoHandles));
3893+
3894+
memoryManager->freeGraphicsMemory(gfxAllocation1);
3895+
}
3896+
3897+
TEST_P(DrmMemoryManagerWithHostIpcAllocationParamTest,
3898+
givenIPCBoHandleAndSharedAllocationReuseEnabledWhenAllocationCreatedFromMultipleHandlesThenBoHandleSharingIsNotUsed) {
3899+
const bool reuseSharedAllocation = true;
3900+
3901+
mock->ioctlExpected.primeFdToHandle = 1;
3902+
mock->ioctlExpected.gemWait = 1;
3903+
mock->ioctlExpected.gemClose = 1;
3904+
mock->outputHandle = 88u;
3905+
bool isHostIpcAllocation = GetParam();
3906+
AllocationProperties properties(rootDeviceIndex, true, 4096u, AllocationType::sharedBuffer, false, {0b0010});
3907+
3908+
std::vector<osHandle> handles = {11u};
3909+
auto gfxAllocation1 = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, isHostIpcAllocation, reuseSharedAllocation, nullptr);
3910+
DrmAllocation *drmAllocation1 = static_cast<DrmAllocation *>(gfxAllocation1);
3911+
ASSERT_NE(nullptr, drmAllocation1);
3912+
3913+
// BoHandle not registered as shared at all
3914+
auto bo1 = drmAllocation1->getBO();
3915+
EXPECT_NE(bo1, nullptr);
3916+
EXPECT_EQ(static_cast<uint32_t>(bo1->getHandle()), mock->outputHandle);
3917+
EXPECT_FALSE(bo1->isBoHandleShared());
3918+
auto boHandleWrapperIt1 = memoryManager->sharedBoHandles.find(mock->outputHandle);
3919+
EXPECT_EQ(boHandleWrapperIt1, std::end(memoryManager->sharedBoHandles));
3920+
3921+
memoryManager->freeGraphicsMemory(gfxAllocation1);
3922+
}
3923+
3924+
TEST_P(DrmMemoryManagerWithHostIpcAllocationParamTest,
3925+
givenIPCBoHandleAndSharedAllocationReuseDisabledWhenMultipleAllocationsCreatedFromSingleProcessThenBoHandleIsClosedOnlyOnce) {
3926+
const bool reuseSharedAllocation = false;
3927+
3928+
mock->ioctlExpected.primeFdToHandle = 2;
3929+
mock->ioctlExpected.gemWait = 2;
3930+
mock->ioctlExpected.gemClose = 1;
3931+
mock->outputHandle = 88u;
3932+
bool isHostIpcAllocation = GetParam();
3933+
AllocationProperties properties(rootDeviceIndex, false, 4096u, AllocationType::sharedBuffer, false, {});
3934+
3935+
osHandle handle1 = 11u;
3936+
auto gfxAllocation1 = memoryManager->createGraphicsAllocationFromSharedHandle(handle1, properties, false, isHostIpcAllocation, reuseSharedAllocation, nullptr);
3937+
DrmAllocation *drmAllocation1 = static_cast<DrmAllocation *>(gfxAllocation1);
3938+
ASSERT_NE(nullptr, drmAllocation1);
3939+
3940+
// BoHandle registered as shared but with WEAK ownership - GEM_CLOSE can be called on it
3941+
auto bo1 = drmAllocation1->getBO();
3942+
EXPECT_NE(bo1, nullptr);
3943+
EXPECT_EQ(static_cast<uint32_t>(bo1->getHandle()), mock->outputHandle);
3944+
EXPECT_TRUE(bo1->isBoHandleShared());
3945+
auto boHandleWrapperIt1 = memoryManager->sharedBoHandles.find(mock->outputHandle);
3946+
EXPECT_NE(boHandleWrapperIt1, std::end(memoryManager->sharedBoHandles));
3947+
EXPECT_TRUE(boHandleWrapperIt1->second.canCloseBoHandle());
3948+
3949+
osHandle handle2 = 12u;
3950+
auto gfxAllocation2 = memoryManager->createGraphicsAllocationFromSharedHandle(handle2, properties, false, isHostIpcAllocation, false, nullptr);
3951+
DrmAllocation *drmAllocation2 = static_cast<DrmAllocation *>(gfxAllocation2);
3952+
ASSERT_NE(nullptr, drmAllocation2);
3953+
// BoHandle registered as shared with SHARED ownership - GEM_CLOSE cannot be called on it
3954+
auto bo2 = drmAllocation2->getBO();
3955+
EXPECT_NE(bo2, nullptr);
3956+
EXPECT_EQ(static_cast<uint32_t>(bo2->getHandle()), mock->outputHandle);
3957+
EXPECT_TRUE(bo2->isBoHandleShared());
3958+
auto boHandleWrapperIt2 = memoryManager->sharedBoHandles.find(mock->outputHandle);
3959+
EXPECT_EQ(boHandleWrapperIt2, boHandleWrapperIt1);
3960+
EXPECT_FALSE(boHandleWrapperIt2->second.canCloseBoHandle());
3961+
3962+
memoryManager->freeGraphicsMemory(gfxAllocation2);
3963+
// GEM_CLOSE can be called on BoHandle again
3964+
EXPECT_TRUE(boHandleWrapperIt2->second.canCloseBoHandle());
3965+
memoryManager->freeGraphicsMemory(gfxAllocation1);
3966+
}
3967+
3968+
TEST_P(DrmMemoryManagerWithHostIpcAllocationParamTest,
3969+
givenIPCBoHandleAndSharedAllocationReuseDisabledWhenMultipleAllocationsCreatedFromMultipleSharedHandlesFromSingleProcessThenBoHandleIsClosedOnlyOnce) {
3970+
const bool reuseSharedAllocation = false;
3971+
3972+
mock->ioctlExpected.primeFdToHandle = 2;
3973+
mock->ioctlExpected.gemWait = 2;
3974+
mock->ioctlExpected.gemClose = 1;
3975+
mock->outputHandle = 88u;
3976+
bool isHostIpcAllocation = GetParam();
3977+
AllocationProperties properties(rootDeviceIndex, true, 4096u, AllocationType::sharedBuffer, false, {});
3978+
3979+
std::vector<osHandle> handles1 = {11u};
3980+
auto gfxAllocation1 = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles1, properties, false, isHostIpcAllocation, reuseSharedAllocation, nullptr);
3981+
DrmAllocation *drmAllocation1 = static_cast<DrmAllocation *>(gfxAllocation1);
3982+
ASSERT_NE(nullptr, drmAllocation1);
3983+
3984+
// BoHandle registered as shared but with WEAK ownership - GEM_CLOSE can be called on it
3985+
auto bo1 = drmAllocation1->getBO();
3986+
EXPECT_NE(bo1, nullptr);
3987+
EXPECT_EQ(static_cast<uint32_t>(bo1->getHandle()), mock->outputHandle);
3988+
EXPECT_TRUE(bo1->isBoHandleShared());
3989+
auto boHandleWrapperIt1 = memoryManager->sharedBoHandles.find(mock->outputHandle);
3990+
EXPECT_NE(boHandleWrapperIt1, std::end(memoryManager->sharedBoHandles));
3991+
EXPECT_TRUE(boHandleWrapperIt1->second.canCloseBoHandle());
3992+
3993+
std::vector<osHandle> handles2 = {12u};
3994+
auto gfxAllocation2 = memoryManager->createGraphicsAllocationFromMultipleSharedHandles(handles2, properties, false, isHostIpcAllocation, false, nullptr);
3995+
DrmAllocation *drmAllocation2 = static_cast<DrmAllocation *>(gfxAllocation2);
3996+
ASSERT_NE(nullptr, drmAllocation2);
3997+
// BoHandle registered as shared with SHARED ownership - GEM_CLOSE cannot be called on it
3998+
auto bo2 = drmAllocation2->getBO();
3999+
EXPECT_NE(bo2, nullptr);
4000+
EXPECT_EQ(static_cast<uint32_t>(bo2->getHandle()), mock->outputHandle);
4001+
EXPECT_TRUE(bo2->isBoHandleShared());
4002+
auto boHandleWrapperIt2 = memoryManager->sharedBoHandles.find(mock->outputHandle);
4003+
EXPECT_EQ(boHandleWrapperIt2, boHandleWrapperIt1);
4004+
EXPECT_FALSE(boHandleWrapperIt2->second.canCloseBoHandle());
4005+
4006+
memoryManager->freeGraphicsMemory(gfxAllocation2);
4007+
// GEM_CLOSE can be called on BoHandle again
4008+
EXPECT_TRUE(boHandleWrapperIt2->second.canCloseBoHandle());
4009+
memoryManager->freeGraphicsMemory(gfxAllocation1);
4010+
}
4011+
4012+
INSTANTIATE_TEST_CASE_P(HostIpcAllocationFlag,
4013+
DrmMemoryManagerWithHostIpcAllocationParamTest,
4014+
::testing::Values(false, true));
4015+
38614016
TEST(DrmMemoryManagerFreeGraphicsMemoryUnreferenceTest,
38624017
givenCallToCreateSharedAllocationWithReuseSharedAllocationThenAllocationsSuccedAndAddressesAreTheSame) {
38634018
MockExecutionEnvironment executionEnvironment(defaultHwInfo.get());

0 commit comments

Comments
 (0)
Please sign in to comment.