L0Debug - add support for mirrored isa heaps

- allow tileInstanced ISA while debugging

Signed-off-by: Mateusz Hoppe <mateusz.hoppe@intel.com>
This commit is contained in:
Mateusz Hoppe
2022-09-14 09:23:40 +00:00
committed by Compute-Runtime-Automation
parent 643e21631c
commit 92893a5101
7 changed files with 639 additions and 41 deletions

View File

@@ -764,12 +764,15 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v
auto connection = clientHandleToConnection[vmBind->client_handle].get();
uint32_t index = 0;
const auto uuid = vmBind->uuids[index];
const auto tileIndex = tileSessionsEnabled ? connection->vmToTile[vmHandle] : 0;
if (connection->uuidMap.find(uuid) == connection->uuidMap.end()) {
PRINT_DEBUGGER_ERROR_LOG("Unknown UUID handle = %llu\n", (uint64_t)uuid);
return;
}
DEBUG_BREAK_IF(connection->vmToTile.find(vmHandle) == connection->vmToTile.end() && connection->uuidMap[uuid].classIndex == NEO::DrmResourceClass::Isa);
const auto tileIndex = connection->vmToTile[vmHandle];
PRINT_DEBUGGER_INFO_LOG("UUID handle = %llu class index = %d\n", (uint64_t)vmBind->uuids[index], (int)clientHandleToConnection[vmBind->client_handle]->uuidMap[vmBind->uuids[index]].classIndex);
auto classUuid = connection->uuidMap[uuid].classHandle;
@@ -794,7 +797,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v
}
}
bool handleEvent = isTileWithinDeviceBitfield(connection->vmToTile[vmBind->vm_handle]);
bool handleEvent = isTileWithinDeviceBitfield(tileIndex);
if (handleEvent && connection->uuidMap[uuid].classIndex == NEO::DrmResourceClass::Isa) {
PRINT_DEBUGGER_INFO_LOG("ISA vm_handle = %llu, tileIndex = %lu", (uint64_t)vmHandle, tileIndex);
@@ -803,6 +806,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v
bool perKernelModules = true;
int moduleUUIDindex = -1;
bool tileInstanced = false;
bool allInstancesEventsReceived = true;
for (uint32_t uuidIter = 1; uuidIter < vmBind->num_uuids; uuidIter++) {
if (connection->uuidMap[vmBind->uuids[uuidIter]].classIndex == NEO::DrmResourceClass::L0ZebinModule) {
@@ -820,6 +824,10 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v
auto &isaMap = connection->isaMap[tileIndex];
auto &elfMap = connection->elfMap;
uint32_t deviceBitfield = 0;
memcpy_s(&deviceBitfield, sizeof(uint32_t), connection->uuidMap[uuid].data.get(), connection->uuidMap[uuid].dataSize);
NEO::DeviceBitfield devices(deviceBitfield);
auto isa = std::make_unique<IsaAllocation>();
isa->bindInfo = {vmBind->va_start, vmBind->va_length};
isa->vmHandle = vmHandle;
@@ -828,6 +836,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v
isa->moduleEnd = 0;
isa->tileInstanced = tileInstanced;
isa->perKernelModule = perKernelModules;
isa->deviceBitfield = devices;
for (index = 1; index < vmBind->num_uuids; index++) {
if (connection->uuidMap[vmBind->uuids[index]].classIndex == NEO::DrmResourceClass::Elf) {
@@ -893,14 +902,20 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v
static_cast<TileDebugSessionLinux *>(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr);
}
} else {
pushApiEvent(debugEvent, nullptr);
if (devices.count() > 1) {
allInstancesEventsReceived = checkAllOtherTileIsaAllocationsPresent(tileIndex, vmBind->va_start);
}
if (allInstancesEventsReceived) {
pushApiEvent(debugEvent, nullptr);
}
}
}
}
if (createEvent) {
std::lock_guard<std::mutex> lock(asyncThreadMutex);
if (!connection->isaMap[tileIndex][vmBind->va_start]->moduleLoadEventAck && perKernelModules) {
if (allInstancesEventsReceived && !connection->isaMap[tileIndex][vmBind->va_start]->moduleLoadEventAck && perKernelModules) {
PRINT_DEBUGGER_INFO_LOG("Add event to ack, seqno = %llu", (uint64_t)vmBind->base.seqno);
connection->isaMap[tileIndex][vmBind->va_start]->ackEvents.push_back(vmBind->base);
shouldAckEvent = false;
@@ -931,7 +946,13 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v
static_cast<TileDebugSessionLinux *>(tileSessions[tileIndex].first)->removeModule(debugEvent.info.module);
static_cast<TileDebugSessionLinux *>(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr);
} else {
pushApiEvent(debugEvent, nullptr);
bool notifyEvent = true;
if (isa->deviceBitfield.count() > 1) {
notifyEvent = checkAllOtherTileIsaAllocationsRemoved(tileIndex, vmBind->va_start);
}
if (notifyEvent) {
pushApiEvent(debugEvent, nullptr);
}
}
}
std::unique_lock<std::mutex> memLock(asyncThreadMutex);
@@ -1319,6 +1340,55 @@ ze_result_t DebugSessionLinux::getISAVMHandle(uint32_t deviceIndex, const zet_de
return status;
}
bool DebugSessionLinux::getIsaInfoForAllInstances(NEO::DeviceBitfield deviceBitfield, const zet_debug_memory_space_desc_t *desc, size_t size, uint64_t vmHandles[], ze_result_t &status) {
auto gmmHelper = connectedDevice->getNEODevice()->getGmmHelper();
auto accessVA = gmmHelper->decanonize(desc->address);
status = ZE_RESULT_ERROR_UNINITIALIZED;
bool tileInstancedIsa = false;
bool invalidIsaRange = false;
uint32_t isaFound = 0;
for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) {
vmHandles[i] = invalidHandle;
if (deviceBitfield.test(i)) {
auto &isaMap = clientHandleToConnection[clientHandle]->isaMap[i];
if (isaMap.size() > 0) {
uint64_t baseVa;
uint64_t ceilVa;
for (const auto &isa : isaMap) {
baseVa = isa.second->bindInfo.gpuVa;
ceilVa = isa.second->bindInfo.gpuVa + isa.second->bindInfo.size;
if (accessVA >= baseVa && accessVA < ceilVa) {
isaFound++;
if (accessVA + size > ceilVa) {
invalidIsaRange = true;
} else {
vmHandles[i] = isa.second->vmHandle;
}
tileInstancedIsa = isa.second->tileInstanced;
break;
}
}
}
}
}
if (invalidIsaRange) {
status = ZE_RESULT_ERROR_INVALID_ARGUMENT;
} else if (isaFound > 0) {
if ((tileInstancedIsa && deviceBitfield.count() == isaFound) ||
!tileInstancedIsa) {
status = ZE_RESULT_SUCCESS;
}
}
return isaFound > 0;
}
void DebugSessionLinux::printContextVms() {
if (NEO::DebugManager.flags.DebuggerLogBitmask.get() & NEO::DebugVariables::DEBUGGER_LOG_BITMASK::LOG_INFO) {
PRINT_DEBUGGER_LOG(stdout, "\nINFO: Context - VM map: ", "");
@@ -1391,9 +1461,7 @@ ze_result_t DebugSessionLinux::readMemory(ze_device_thread_t thread, const zet_d
return status;
}
uint32_t deviceIndex = connectedDevice->getNEODevice()->isSubDevice() ? Math::log2(static_cast<uint32_t>(connectedDevice->getNEODevice()->getDeviceBitfield().to_ulong())) : 0;
bool isa = tryReadIsa(deviceIndex, desc, size, buffer, status);
bool isa = tryReadIsa(connectedDevice->getNEODevice()->getDeviceBitfield(), desc, size, buffer, status);
if (isa) {
return status;
}
@@ -1422,9 +1490,9 @@ ze_result_t DebugSessionLinux::writeMemory(ze_device_thread_t thread, const zet_
return status;
}
uint32_t deviceIndex = connectedDevice->getNEODevice()->isSubDevice() ? Math::log2(static_cast<uint32_t>(connectedDevice->getNEODevice()->getDeviceBitfield().to_ulong())) : 0;
auto deviceBitfield = connectedDevice->getNEODevice()->getDeviceBitfield();
bool isa = tryWriteIsa(deviceIndex, desc, size, buffer, status);
bool isa = tryWriteIsa(deviceBitfield, desc, size, buffer, status);
if (isa) {
return status;
}
@@ -1442,43 +1510,90 @@ ze_result_t DebugSessionLinux::writeMemory(ze_device_thread_t thread, const zet_
return writeGpuMemory(threadVmHandle, static_cast<const char *>(buffer), size, desc->address);
}
bool DebugSessionLinux::tryWriteIsa(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, const void *buffer, ze_result_t &status) {
return tryAccessIsa(deviceIndex, desc, size, const_cast<void *>(buffer), true, status);
bool DebugSessionLinux::tryWriteIsa(NEO::DeviceBitfield deviceBitfield, const zet_debug_memory_space_desc_t *desc, size_t size, const void *buffer, ze_result_t &status) {
return tryAccessIsa(deviceBitfield, desc, size, const_cast<void *>(buffer), true, status);
}
bool DebugSessionLinux::tryReadIsa(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, ze_result_t &status) {
return tryAccessIsa(deviceIndex, desc, size, buffer, false, status);
bool DebugSessionLinux::tryReadIsa(NEO::DeviceBitfield deviceBitfield, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, ze_result_t &status) {
return tryAccessIsa(deviceBitfield, desc, size, buffer, false, status);
}
bool DebugSessionLinux::tryAccessIsa(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, bool write, ze_result_t &status) {
bool DebugSessionLinux::tryAccessIsa(NEO::DeviceBitfield deviceBitfield, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, bool write, ze_result_t &status) {
status = ZE_RESULT_ERROR_NOT_AVAILABLE;
uint64_t vmHandle = invalidHandle;
uint64_t vmHandle[NEO::EngineLimits::maxHandleCount] = {invalidHandle};
uint32_t deviceIndex = Math::getMinLsbSet(static_cast<uint32_t>(deviceBitfield.to_ulong()));
bool isaAccess = false;
auto checkIfAnyFailed = [](const auto &result) { return result != ZE_RESULT_SUCCESS; };
{
std::lock_guard<std::mutex> memLock(asyncThreadMutex);
status = getISAVMHandle(deviceIndex, desc, size, vmHandle);
if (status == ZE_RESULT_SUCCESS) {
isaAccess = true;
} else if (status == ZE_RESULT_ERROR_INVALID_ARGUMENT) {
return true;
if (deviceBitfield.count() == 1) {
status = getISAVMHandle(deviceIndex, desc, size, vmHandle[deviceIndex]);
if (status == ZE_RESULT_SUCCESS) {
isaAccess = true;
}
if (status == ZE_RESULT_ERROR_INVALID_ARGUMENT) {
return true;
}
} else {
isaAccess = getIsaInfoForAllInstances(deviceBitfield, desc, size, vmHandle, status);
}
}
if (isaAccess) {
if (isaAccess && status == ZE_RESULT_SUCCESS) {
if (vmHandle != invalidHandle) {
if (write) {
status = writeGpuMemory(vmHandle, static_cast<char *>(buffer), size, desc->address);
if (write) {
if (deviceBitfield.count() == 1) {
if (vmHandle[deviceIndex] != invalidHandle) {
status = writeGpuMemory(vmHandle[deviceIndex], static_cast<char *>(buffer), size, desc->address);
} else {
status = ZE_RESULT_ERROR_UNINITIALIZED;
}
} else {
status = readGpuMemory(vmHandle, static_cast<char *>(buffer), size, desc->address);
std::vector<ze_result_t> results(NEO::EngineLimits::maxHandleCount);
for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) {
results[i] = ZE_RESULT_SUCCESS;
if (deviceBitfield.test(i) && vmHandle[i] != invalidHandle) {
results[i] = writeGpuMemory(vmHandle[i], static_cast<char *>(buffer), size, desc->address);
if (results[i] != ZE_RESULT_SUCCESS) {
break;
}
}
}
const bool anyFailed = std::any_of(results.begin(), results.end(), checkIfAnyFailed);
if (anyFailed) {
status = ZE_RESULT_ERROR_UNKNOWN;
}
}
} else {
status = ZE_RESULT_ERROR_UNINITIALIZED;
if (deviceBitfield.count() > 1) {
for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) {
if (vmHandle[i] != invalidHandle) {
deviceIndex = i;
break;
}
}
}
if (vmHandle[deviceIndex] != invalidHandle) {
status = readGpuMemory(vmHandle[deviceIndex], static_cast<char *>(buffer), size, desc->address);
} else {
status = ZE_RESULT_ERROR_UNINITIALIZED;
}
}
}
return isaAccess;
}
ze_result_t DebugSessionLinux::accessDefaultMemForThreadAll(const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, bool write) {
auto status = ZE_RESULT_ERROR_UNINITIALIZED;
std::vector<uint64_t> allVms;
@@ -1578,8 +1693,15 @@ ze_result_t DebugSessionLinux::acknowledgeEvent(const zet_debug_event_t *event)
}
if (apiEventToAck.type == ZET_DEBUG_EVENT_TYPE_MODULE_LOAD) {
if (ackIsaEvents(0, apiEventToAck.info.module.load)) {
bool allIsaAcked = true;
for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) {
if (connectedDevice->getNEODevice()->getDeviceBitfield().test(i)) {
if (!ackIsaEvents(i, apiEventToAck.info.module.load)) {
allIsaAcked = false;
}
}
}
if (allIsaAcked) {
return ZE_RESULT_SUCCESS;
}
}

View File

@@ -109,6 +109,7 @@ struct DebugSessionLinux : DebugSessionImp {
uint64_t vmHandle;
bool tileInstanced = false;
bool perKernelModule = true;
NEO::DeviceBitfield deviceBitfield;
uint64_t moduleBegin;
uint64_t moduleEnd;
@@ -251,14 +252,16 @@ struct DebugSessionLinux : DebugSessionImp {
ze_result_t readGpuMemory(uint64_t vmHandle, char *output, size_t size, uint64_t gpuVa) override;
ze_result_t writeGpuMemory(uint64_t vmHandle, const char *input, size_t size, uint64_t gpuVa) override;
ze_result_t getISAVMHandle(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, uint64_t &vmHandle);
bool getIsaInfoForAllInstances(NEO::DeviceBitfield deviceBitfield, const zet_debug_memory_space_desc_t *desc, size_t size, uint64_t vmHandles[], ze_result_t &status);
ze_result_t getElfOffset(const zet_debug_memory_space_desc_t *desc, size_t size, const char *&elfData, uint64_t &offset);
ze_result_t readElfSpace(const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer,
const char *&elfData, const uint64_t offset);
virtual bool tryReadElf(const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, ze_result_t &status);
bool tryWriteIsa(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, const void *buffer, ze_result_t &status);
bool tryReadIsa(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, ze_result_t &status);
virtual bool tryAccessIsa(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, bool write, ze_result_t &status);
bool tryWriteIsa(NEO::DeviceBitfield deviceBitfield, const zet_debug_memory_space_desc_t *desc, size_t size, const void *buffer, ze_result_t &status);
bool tryReadIsa(NEO::DeviceBitfield deviceBitfield, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, ze_result_t &status);
virtual bool tryAccessIsa(NEO::DeviceBitfield deviceBitfield, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, bool write, ze_result_t &status);
ze_result_t accessDefaultMemForThreadAll(const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, bool write);
MOCKABLE_VIRTUAL int threadControl(const std::vector<EuThread::ThreadId> &threads, uint32_t tile, ThreadControlCmd threadCmd, std::unique_ptr<uint8_t[]> &bitmask, size_t &bitmaskSize);
@@ -271,6 +274,32 @@ struct DebugSessionLinux : DebugSessionImp {
return connectedDevice->getNEODevice()->getDeviceBitfield().test(tileIndex);
}
bool checkAllOtherTileIsaAllocationsPresent(uint32_t tileIndex, uint64_t isaVa) {
bool allInstancesPresent = true;
for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) {
if (i != tileIndex && connectedDevice->getNEODevice()->getDeviceBitfield().test(i)) {
if (clientHandleToConnection[clientHandle]->isaMap[i].find(isaVa) == clientHandleToConnection[clientHandle]->isaMap[i].end()) {
allInstancesPresent = false;
break;
}
}
}
return allInstancesPresent;
}
bool checkAllOtherTileIsaAllocationsRemoved(uint32_t tileIndex, uint64_t isaVa) {
bool allInstancesRemoved = true;
for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) {
if (i != tileIndex && connectedDevice->getNEODevice()->getDeviceBitfield().test(i)) {
if (clientHandleToConnection[clientHandle]->isaMap[i].find(isaVa) != clientHandleToConnection[clientHandle]->isaMap[i].end()) {
allInstancesRemoved = false;
break;
}
}
}
return allInstancesRemoved;
}
ThreadHelper internalEventThread;
std::mutex internalEventThreadMutex;
std::condition_variable internalEventCondition;
@@ -337,8 +366,8 @@ struct TileDebugSessionLinux : DebugSessionLinux {
return rootDebugSession->tryReadElf(desc, size, buffer, status);
}
bool tryAccessIsa(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, bool write, ze_result_t &status) override {
return rootDebugSession->tryAccessIsa(deviceIndex, desc, size, buffer, write, status);
bool tryAccessIsa(NEO::DeviceBitfield deviceBitfield, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer, bool write, ze_result_t &status) override {
return rootDebugSession->tryAccessIsa(deviceBitfield, desc, size, buffer, write, status);
}
bool ackIsaEvents(uint32_t deviceIndex, uint64_t isaVa) override {

View File

@@ -261,6 +261,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux {
using L0::DebugSessionLinux::eventsToAck;
using L0::DebugSessionLinux::extractVaFromUuidString;
using L0::DebugSessionLinux::fd;
using L0::DebugSessionLinux::getIsaInfoForAllInstances;
using L0::DebugSessionLinux::getISAVMHandle;
using L0::DebugSessionLinux::getRegisterSetProperties;
using L0::DebugSessionLinux::getSbaBufferGpuVa;

View File

@@ -1491,7 +1491,6 @@ TEST_F(DebugApiLinuxTest, GivenCanonizedAddressWhenGettingIsaVmHandleThenCorrect
}
uint64_t vmHandle = 0;
auto retVal = session->getISAVMHandle(0, &desc, isaSize, vmHandle);
EXPECT_EQ(ZE_RESULT_SUCCESS, retVal);
EXPECT_EQ(3u, vmHandle);
@@ -6289,6 +6288,428 @@ TEST_F(DebugApiLinuxMultitileTest, givenApiThreadAndMultipleTilesWhenGettingDevi
EXPECT_EQ(1u, deviceIndex);
}
struct DebugApiLinuxMultiDeviceVmBindFixture : public DebugApiLinuxMultiDeviceFixture, public MockDebugSessionLinuxHelper {
void setUp() {
DebugApiLinuxMultiDeviceFixture::setUp();
zet_debug_config_t config = {};
config.pid = 0x1234;
session = std::make_unique<MockDebugSessionLinux>(config, deviceImp, 10);
ASSERT_NE(nullptr, session);
session->clientHandle = MockDebugSessionLinux::mockClientHandle;
handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
setupSessionClassHandlesAndUuidMap(session.get());
setupVmToTile(session.get());
}
void tearDown() {
DebugApiLinuxMultiDeviceFixture::tearDown();
}
MockIoctlHandler *handler = nullptr;
std::unique_ptr<MockDebugSessionLinux> session;
};
using DebugApiLinuxMultiDeviceVmBindTest = Test<DebugApiLinuxMultiDeviceVmBindFixture>;
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaWhenHandlingVmBindCreateEventsThenModuleLoadIsTriggeredAfterAllInstancesEventsReceived) {
auto handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
uint32_t devices = static_cast<uint32_t>(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong());
DebugSessionLinux::UuidData isaUuidData = {
.handle = isaUUID,
.classHandle = isaClassHandle,
.classIndex = NEO::DrmResourceClass::Isa,
.data = std::make_unique<char[]>(sizeof(devices)),
.dataSize = sizeof(devices)};
memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices));
session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData);
addIsaVmBindEvent(session.get(), vm0, true, true);
EXPECT_EQ(1u, session->clientHandleToConnection[session->clientHandle]->isaMap[0].size());
EXPECT_EQ(0u, session->clientHandleToConnection[session->clientHandle]->isaMap[1].size());
EXPECT_EQ(20u, handler->debugEventAcked.seqno);
EXPECT_EQ(0u, session->apiEvents.size());
addIsaVmBindEvent(session.get(), vm1, true, true);
EXPECT_EQ(1u, session->apiEvents.size());
zet_debug_event_t event;
auto result = session->readEvent(0, &event);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_MODULE_LOAD, event.type);
EXPECT_EQ(isaGpuVa, event.info.module.load);
}
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaWhenHandlingVmBindDestroyEventsThenModuleUnloadIsTriggeredAfterAllInstancesEventsReceived) {
auto handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
uint32_t devices = static_cast<uint32_t>(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong());
DebugSessionLinux::UuidData isaUuidData = {
.handle = isaUUID,
.classHandle = isaClassHandle,
.classIndex = NEO::DrmResourceClass::Isa,
.data = std::make_unique<char[]>(sizeof(devices)),
.dataSize = sizeof(devices)};
memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices));
session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData);
addIsaVmBindEvent(session.get(), vm0, false, true);
addIsaVmBindEvent(session.get(), vm1, false, true);
EXPECT_EQ(1u, session->clientHandleToConnection[session->clientHandle]->isaMap[0].size());
EXPECT_EQ(1u, session->clientHandleToConnection[session->clientHandle]->isaMap[1].size());
auto numberOfEvents = session->apiEvents.size();
addIsaVmBindEvent(session.get(), vm0, false, false);
EXPECT_EQ(numberOfEvents, session->apiEvents.size());
addIsaVmBindEvent(session.get(), vm1, false, false);
auto numberOfAllEvents = session->apiEvents.size();
EXPECT_EQ(numberOfEvents + 1, numberOfAllEvents);
zet_debug_event_t event;
ze_result_t result = ZE_RESULT_SUCCESS;
while (numberOfAllEvents--) {
result = session->readEvent(0, &event);
if (result != ZE_RESULT_SUCCESS) {
break;
}
}
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_MODULE_UNLOAD, event.type);
EXPECT_EQ(isaGpuVa, event.info.module.load);
}
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaWhenWritingAndReadingIsaMemoryThenOnlyWritesAreMirrored) {
auto handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
uint32_t devices = static_cast<uint32_t>(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong());
DebugSessionLinux::UuidData isaUuidData = {
.handle = isaUUID,
.classHandle = isaClassHandle,
.classIndex = NEO::DrmResourceClass::Isa,
.data = std::make_unique<char[]>(sizeof(devices)),
.dataSize = sizeof(devices)};
memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices));
session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData);
addIsaVmBindEvent(session.get(), vm0, false, true);
addIsaVmBindEvent(session.get(), vm1, false, true);
EXPECT_EQ(1u, session->clientHandleToConnection[session->clientHandle]->isaMap[0].size());
EXPECT_EQ(1u, session->clientHandleToConnection[session->clientHandle]->isaMap[1].size());
ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
zet_debug_memory_space_desc_t desc;
desc.address = isaGpuVa;
desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT;
uint8_t buffer[16];
handler->pwriteRetVal = 16;
auto result = session->writeMemory(thread, &desc, 16, buffer);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(2, handler->pwriteCalled);
handler->preadRetVal = 16;
result = session->readMemory(thread, &desc, 16, buffer);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(1, handler->preadCalled);
}
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaWhenWritingMemoryFailsThenErrorIsReturned) {
auto handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
uint32_t devices = static_cast<uint32_t>(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong());
DebugSessionLinux::UuidData isaUuidData = {
.handle = isaUUID,
.classHandle = isaClassHandle,
.classIndex = NEO::DrmResourceClass::Isa,
.data = std::make_unique<char[]>(sizeof(devices)),
.dataSize = sizeof(devices)};
memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices));
session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData);
addIsaVmBindEvent(session.get(), vm0, false, true);
addIsaVmBindEvent(session.get(), vm1, false, true);
ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
zet_debug_memory_space_desc_t desc;
desc.address = isaGpuVa;
desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT;
uint8_t buffer[16];
handler->pwriteRetVal = -1;
auto result = session->writeMemory(thread, &desc, 16, buffer);
EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, result);
EXPECT_EQ(1, handler->pwriteCalled);
}
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenSingleIsaWithInvalidVmWhenReadingIsaMemoryThenErrorUninitializedIsReturned) {
auto handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
uint32_t devices = static_cast<uint32_t>(neoDevice->getDeviceBitfield().to_ulong());
DebugSessionLinux::UuidData isaUuidData = {
.handle = isaUUID,
.classHandle = isaClassHandle,
.classIndex = NEO::DrmResourceClass::Isa,
.data = std::make_unique<char[]>(sizeof(devices)),
.dataSize = sizeof(devices)};
memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices));
session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData);
uint64_t vmBindIsaData[sizeof(prelim_drm_i915_debug_event_vm_bind) / sizeof(uint64_t) + 3 * sizeof(typeOfUUID)];
prelim_drm_i915_debug_event_vm_bind *vmBindIsa = reinterpret_cast<prelim_drm_i915_debug_event_vm_bind *>(&vmBindIsaData);
vmBindIsa->base.type = PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND;
vmBindIsa->base.flags = PRELIM_DRM_I915_DEBUG_EVENT_CREATE;
vmBindIsa->base.flags |= PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK;
vmBindIsa->base.size = sizeof(prelim_drm_i915_debug_event_vm_bind) + 3 * sizeof(typeOfUUID);
vmBindIsa->base.seqno = 20u;
vmBindIsa->client_handle = MockDebugSessionLinux::mockClientHandle;
vmBindIsa->va_start = isaGpuVa;
vmBindIsa->va_length = isaSize;
vmBindIsa->vm_handle = MockDebugSessionLinux::invalidHandle;
vmBindIsa->num_uuids = 2;
auto *uuids = reinterpret_cast<typeOfUUID *>(ptrOffset(vmBindIsaData, sizeof(prelim_drm_i915_debug_event_vm_bind)));
typeOfUUID uuidsTemp[2];
uuidsTemp[0] = static_cast<typeOfUUID>(isaUUID);
uuidsTemp[1] = static_cast<typeOfUUID>(elfUUID);
memcpy(uuids, uuidsTemp, sizeof(uuidsTemp));
session->handleEvent(&vmBindIsa->base);
ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
zet_debug_memory_space_desc_t desc;
desc.address = isaGpuVa;
desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT;
uint8_t buffer[16];
handler->preadRetVal = 16;
auto result = session->readMemory(thread, &desc, 16, buffer);
EXPECT_EQ(ZE_RESULT_ERROR_UNINITIALIZED, result);
EXPECT_EQ(0, handler->preadCalled);
}
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaAndSingleInstanceWhenGettingIsaInfoThenIsaTrueAndErrorUninitializedIsReturned) {
auto handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
uint32_t devices = static_cast<uint32_t>(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong());
DebugSessionLinux::UuidData isaUuidData = {
.handle = isaUUID,
.classHandle = isaClassHandle,
.classIndex = NEO::DrmResourceClass::Isa,
.data = std::make_unique<char[]>(sizeof(devices)),
.dataSize = sizeof(devices)};
memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices));
session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData);
addIsaVmBindEvent(session.get(), vm1, false, true);
EXPECT_EQ(1u, session->clientHandleToConnection[session->clientHandle]->isaMap[1].size());
zet_debug_memory_space_desc_t desc;
desc.address = isaGpuVa;
desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT;
uint64_t vm[4];
ze_result_t status = ZE_RESULT_SUCCESS;
auto isIsa = session->getIsaInfoForAllInstances(devices, &desc, 16, vm, status);
EXPECT_TRUE(isIsa);
EXPECT_EQ(ZE_RESULT_ERROR_UNINITIALIZED, status);
}
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenNoIsaWhenGettingIsaInfoThenFalseReturned) {
uint32_t devices = static_cast<uint32_t>(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong());
zet_debug_memory_space_desc_t desc;
desc.address = isaGpuVa;
desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT;
uint64_t vm[4];
ze_result_t status = ZE_RESULT_SUCCESS;
auto isIsa = session->getIsaInfoForAllInstances(devices, &desc, 16, vm, status);
EXPECT_FALSE(isIsa);
EXPECT_EQ(ZE_RESULT_ERROR_UNINITIALIZED, status);
}
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenIsaWhenGettingIsaInfoForWrongAddressThenErrorUninitializedReturned) {
auto handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
uint32_t devices = static_cast<uint32_t>(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong());
DebugSessionLinux::UuidData isaUuidData = {
.handle = isaUUID,
.classHandle = isaClassHandle,
.classIndex = NEO::DrmResourceClass::Isa,
.data = std::make_unique<char[]>(sizeof(devices)),
.dataSize = sizeof(devices)};
memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices));
session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData);
addIsaVmBindEvent(session.get(), vm0, false, true);
EXPECT_EQ(1u, session->clientHandleToConnection[session->clientHandle]->isaMap[0].size());
uint64_t vm[4];
ze_result_t status = ZE_RESULT_SUCCESS;
zet_debug_memory_space_desc_t desc;
desc.address = isaGpuVa - 0x1000;
desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT;
auto isIsa = session->getIsaInfoForAllInstances(devices, &desc, 16, vm, status);
EXPECT_FALSE(isIsa);
EXPECT_EQ(ZE_RESULT_ERROR_UNINITIALIZED, status);
desc.address = isaGpuVa + isaSize + 0x1000;
isIsa = session->getIsaInfoForAllInstances(devices, &desc, 16, vm, status);
EXPECT_FALSE(isIsa);
EXPECT_EQ(ZE_RESULT_ERROR_UNINITIALIZED, status);
}
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaWhenWritingAndReadingWrongIsaRangeThenErrorInvalidArgReturned) {
auto handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
uint32_t devices = static_cast<uint32_t>(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong());
DebugSessionLinux::UuidData isaUuidData = {
.handle = isaUUID,
.classHandle = isaClassHandle,
.classIndex = NEO::DrmResourceClass::Isa,
.data = std::make_unique<char[]>(sizeof(devices)),
.dataSize = sizeof(devices)};
memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices));
session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData);
addIsaVmBindEvent(session.get(), vm0, false, true);
EXPECT_EQ(1u, session->clientHandleToConnection[session->clientHandle]->isaMap[0].size());
ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
zet_debug_memory_space_desc_t desc;
desc.address = isaGpuVa;
desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT;
uint8_t buffer[16];
auto result = session->writeMemory(thread, &desc, isaSize * 2, buffer);
EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, result);
EXPECT_EQ(0, handler->pwriteCalled);
result = session->readMemory(thread, &desc, isaSize * 2, buffer);
EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, result);
EXPECT_EQ(0, handler->preadCalled);
}
TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenSingleMemoryIsaWhenWritingAndReadingThenOnlyOneInstanceIsWrittenAndRead) {
auto handler = new MockIoctlHandler;
session->ioctlHandler.reset(handler);
uint32_t devices = static_cast<uint32_t>(neoDevice->getSubDevice(1)->getDeviceBitfield().to_ulong());
EXPECT_EQ(1u, neoDevice->getSubDevice(1)->getDeviceBitfield().count());
DebugSessionLinux::UuidData isaUuidData = {
.handle = isaUUID,
.classHandle = isaClassHandle,
.classIndex = NEO::DrmResourceClass::Isa,
.data = std::make_unique<char[]>(sizeof(devices)),
.dataSize = sizeof(devices)};
memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices));
session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData);
uint64_t vmBindIsaData[sizeof(prelim_drm_i915_debug_event_vm_bind) / sizeof(uint64_t) + 3 * sizeof(typeOfUUID)];
prelim_drm_i915_debug_event_vm_bind *vmBindIsa = reinterpret_cast<prelim_drm_i915_debug_event_vm_bind *>(&vmBindIsaData);
vmBindIsa->base.type = PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND;
vmBindIsa->base.flags = PRELIM_DRM_I915_DEBUG_EVENT_CREATE;
vmBindIsa->base.flags |= PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK;
vmBindIsa->base.size = sizeof(prelim_drm_i915_debug_event_vm_bind) + 3 * sizeof(typeOfUUID);
vmBindIsa->base.seqno = 20u;
vmBindIsa->client_handle = MockDebugSessionLinux::mockClientHandle;
vmBindIsa->va_start = isaGpuVa;
vmBindIsa->va_length = isaSize;
vmBindIsa->vm_handle = vm1;
vmBindIsa->num_uuids = 2;
auto *uuids = reinterpret_cast<typeOfUUID *>(ptrOffset(vmBindIsaData, sizeof(prelim_drm_i915_debug_event_vm_bind)));
typeOfUUID uuidsTemp[2];
uuidsTemp[0] = static_cast<typeOfUUID>(isaUUID);
uuidsTemp[1] = static_cast<typeOfUUID>(elfUUID);
memcpy(uuids, uuidsTemp, sizeof(uuidsTemp));
session->handleEvent(&vmBindIsa->base);
EXPECT_EQ(1u, session->clientHandleToConnection[session->clientHandle]->isaMap[1].size());
ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
zet_debug_memory_space_desc_t desc;
desc.address = isaGpuVa;
desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT;
uint8_t buffer[16];
handler->pwriteRetVal = 16;
auto result = session->writeMemory(thread, &desc, 16, buffer);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(1, handler->pwriteCalled);
handler->preadRetVal = 16;
result = session->readMemory(thread, &desc, 16, buffer);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(1, handler->preadCalled);
}
struct AffinityMaskMultipleSubdevices : DebugApiLinuxMultiDeviceFixture {
void setUp() {
DebugManager.flags.ZE_AFFINITY_MASK.set("0.0,0.1,0.3");

View File

@@ -47,10 +47,6 @@ StorageInfo MemoryManager::createStorageInfoFromProperties(const AllocationPrope
case AllocationType::DEBUG_MODULE_AREA: {
auto placeIsaOnMultiTile = (properties.subDevicesBitfield.count() != 1);
if (executionEnvironment.isDebuggingEnabled() && !DebugManager.flags.ExperimentalEnableTileAttach.get()) {
placeIsaOnMultiTile = false;
}
if (DebugManager.flags.MultiTileIsaPlacement.get() != -1) {
placeIsaOnMultiTile = !!DebugManager.flags.MultiTileIsaPlacement.get();
}

View File

@@ -196,8 +196,14 @@ void DrmAllocation::registerBOBindExtHandle(Drm *drm) {
}
if (resourceClass != DrmResourceClass::MaxSize) {
uint64_t gpuAddress = getGpuAddress();
auto handle = drm->registerResource(resourceClass, &gpuAddress, sizeof(gpuAddress));
auto handle = 0;
if (resourceClass == DrmResourceClass::Isa) {
auto deviceBitfiled = static_cast<uint32_t>(this->storageInfo.subDeviceBitfield.to_ulong());
handle = drm->registerResource(resourceClass, &deviceBitfiled, sizeof(deviceBitfiled));
} else {
uint64_t gpuAddress = getGpuAddress();
handle = drm->registerResource(resourceClass, &gpuAddress, sizeof(gpuAddress));
}
registeredBoBindHandles.push_back(handle);
auto &bos = getBOs();

View File

@@ -3533,6 +3533,29 @@ TEST_F(DrmAllocationTests, givenResourceRegistrationEnabledAndSingleInstanceIsaW
EXPECT_EQ(1u, drm.unregisterCalledCount);
}
TEST_F(DrmAllocationTests, givenResourceRegistrationEnabledWhenIsaIsRegisteredThenDeviceBitfieldIsPassedAsPayload) {
DrmMockResources drm(*executionEnvironment->rootDeviceEnvironments[0]);
for (uint32_t i = 3; i < 3 + static_cast<uint32_t>(DrmResourceClass::MaxSize); i++) {
drm.classHandles.push_back(i);
}
drm.registeredClass = DrmResourceClass::MaxSize;
MockBufferObject bo(&drm, 3, 0, 0, 1);
MockDrmAllocation allocation(AllocationType::KERNEL_ISA, MemoryPool::LocalMemory);
allocation.storageInfo.subDeviceBitfield = 1 << 3;
allocation.bufferObjects[0] = &bo;
allocation.registerBOBindExtHandle(&drm);
EXPECT_EQ(1u, bo.bindExtHandles.size());
EXPECT_EQ(DrmMockResources::registerResourceReturnHandle, bo.bindExtHandles[0]);
EXPECT_EQ(sizeof(uint32_t), drm.registeredDataSize);
uint32_t *data = reinterpret_cast<uint32_t *>(drm.registeredData);
EXPECT_EQ(static_cast<uint32_t>(allocation.storageInfo.subDeviceBitfield.to_ulong()), *data);
}
TEST_F(DrmAllocationTests, givenDrmAllocationWhenSetCacheRegionIsCalledForDefaultRegionThenReturnTrue) {
DrmMock drm(*executionEnvironment->rootDeviceEnvironments[0]);