Skip to content

Commit 8193312

Browse files
fix(debugger): use per-context fences for vm_bind operations
- vm_bind with user fence updates fence value independently for every VM hence with per-context VMs, every context needs its unique fence address. This prevents 2 contexts from updating value possibly writing lower value than the one that was already stored Resolves: NEO-8004 Source: 7d82b69 Signed-off-by: Mateusz Hoppe <[email protected]>
1 parent 662ff7b commit 8193312

File tree

6 files changed

+134
-6
lines changed

6 files changed

+134
-6
lines changed

shared/source/os_interface/linux/drm_neo.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,8 +1464,19 @@ int changeBufferObjectBinding(Drm *drm, OsContext *osContext, uint32_t vmHandleI
14641464

14651465
if (!drm->hasPageFaultSupport() || bo->isExplicitResidencyRequired()) {
14661466
auto nextExtension = vmBind.extensions;
1467-
auto address = castToUint64(drm->getFenceAddr(vmHandleId));
1468-
auto value = drm->getNextFenceVal(vmHandleId);
1467+
1468+
uint64_t address = 0;
1469+
uint64_t value = 0;
1470+
1471+
if (drm->isPerContextVMRequired()) {
1472+
auto osContextLinux = static_cast<OsContextLinux *>(osContext);
1473+
address = castToUint64(osContextLinux->getFenceAddr(vmHandleId));
1474+
value = osContextLinux->getNextFenceVal(vmHandleId);
1475+
} else {
1476+
address = castToUint64(drm->getFenceAddr(vmHandleId));
1477+
value = drm->getNextFenceVal(vmHandleId);
1478+
}
1479+
14691480
incrementFenceValue = true;
14701481
ioctlHelper->fillVmBindExtUserFence(vmBindExtUserFence, address, value, nextExtension);
14711482
vmBind.extensions = castToUint64(vmBindExtUserFence);
@@ -1487,7 +1498,12 @@ int changeBufferObjectBinding(Drm *drm, OsContext *osContext, uint32_t vmHandleI
14871498
}
14881499
}
14891500
if (incrementFenceValue) {
1490-
drm->incFenceVal(vmHandleId);
1501+
if (drm->isPerContextVMRequired()) {
1502+
auto osContextLinux = static_cast<OsContextLinux *>(osContext);
1503+
osContextLinux->incFenceVal(vmHandleId);
1504+
} else {
1505+
drm->incFenceVal(vmHandleId);
1506+
}
14911507
}
14921508
}
14931509

shared/source/os_interface/linux/os_context_linux.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "shared/source/execution_environment/root_device_environment.h"
1313
#include "shared/source/helpers/engine_node_helper.h"
1414
#include "shared/source/helpers/hw_info.h"
15+
#include "shared/source/helpers/ptr_math.h"
1516
#include "shared/source/os_interface/linux/drm_neo.h"
1617
#include "shared/source/os_interface/linux/ioctl_helper.h"
1718
#include "shared/source/os_interface/os_context.h"
@@ -30,7 +31,10 @@ OsContext *OsContextLinux::create(OSInterface *osInterface, uint32_t rootDeviceI
3031

3132
OsContextLinux::OsContextLinux(Drm &drm, uint32_t rootDeviceIndex, uint32_t contextId, const EngineDescriptor &engineDescriptor)
3233
: OsContext(rootDeviceIndex, contextId, engineDescriptor),
33-
drm(drm) {}
34+
drm(drm) {
35+
pagingFence.fill(0u);
36+
fenceVal.fill(0u);
37+
}
3438

3539
bool OsContextLinux::initializeContext() {
3640
auto hwInfo = drm.getRootDeviceEnvironment().getHardwareInfo();
@@ -88,8 +92,25 @@ Drm &OsContextLinux::getDrm() const {
8892
void OsContextLinux::waitForPagingFence() {
8993
for (auto drmIterator = 0u; drmIterator < this->deviceBitfield.size(); drmIterator++) {
9094
if (this->deviceBitfield.test(drmIterator)) {
91-
drm.waitForBind(drmIterator);
95+
this->waitForBind(drmIterator);
96+
}
97+
}
98+
}
99+
100+
void OsContextLinux::waitForBind(uint32_t drmIterator) {
101+
if (drm.isPerContextVMRequired()) {
102+
if (pagingFence[drmIterator] >= fenceVal[drmIterator]) {
103+
return;
92104
}
105+
auto lock = drm.lockBindFenceMutex();
106+
auto fenceAddress = castToUint64(&this->pagingFence[drmIterator]);
107+
auto fenceValue = this->fenceVal[drmIterator];
108+
lock.unlock();
109+
110+
drm.waitUserFence(0u, fenceAddress, fenceValue, Drm::ValueWidth::U64, -1, drm.getIoctlHelper()->getWaitUserFenceSoftFlag());
111+
112+
} else {
113+
drm.waitForBind(drmIterator);
93114
}
94115
}
95116

shared/source/os_interface/linux/os_context_linux.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
#pragma once
99

1010
#include "shared/source/helpers/mt_helpers.h"
11+
#include "shared/source/memory_manager/definitions/engine_limits.h"
1112
#include "shared/source/os_interface/os_context.h"
1213

14+
#include <array>
1315
#include <atomic>
1416
#include <vector>
1517

@@ -52,6 +54,11 @@ class OsContextLinux : public OsContext {
5254

5355
uint64_t getOfflineDumpContextId(uint32_t deviceIndex) const override;
5456

57+
uint64_t getNextFenceVal(uint32_t deviceIndex) { return fenceVal[deviceIndex] + 1; }
58+
void incFenceVal(uint32_t deviceIndex) { fenceVal[deviceIndex]++; }
59+
uint64_t *getFenceAddr(uint32_t deviceIndex) { return &pagingFence[deviceIndex]; }
60+
void waitForBind(uint32_t drmIterator);
61+
5562
protected:
5663
bool initializeContext() override;
5764

@@ -60,6 +67,10 @@ class OsContextLinux : public OsContext {
6067
unsigned int engineFlag = 0;
6168
std::vector<uint32_t> drmContextIds;
6269
std::vector<uint32_t> drmVmIds;
70+
71+
std::array<uint64_t, EngineLimits::maxHandleCount> pagingFence;
72+
std::array<uint64_t, EngineLimits::maxHandleCount> fenceVal;
73+
6374
Drm &drm;
6475
bool contextHangDetected = false;
6576
};

shared/test/common/mocks/linux/mock_os_context_linux.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ namespace NEO {
1212
class MockOsContextLinux : public OsContextLinux {
1313
public:
1414
using OsContextLinux::drmContextIds;
15+
using OsContextLinux::fenceVal;
16+
using OsContextLinux::pagingFence;
1517

1618
MockOsContextLinux(Drm &drm, uint32_t rootDeviceIndex, uint32_t contextId, const EngineDescriptor &engineDescriptor)
1719
: OsContextLinux(drm, rootDeviceIndex, contextId, engineDescriptor) {}

shared/test/unit_test/os_interface/linux/drm_vm_bind_prelim_tests.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2018-2022 Intel Corporation
2+
* Copyright (C) 2018-2023 Intel Corporation
33
*
44
* SPDX-License-Identifier: MIT
55
*
@@ -12,6 +12,7 @@
1212
#include "shared/test/common/helpers/engine_descriptor_helper.h"
1313
#include "shared/test/common/libult/linux/drm_query_mock.h"
1414
#include "shared/test/common/mocks/linux/mock_drm_allocation.h"
15+
#include "shared/test/common/mocks/linux/mock_os_context_linux.h"
1516
#include "shared/test/common/mocks/mock_execution_environment.h"
1617

1718
#include "gtest/gtest.h"
@@ -59,6 +60,35 @@ TEST(DrmVmBindTest, givenBoRequiringExplicitResidencyWhenBindingThenMakeResident
5960
}
6061
}
6162

63+
TEST(DrmVmBindTest, givenPerContextVmsAndBoRequiringExplicitResidencyWhenBindingThenPagingFenceFromContextIsUsed) {
64+
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
65+
executionEnvironment->rootDeviceEnvironments[0]->initGmm();
66+
executionEnvironment->initializeMemoryManager();
67+
DrmQueryMock drm{*executionEnvironment->rootDeviceEnvironments[0]};
68+
drm.pageFaultSupported = true;
69+
drm.requirePerContextVM = true;
70+
71+
for (auto requireResidency : {false, true}) {
72+
MockBufferObject bo(&drm, 3, 0, 0, 1);
73+
bo.requireExplicitResidency(requireResidency);
74+
75+
MockOsContextLinux osContext(drm, 0, 0u, EngineDescriptorHelper::getDefaultDescriptor());
76+
osContext.ensureContextInitialized();
77+
uint32_t vmHandleId = 0;
78+
bo.bind(&osContext, vmHandleId);
79+
80+
if (requireResidency) {
81+
EXPECT_EQ(DrmPrelimHelper::getImmediateVmBindFlag() | DrmPrelimHelper::getMakeResidentVmBindFlag(), drm.context.receivedVmBind->flags);
82+
ASSERT_TRUE(drm.context.receivedVmBindUserFence);
83+
EXPECT_EQ(castToUint64(osContext.getFenceAddr(vmHandleId)), drm.context.receivedVmBindUserFence->addr);
84+
EXPECT_EQ(osContext.fenceVal[vmHandleId], drm.context.receivedVmBindUserFence->val);
85+
EXPECT_EQ(1u, osContext.fenceVal[vmHandleId]);
86+
} else {
87+
EXPECT_EQ(DrmPrelimHelper::getImmediateVmBindFlag(), drm.context.receivedVmBind->flags);
88+
}
89+
}
90+
}
91+
6292
TEST(DrmVmBindTest, givenBoNotRequiringExplicitResidencyWhenCallingWaitForBindThenDontWaitOnUserFence) {
6393
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
6494
executionEnvironment->rootDeviceEnvironments[0]->initGmm();

shared/test/unit_test/os_interface/linux/os_context_linux_tests.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#include "shared/source/os_interface/linux/drm_memory_operations_handler.h"
9+
#include "shared/source/os_interface/linux/ioctl_helper.h"
910
#include "shared/source/os_interface/linux/os_context_linux.h"
1011
#include "shared/test/common/helpers/engine_descriptor_helper.h"
1112
#include "shared/test/common/libult/linux/drm_mock.h"
@@ -68,3 +69,50 @@ TEST(OSContextLinux, givenOsContextLinuxWhenQueryingForOfflineDumpContextIdThenC
6869

6970
EXPECT_EQ(0u, osContext.getOfflineDumpContextId(10));
7071
}
72+
73+
TEST(OSContextLinux, givenPerContextVmsAndBindNotCompleteWhenWaitForPagingFenceThenContextFenceIsPassedToWaitUserFenceIoctl) {
74+
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
75+
DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]};
76+
drm.requirePerContextVM = true;
77+
78+
MockOsContextLinux osContext(drm, 0, 0u, EngineDescriptorHelper::getDefaultDescriptor());
79+
osContext.ensureContextInitialized();
80+
81+
drm.pagingFence[0] = 26u;
82+
drm.fenceVal[0] = 31u;
83+
84+
osContext.pagingFence[0] = 46u;
85+
osContext.fenceVal[0] = 51u;
86+
87+
osContext.waitForPagingFence();
88+
89+
EXPECT_EQ(1u, drm.waitUserFenceParams.size());
90+
EXPECT_EQ(0u, drm.waitUserFenceParams[0].ctxId);
91+
EXPECT_EQ(castToUint64(&osContext.pagingFence[0]), drm.waitUserFenceParams[0].address);
92+
EXPECT_EQ(drm.ioctlHelper->getWaitUserFenceSoftFlag(), drm.waitUserFenceParams[0].flags);
93+
EXPECT_EQ(osContext.fenceVal[0], drm.waitUserFenceParams[0].value);
94+
EXPECT_EQ(-1, drm.waitUserFenceParams[0].timeout);
95+
96+
drm.requirePerContextVM = false;
97+
osContext.waitForPagingFence();
98+
99+
EXPECT_EQ(castToUint64(&drm.pagingFence[0]), drm.waitUserFenceParams[1].address);
100+
EXPECT_EQ(drm.ioctlHelper->getWaitUserFenceSoftFlag(), drm.waitUserFenceParams[1].flags);
101+
EXPECT_EQ(drm.fenceVal[0], drm.waitUserFenceParams[1].value);
102+
}
103+
104+
TEST(OSContextLinux, givenPerContextVmsAndBindCompleteWhenWaitForPagingFenceThenWaitUserFenceIoctlIsNotCalled) {
105+
auto executionEnvironment = std::make_unique<MockExecutionEnvironment>();
106+
DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]};
107+
drm.requirePerContextVM = true;
108+
109+
MockOsContextLinux osContext(drm, 0, 0u, EngineDescriptorHelper::getDefaultDescriptor());
110+
osContext.ensureContextInitialized();
111+
112+
osContext.pagingFence[0] = 3u;
113+
osContext.fenceVal[0] = 3u;
114+
115+
osContext.waitForPagingFence();
116+
117+
EXPECT_EQ(0u, drm.waitUserFenceParams.size());
118+
}

0 commit comments

Comments
 (0)