fix(zebin): register zebin's debug elf only once

- minimize memory use
- enhance performance of debug

Resolves: NEO-7585


Signed-off-by: Mateusz Hoppe <mateusz.hoppe@intel.com>
This commit is contained in:
Mateusz Hoppe 2022-12-23 13:38:21 +00:00 committed by Compute-Runtime-Automation
parent 3dfd0aa25a
commit c52f966fdf
11 changed files with 171 additions and 32 deletions

View File

@ -1287,10 +1287,10 @@ void ModuleImp::registerElfInDebuggerL0() {
NEO::DebugData debugData; // pass debug zebin in vIsa field
debugData.vIsa = reinterpret_cast<const char *>(translationUnit->debugData.get());
debugData.vIsaSize = static_cast<uint32_t>(translationUnit->debugDataSize);
this->debugElfHandle = debuggerL0->registerElf(&debugData);
StackVec<NEO::GraphicsAllocation *, 32> segmentAllocs;
for (auto &kernImmData : kernelImmDatas) {
debuggerL0->registerElf(&debugData, kernImmData->getIsaGraphicsAllocation());
segmentAllocs.push_back(kernImmData->getIsaGraphicsAllocation());
}
@ -1301,7 +1301,7 @@ void ModuleImp::registerElfInDebuggerL0() {
segmentAllocs.push_back(translationUnit->globalConstBuffer);
}
debuggerL0->attachZebinModuleToSegmentAllocations(segmentAllocs, debugModuleHandle);
debuggerL0->attachZebinModuleToSegmentAllocations(segmentAllocs, this->debugModuleHandle, this->debugElfHandle);
} else {
for (auto &kernImmData : kernelImmDatas) {
if (kernImmData->getKernelInfo()->kernelDescriptor.external.debugData.get()) {
@ -1316,7 +1316,7 @@ void ModuleImp::registerElfInDebuggerL0() {
notifyDebugData = &relocatedDebugData;
}
debuggerL0->registerElf(notifyDebugData, kernImmData->getIsaGraphicsAllocation());
debuggerL0->registerElfAndLinkWithAllocation(notifyDebugData, kernImmData->getIsaGraphicsAllocation());
}
}
}

View File

@ -182,6 +182,7 @@ struct ModuleImp : public Module {
NEO::Linker::UnresolvedExternals unresolvedExternalsInfo{};
std::set<NEO::GraphicsAllocation *> importedSymbolAllocations{};
uint32_t debugModuleHandle = 0;
uint32_t debugElfHandle = 0;
uint32_t profileFlags = 0;
uint64_t moduleLoadAddress = std::numeric_limits<uint64_t>::max();

View File

@ -176,14 +176,14 @@ TEST(L0DebuggerLinux, givenPerContextVmNotEnabledWhenInitializingDebuggingInOsTh
EXPECT_FALSE(drmMock->registerClassesCalled);
}
TEST_F(L0DebuggerLinuxTest, whenRegisterElfisCalledThenItRegistersBindExtHandles) {
TEST_F(L0DebuggerLinuxTest, whenRegisterElfAndLinkWithAllocationIsCalledThenItRegistersBindExtHandles) {
NEO::DebugData debugData;
debugData.vIsa = "01234567890";
debugData.vIsaSize = 10;
MockDrmAllocation isaAllocation(AllocationType::KERNEL_ISA, MemoryPool::System4KBPages);
MockBufferObject bo(drmMock, 3, 0, 0, 1);
isaAllocation.bufferObjects[0] = &bo;
device->getL0Debugger()->registerElf(&debugData, &isaAllocation);
device->getL0Debugger()->registerElfAndLinkWithAllocation(&debugData, &isaAllocation);
EXPECT_EQ(static_cast<size_t>(10), drmMock->registeredDataSize);
@ -196,31 +196,38 @@ TEST_F(L0DebuggerLinuxTest, whenRegisterElfisCalledThenItRegistersBindExtHandles
}
}
TEST_F(L0DebuggerLinuxTest, whenRegisterElfisCalledInAllocationWithNoBOThenItRegistersBindExtHandles) {
TEST_F(L0DebuggerLinuxTest, whenRegisterElfAndLinkWithAllocationIsCalledInAllocationWithNoBOThenItRegistersBindExtHandles) {
NEO::DebugData debugData;
debugData.vIsa = "01234567890";
debugData.vIsaSize = 10;
MockDrmAllocation isaAllocation(AllocationType::KERNEL_ISA, MemoryPool::System4KBPages);
device->getL0Debugger()->registerElf(&debugData, &isaAllocation);
device->getL0Debugger()->registerElfAndLinkWithAllocation(&debugData, &isaAllocation);
EXPECT_EQ(static_cast<size_t>(10u), drmMock->registeredDataSize);
}
TEST_F(L0DebuggerLinuxTest, givenNoOSInterfaceThenRegisterElfDoesNothing) {
NEO::OSInterface *osInterfaceTmp = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.release();
HWTEST_F(L0DebuggerLinuxTest, givenFailureToRegisterElfWhenRegisterElfAndLinkWithAllocationIsCalledThenBindExtHandleIsNotAdded) {
NEO::DebugData debugData;
debugData.vIsa = "01234567890";
debugData.vIsaSize = 10;
drmMock->registeredDataSize = 0;
MockDrmAllocation isaAllocation(AllocationType::KERNEL_ISA, MemoryPool::System4KBPages);
MockBufferObject bo(drmMock, 3, 0, 0, 1);
isaAllocation.bufferObjects[0] = &bo;
device->getL0Debugger()->registerElf(&debugData, &isaAllocation);
auto debuggerL0Hw = static_cast<MockDebuggerL0Hw<FamilyType> *>(device->getL0Debugger());
debuggerL0Hw->elfHandleToReturn = 0;
device->getL0Debugger()->registerElfAndLinkWithAllocation(&debugData, &isaAllocation);
EXPECT_EQ(static_cast<size_t>(0u), drmMock->registeredDataSize);
neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(osInterfaceTmp);
auto &bos = isaAllocation.getBOs();
for (auto bo : bos) {
if (bo) {
auto extBindHandles = bo->getBindExtHandles();
EXPECT_EQ(static_cast<size_t>(0), extBindHandles.size());
}
}
}
TEST_F(L0DebuggerLinuxTest, givenAllocationsWhenAttachingZebinModuleThenAllAllocationsHaveRegisteredHandle) {
TEST_F(L0DebuggerLinuxTest, givenAllocationsWhenAttachingZebinModuleThenAllAllocationsHaveRegisteredHandles) {
MockDrmAllocation isaAllocation(AllocationType::KERNEL_ISA, MemoryPool::System4KBPages);
MockBufferObject bo(drmMock, 3, 0, 0, 1);
isaAllocation.bufferObjects[0] = &bo;
@ -230,6 +237,7 @@ TEST_F(L0DebuggerLinuxTest, givenAllocationsWhenAttachingZebinModuleThenAllAlloc
isaAllocation2.bufferObjects[0] = &bo2;
uint32_t handle = 0;
const uint32_t elfHandle = 198;
StackVec<NEO::GraphicsAllocation *, 32> kernelAllocs;
kernelAllocs.push_back(&isaAllocation);
@ -238,7 +246,7 @@ TEST_F(L0DebuggerLinuxTest, givenAllocationsWhenAttachingZebinModuleThenAllAlloc
drmMock->registeredDataSize = 0;
drmMock->registeredClass = NEO::DrmResourceClass::MaxSize;
EXPECT_TRUE(device->getL0Debugger()->attachZebinModuleToSegmentAllocations(kernelAllocs, handle));
EXPECT_TRUE(device->getL0Debugger()->attachZebinModuleToSegmentAllocations(kernelAllocs, handle, elfHandle));
EXPECT_EQ(sizeof(uint32_t), drmMock->registeredDataSize);
EXPECT_EQ(NEO::DrmResourceClass::L0ZebinModule, drmMock->registeredClass);
@ -248,8 +256,15 @@ TEST_F(L0DebuggerLinuxTest, givenAllocationsWhenAttachingZebinModuleThenAllAlloc
return std::find(bindExtHandles.begin(), bindExtHandles.end(), handle) != bindExtHandles.end();
};
const auto containsElfHandle = [elfHandle](const auto &bufferObject) {
const auto &bindExtHandles = bufferObject.getBindExtHandles();
return std::find(bindExtHandles.begin(), bindExtHandles.end(), elfHandle) != bindExtHandles.end();
};
EXPECT_TRUE(containsModuleHandle(bo));
EXPECT_TRUE(containsModuleHandle(bo2));
EXPECT_TRUE(containsElfHandle(bo));
EXPECT_TRUE(containsElfHandle(bo2));
}
TEST_F(L0DebuggerLinuxTest, givenModuleHandleWhenRemoveZebinModuleIsCalledThenHandleIsUnregistered) {

View File

@ -511,7 +511,7 @@ HWTEST_F(ModuleWithDebuggerL0Test, GivenDebugDataWithRelocationsWhenInitializing
EXPECT_EQ(0u, getMockDebuggerL0Hw<FamilyType>()->registerElfCount);
EXPECT_EQ(moduleMock->initialize(&moduleDesc, neoDevice), ZE_RESULT_SUCCESS);
EXPECT_EQ(1u, getMockDebuggerL0Hw<FamilyType>()->registerElfCount);
EXPECT_EQ(1u, getMockDebuggerL0Hw<FamilyType>()->registerElfAndLinkCount);
EXPECT_EQ(1u, getMockDebuggerL0Hw<FamilyType>()->notifyModuleCreateCount);
EXPECT_NE(nullptr, kernelInfo->kernelDescriptor.external.relocatedDebugData.get());
@ -562,7 +562,7 @@ HWTEST_F(ModuleWithDebuggerL0Test, GivenDebugDataWithoutRelocationsWhenInitializ
EXPECT_EQ(0u, getMockDebuggerL0Hw<FamilyType>()->registerElfCount);
EXPECT_EQ(moduleMock->initialize(&moduleDesc, neoDevice), ZE_RESULT_SUCCESS);
EXPECT_EQ(1u, getMockDebuggerL0Hw<FamilyType>()->registerElfCount);
EXPECT_EQ(1u, getMockDebuggerL0Hw<FamilyType>()->registerElfAndLinkCount);
EXPECT_EQ(1u, getMockDebuggerL0Hw<FamilyType>()->notifyModuleCreateCount);
EXPECT_EQ(nullptr, kernelInfo->kernelDescriptor.external.relocatedDebugData.get());
@ -639,7 +639,7 @@ HWTEST_F(ModuleWithZebinAndL0DebuggerTest, GivenZebinDebugDataWhenInitializingMo
zebin.storage.data(), zebin.storage.size());
EXPECT_EQ(0u, getMockDebuggerL0Hw<FamilyType>()->registerElfCount);
EXPECT_EQ(moduleMock->initialize(&moduleDesc, neoDevice), ZE_RESULT_SUCCESS);
EXPECT_EQ(2u, getMockDebuggerL0Hw<FamilyType>()->registerElfCount);
EXPECT_EQ(1u, getMockDebuggerL0Hw<FamilyType>()->registerElfCount);
EXPECT_EQ(1u, getMockDebuggerL0Hw<FamilyType>()->notifyModuleCreateCount);
}

View File

@ -90,7 +90,8 @@ class DebuggerL0 : public NEO::Debugger, NEO::NonCopyableOrMovableClass {
}
void printTrackedAddresses(uint32_t contextId);
MOCKABLE_VIRTUAL void registerElf(NEO::DebugData *debugData, NEO::GraphicsAllocation *isaAllocation);
MOCKABLE_VIRTUAL void registerElfAndLinkWithAllocation(NEO::DebugData *debugData, NEO::GraphicsAllocation *isaAllocation);
MOCKABLE_VIRTUAL uint32_t registerElf(NEO::DebugData *debugData);
MOCKABLE_VIRTUAL void notifyCommandQueueCreated(NEO::Device *device);
MOCKABLE_VIRTUAL void notifyCommandQueueDestroyed(NEO::Device *device);
MOCKABLE_VIRTUAL void notifyModuleLoadAllocations(Device *device, const StackVec<NEO::GraphicsAllocation *, 32> &allocs);
@ -102,7 +103,7 @@ class DebuggerL0 : public NEO::Debugger, NEO::NonCopyableOrMovableClass {
virtual size_t getSbaAddressLoadCommandsSize() = 0;
virtual void programSbaAddressLoad(NEO::LinearStream &cmdStream, uint64_t sbaGpuVa) = 0;
MOCKABLE_VIRTUAL bool attachZebinModuleToSegmentAllocations(const StackVec<NEO::GraphicsAllocation *, 32> &kernelAlloc, uint32_t &moduleHandle);
MOCKABLE_VIRTUAL bool attachZebinModuleToSegmentAllocations(const StackVec<NEO::GraphicsAllocation *, 32> &kernelAlloc, uint32_t &moduleHandle, uint32_t elfHandle);
MOCKABLE_VIRTUAL bool removeZebinModule(uint32_t moduleHandle);
void setSingleAddressSpaceSbaTracking(bool value) {

View File

@ -32,15 +32,23 @@ void DebuggerL0::initSbaTrackingMode() {
void DebuggerL0::registerAllocationType(GraphicsAllocation *allocation) {}
void DebuggerL0::registerElf(NEO::DebugData *debugData, NEO::GraphicsAllocation *isaAllocation) {
if (device->getRootDeviceEnvironment().osInterface.get() != nullptr) {
auto drm = device->getRootDeviceEnvironment().osInterface->getDriverModel()->as<NEO::Drm>();
auto handle = drm->registerResource(NEO::DrmResourceClass::Elf, debugData->vIsa, debugData->vIsaSize);
void DebuggerL0::registerElfAndLinkWithAllocation(NEO::DebugData *debugData, NEO::GraphicsAllocation *isaAllocation) {
auto handle = registerElf(debugData);
if (handle != 0) {
static_cast<NEO::DrmAllocation *>(isaAllocation)->linkWithRegisteredHandle(handle);
}
}
bool DebuggerL0::attachZebinModuleToSegmentAllocations(const StackVec<NEO::GraphicsAllocation *, 32> &allocs, uint32_t &moduleHandle) {
uint32_t DebuggerL0::registerElf(NEO::DebugData *debugData) {
uint32_t handle = 0;
if (device->getRootDeviceEnvironment().osInterface.get() != nullptr) {
auto drm = device->getRootDeviceEnvironment().osInterface->getDriverModel()->as<NEO::Drm>();
handle = drm->registerResource(NEO::DrmResourceClass::Elf, debugData->vIsa, debugData->vIsaSize);
}
return handle;
}
bool DebuggerL0::attachZebinModuleToSegmentAllocations(const StackVec<NEO::GraphicsAllocation *, 32> &allocs, uint32_t &moduleHandle, uint32_t elfHandle) {
if (device->getRootDeviceEnvironment().osInterface == nullptr) {
return false;
}
@ -50,6 +58,7 @@ bool DebuggerL0::attachZebinModuleToSegmentAllocations(const StackVec<NEO::Graph
for (auto &allocation : allocs) {
auto drmAllocation = static_cast<NEO::DrmAllocation *>(allocation);
drmAllocation->linkWithRegisteredHandle(elfHandle);
drmAllocation->linkWithRegisteredHandle(moduleHandle);
}

View File

@ -98,10 +98,14 @@ void DebuggerL0::registerAllocationType(GraphicsAllocation *allocation) {
DEBUG_BREAK_IF(STATUS_SUCCESS != status);
}
void DebuggerL0::registerElf(NEO::DebugData *debugData, NEO::GraphicsAllocation *allocation) {
void DebuggerL0::registerElfAndLinkWithAllocation(NEO::DebugData *debugData, NEO::GraphicsAllocation *allocation) {
}
bool DebuggerL0::attachZebinModuleToSegmentAllocations(const StackVec<NEO::GraphicsAllocation *, 32> &kernelAllocs, uint32_t &moduleHandle) {
uint32_t DebuggerL0::registerElf(NEO::DebugData *debugData) {
return 0;
}
bool DebuggerL0::attachZebinModuleToSegmentAllocations(const StackVec<NEO::GraphicsAllocation *, 32> &kernelAllocs, uint32_t &moduleHandle, uint32_t elfHandle) {
return false;
}

View File

@ -55,19 +55,28 @@ class MockDebuggerL0Hw : public NEO::DebuggerL0Hw<GfxFamily> {
return NEO::DebuggerL0Hw<GfxFamily>::getSbaTrackingCommandsSize(trackedAddressCount);
}
void registerElf(NEO::DebugData *debugData, NEO::GraphicsAllocation *isaAllocation) override {
registerElfCount++;
void registerElfAndLinkWithAllocation(NEO::DebugData *debugData, NEO::GraphicsAllocation *isaAllocation) override {
registerElfAndLinkCount++;
lastReceivedElf = debugData->vIsa;
NEO::DebuggerL0Hw<GfxFamily>::registerElf(debugData, isaAllocation);
NEO::DebuggerL0Hw<GfxFamily>::registerElfAndLinkWithAllocation(debugData, isaAllocation);
}
bool attachZebinModuleToSegmentAllocations(const StackVec<NEO::GraphicsAllocation *, 32> &allocs, uint32_t &moduleHandle) override {
uint32_t registerElf(NEO::DebugData *debugData) override {
if (elfHandleToReturn != std::numeric_limits<uint32_t>::max()) {
return elfHandleToReturn;
}
registerElfCount++;
lastReceivedElf = debugData->vIsa;
return NEO::DebuggerL0Hw<GfxFamily>::registerElf(debugData);
}
bool attachZebinModuleToSegmentAllocations(const StackVec<NEO::GraphicsAllocation *, 32> &allocs, uint32_t &moduleHandle, uint32_t elfHandle) override {
segmentCountWithAttachedModuleHandle = static_cast<uint32_t>(allocs.size());
if (std::numeric_limits<uint32_t>::max() != moduleHandleToReturn) {
moduleHandle = moduleHandleToReturn;
return true;
}
return NEO::DebuggerL0Hw<GfxFamily>::attachZebinModuleToSegmentAllocations(allocs, moduleHandle);
return NEO::DebuggerL0Hw<GfxFamily>::attachZebinModuleToSegmentAllocations(allocs, moduleHandle, elfHandle);
}
bool removeZebinModule(uint32_t moduleHandle) override {
@ -108,6 +117,7 @@ class MockDebuggerL0Hw : public NEO::DebuggerL0Hw<GfxFamily> {
uint32_t captureStateBaseAddressCount = 0;
uint32_t getSbaTrackingCommandsSizeCount = 0;
uint32_t registerElfCount = 0;
uint32_t registerElfAndLinkCount = 0;
uint32_t commandQueueCreatedCount = 0;
uint32_t commandQueueDestroyedCount = 0;
uint32_t registerAllocationTypeCount = 0;
@ -118,6 +128,7 @@ class MockDebuggerL0Hw : public NEO::DebuggerL0Hw<GfxFamily> {
uint32_t segmentCountWithAttachedModuleHandle = 0;
uint32_t removedZebinModuleHandle = 0;
uint32_t moduleHandleToReturn = std::numeric_limits<uint32_t>::max();
uint32_t elfHandleToReturn = std::numeric_limits<uint32_t>::max();
NEO::Device *notifyModuleLoadAllocationsCapturedDevice = nullptr;
};

View File

@ -9,3 +9,5 @@ target_sources(neo_shared_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test_l0_debugger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_l0_debugger_single_address_space.cpp
)
add_subdirectories()

View File

@ -0,0 +1,12 @@
#
# Copyright (C) 2022 Intel Corporation
#
# SPDX-License-Identifier: MIT
#
if(UNIX)
target_sources(neo_shared_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
${CMAKE_CURRENT_SOURCE_DIR}/test_l0_debugger_linux.cpp
)
endif()

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2022 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/debugger/debugger_l0.h"
#include "shared/source/execution_environment/root_device_environment.h"
#include "shared/source/kernel/debug_data.h"
#include "shared/source/os_interface/os_interface.h"
#include "shared/test/common/libult/linux/drm_mock.h"
#include "shared/test/common/mocks/linux/mock_drm_allocation.h"
#include "shared/test/common/mocks/mock_device.h"
#include "shared/test/common/test_macros/test.h"
#include <algorithm>
#include <memory>
using namespace NEO;
struct L0DebuggerSharedLinuxFixture {
void setUp() {
setUp(nullptr);
}
void setUp(HardwareInfo *hwInfo) {
auto executionEnvironment = new NEO::ExecutionEnvironment();
executionEnvironment->prepareRootDeviceEnvironments(1);
executionEnvironment->setDebuggingEnabled();
executionEnvironment->rootDeviceEnvironments[0]->setHwInfo(hwInfo ? hwInfo : defaultHwInfo.get());
executionEnvironment->initializeMemoryManager();
auto osInterface = new OSInterface();
drmMock = new DrmMockResources(*executionEnvironment->rootDeviceEnvironments[0]);
executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(osInterface);
executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::unique_ptr<Drm>(drmMock));
neoDevice.reset(NEO::MockDevice::create<NEO::MockDevice>(executionEnvironment, 0u));
auto rootDeviceEnvironment = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get();
rootDeviceEnvironment->initDebuggerL0(neoDevice.get());
}
void tearDown() {
drmMock = nullptr;
};
std::unique_ptr<NEO::MockDevice> neoDevice = nullptr;
DrmMockResources *drmMock = nullptr;
};
using L0DebuggerSharedLinuxTest = Test<L0DebuggerSharedLinuxFixture>;
TEST_F(L0DebuggerSharedLinuxTest, givenNoOSInterfaceThenRegisterElfDoesNothing) {
NEO::OSInterface *osInterfaceTmp = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.release();
NEO::DebugData debugData;
debugData.vIsa = "01234567890";
debugData.vIsaSize = 10;
drmMock->registeredDataSize = 0;
neoDevice->getL0Debugger()->registerElf(&debugData);
EXPECT_EQ(static_cast<size_t>(0u), drmMock->registeredDataSize);
neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(osInterfaceTmp);
}
TEST_F(L0DebuggerSharedLinuxTest, givenNoOSInterfaceThenRegisterElfAndLinkWithAllocationDoesNothing) {
NEO::OSInterface *osInterfaceTmp = neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.release();
NEO::DebugData debugData;
debugData.vIsa = "01234567890";
debugData.vIsaSize = 10;
drmMock->registeredDataSize = 0;
MockDrmAllocation isaAllocation(AllocationType::KERNEL_ISA, MemoryPool::System4KBPages);
MockBufferObject bo(drmMock, 3, 0, 0, 1);
isaAllocation.bufferObjects[0] = &bo;
neoDevice->getL0Debugger()->registerElfAndLinkWithAllocation(&debugData, &isaAllocation);
EXPECT_EQ(static_cast<size_t>(0u), drmMock->registeredDataSize);
EXPECT_EQ(0u, isaAllocation.bufferObjects[0]->getBindExtHandles().size());
neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(osInterfaceTmp);
}