From fc224202d61b80f76d5539d820964678f83f458d Mon Sep 17 00:00:00 2001 From: Kacper Nowak Date: Fri, 14 Jan 2022 15:39:43 +0000 Subject: [PATCH] Create debug zebin in OCL This commit adds debug zebin creation in OCL. - Added returning debug zebin in build/linking paths in OCL if corresponding device binary format was detected. - Refactored getZebinSegments() method - added common ctor for both L0/OCL paths Signed-off-by: Kacper Nowak --- level_zero/core/source/module/module_imp.cpp | 31 ++----- opencl/source/program/build.cpp | 2 +- opencl/source/program/link.cpp | 2 +- .../source/program/process_device_binary.cpp | 35 +++++++- opencl/source/program/program.h | 8 +- opencl/test/unit_test/program/CMakeLists.txt | 5 +- .../unit_test/program/program_with_zebin.cpp | 61 ++++++++++++++ .../unit_test/program/program_with_zebin.h | 54 ++++++++++++ .../program/program_with_zebin_tests.cpp | 82 +++++++++++++++++++ .../device_binary_format/debug_zebin.cpp | 21 ++++- .../source/device_binary_format/debug_zebin.h | 6 +- 11 files changed, 275 insertions(+), 32 deletions(-) create mode 100644 opencl/test/unit_test/program/program_with_zebin.cpp create mode 100644 opencl/test/unit_test/program/program_with_zebin.h create mode 100644 opencl/test/unit_test/program/program_with_zebin_tests.cpp diff --git a/level_zero/core/source/module/module_imp.cpp b/level_zero/core/source/module/module_imp.cpp index d32de6b2c5..f2a2667b8b 100644 --- a/level_zero/core/source/module/module_imp.cpp +++ b/level_zero/core/source/module/module_imp.cpp @@ -440,31 +440,12 @@ ModuleImp::~ModuleImp() { } NEO::Debug::Segments ModuleImp::getZebinSegments() { - NEO::Debug::Segments segments; - - auto varBuffer = translationUnit->globalVarBuffer; - if (varBuffer) { - segments.varData = {varBuffer->getGpuAddressToPatch(), {reinterpret_cast(varBuffer->getUnderlyingBuffer()), varBuffer->getUnderlyingBufferSize()}}; - } - - auto constBuffer = translationUnit->globalConstBuffer; - if (constBuffer) { - segments.constData = {constBuffer->getGpuAddressToPatch(), {reinterpret_cast(constBuffer->getUnderlyingBuffer()), constBuffer->getUnderlyingBufferSize()}}; - } - - auto stringBuffer = translationUnit->programInfo.globalStrings; - if (stringBuffer.initData) { - segments.stringData = {reinterpret_cast(stringBuffer.initData), - {reinterpret_cast(stringBuffer.initData), stringBuffer.size}}; - } - - for (auto &kernImmData : this->kernelImmDatas) { - const auto &isa = kernImmData->getIsaGraphicsAllocation(); - NEO::Debug::Segments::Segment kernelSegment = {isa->getGpuAddressToPatch(), {reinterpret_cast(isa->getUnderlyingBuffer()), isa->getUnderlyingBufferSize()}}; - segments.nameToSegMap.insert(std::pair(kernImmData->getDescriptor().kernelMetadata.kernelName, kernelSegment)); - } - - return segments; + std::vector> kernels; + for (const auto &kernelImmData : kernelImmDatas) + kernels.push_back({kernelImmData->getDescriptor().kernelMetadata.kernelName, kernelImmData->getIsaGraphicsAllocation()}); + ArrayRef strings = {reinterpret_cast(translationUnit->programInfo.globalStrings.initData), + translationUnit->programInfo.globalStrings.size}; + return NEO::Debug::Segments(translationUnit->globalVarBuffer, translationUnit->globalConstBuffer, strings, kernels); } bool ModuleImp::initialize(const ze_module_desc_t *desc, NEO::Device *neoDevice) { diff --git a/opencl/source/program/build.cpp b/opencl/source/program/build.cpp index 99d89efb09..b483bfe7b7 100644 --- a/opencl/source/program/build.cpp +++ b/opencl/source/program/build.cpp @@ -186,7 +186,7 @@ cl_int Program::build( if (BuildPhase::DebugDataNotification == phaseReached[rootDeviceIndex]) { continue; } - processDebugData(rootDeviceIndex); + createDebugData(clDevice->getRootDeviceIndex()); if (clDevice->getSourceLevelDebugger()) { for (auto kernelInfo : buildInfos[rootDeviceIndex].kernelInfoArray) { clDevice->getSourceLevelDebugger()->notifyKernelDebugData(&kernelInfo->debugData, diff --git a/opencl/source/program/link.cpp b/opencl/source/program/link.cpp index 5bf1f7c3b7..8c20104417 100644 --- a/opencl/source/program/link.cpp +++ b/opencl/source/program/link.cpp @@ -170,7 +170,7 @@ cl_int Program::link( if (kernelDebugDataNotified[rootDeviceIndex]) { continue; } - processDebugData(rootDeviceIndex); + createDebugData(rootDeviceIndex); for (auto kernelInfo : buildInfos[rootDeviceIndex].kernelInfoArray) { device->getSourceLevelDebugger()->notifyKernelDebugData(&kernelInfo->debugData, kernelInfo->kernelDescriptor.kernelMetadata.kernelName, diff --git a/opencl/source/program/process_device_binary.cpp b/opencl/source/program/process_device_binary.cpp index c569395904..59a045168a 100644 --- a/opencl/source/program/process_device_binary.cpp +++ b/opencl/source/program/process_device_binary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2022 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -61,6 +61,7 @@ cl_int Program::linkBinary(Device *pDevice, const void *constantsInitData, const } auto rootDeviceIndex = pDevice->getRootDeviceIndex(); auto &kernelInfoArray = buildInfos[rootDeviceIndex].kernelInfoArray; + buildInfos[rootDeviceIndex].constStringSectionData = stringsInfo; Linker linker(*linkerInput); Linker::SegmentInfo globals; Linker::SegmentInfo constants; @@ -276,4 +277,36 @@ void Program::processDebugData(uint32_t rootDeviceIndex) { } } +Debug::Segments Program::getZebinSegments(uint32_t rootDeviceIndex) { + ArrayRef strings = {reinterpret_cast(buildInfos[rootDeviceIndex].constStringSectionData.initData), + buildInfos[rootDeviceIndex].constStringSectionData.size}; + std::vector> kernels; + for (const auto &kernelInfo : buildInfos[rootDeviceIndex].kernelInfoArray) + kernels.push_back({kernelInfo->kernelDescriptor.kernelMetadata.kernelName, kernelInfo->getGraphicsAllocation()}); + + return Debug::Segments(getGlobalSurface(rootDeviceIndex), getConstantSurface(rootDeviceIndex), strings, kernels); +} + +void Program::createDebugZebin(uint32_t rootDeviceIndex) { + if (debugDataSize != 0) { + return; + } + auto refBin = ArrayRef(reinterpret_cast(buildInfos[rootDeviceIndex].unpackedDeviceBinary.get()), buildInfos[rootDeviceIndex].unpackedDeviceBinarySize); + auto segments = getZebinSegments(rootDeviceIndex); + auto debugZebin = Debug::createDebugZebin(refBin, segments); + + debugDataSize = debugZebin.size(); + debugData.reset(new char[debugDataSize]); + memcpy_s(debugData.get(), debugDataSize, + debugZebin.data(), debugZebin.size()); +} + +void Program::createDebugData(uint32_t rootDeviceIndex) { + auto refBin = ArrayRef(reinterpret_cast(buildInfos[rootDeviceIndex].unpackedDeviceBinary.get()), buildInfos[rootDeviceIndex].unpackedDeviceBinarySize); + if (isDeviceBinaryFormat(refBin)) { + createDebugZebin(rootDeviceIndex); + } else { + processDebugData(rootDeviceIndex); + } +} } // namespace NEO diff --git a/opencl/source/program/program.h b/opencl/source/program/program.h index 01b46b062c..af6363c59e 100644 --- a/opencl/source/program/program.h +++ b/opencl/source/program/program.h @@ -8,6 +8,7 @@ #pragma once #include "shared/source/compiler_interface/compiler_interface.h" #include "shared/source/compiler_interface/linker.h" +#include "shared/source/device_binary_format/debug_zebin.h" #include "shared/source/device_binary_format/elf/elf_encoder.h" #include "shared/source/helpers/non_copyable_or_moveable.h" #include "shared/source/program/program_info.h" @@ -173,7 +174,7 @@ class Program : public BaseObject<_cl_program> { cl_int getSource(std::string &binary) const; - void processDebugData(uint32_t rootDeviceIndex); + MOCKABLE_VIRTUAL void processDebugData(uint32_t rootDeviceIndex); void updateBuildLog(uint32_t rootDeviceIndex, const char *pErrorString, const size_t errorStringSize); @@ -282,6 +283,10 @@ class Program : public BaseObject<_cl_program> { this->context = pContext; } + void createDebugData(uint32_t rootDeviceIndex); + MOCKABLE_VIRTUAL void createDebugZebin(uint32_t rootDeviceIndex); + Debug::Segments getZebinSegments(uint32_t rootDeviceIndex); + protected: MOCKABLE_VIRTUAL cl_int createProgramFromBinary(const void *pBinary, size_t binarySize, ClDevice &clDevice); @@ -350,6 +355,7 @@ class Program : public BaseObject<_cl_program> { std::unique_ptr packedDeviceBinary; size_t packedDeviceBinarySize = 0U; + ProgramInfo::GlobalSurfaceInfo constStringSectionData; }; std::vector buildInfos; diff --git a/opencl/test/unit_test/program/CMakeLists.txt b/opencl/test/unit_test/program/CMakeLists.txt index 6a4c696970..a62fce23e2 100644 --- a/opencl/test/unit_test/program/CMakeLists.txt +++ b/opencl/test/unit_test/program/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2018-2021 Intel Corporation +# Copyright (C) 2018-2022 Intel Corporation # # SPDX-License-Identifier: MIT # @@ -25,6 +25,9 @@ set(IGDRCL_SRCS_tests_program ${CMAKE_CURRENT_SOURCE_DIR}/program_with_block_kernels_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/program_with_kernel_debug_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/program_with_source.h + ${CMAKE_CURRENT_SOURCE_DIR}/program_with_zebin.h + ${CMAKE_CURRENT_SOURCE_DIR}/program_with_zebin.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/program_with_zebin_tests.cpp ) get_property(NEO_CORE_SRCS_tests_program GLOBAL PROPERTY NEO_CORE_SRCS_tests_program) diff --git a/opencl/test/unit_test/program/program_with_zebin.cpp b/opencl/test/unit_test/program/program_with_zebin.cpp new file mode 100644 index 0000000000..98c02d665d --- /dev/null +++ b/opencl/test/unit_test/program/program_with_zebin.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "opencl/test/unit_test/program/program_with_zebin.h" + +#include "shared/test/unit_test/device_binary_format/zebin_tests.h" + +#include "opencl/test/unit_test/mocks/mock_buffer.h" + +using namespace NEO; + +void ProgramWithZebinFixture::SetUp() { + ProgramTests::SetUp(); + program = std::make_unique(toClDeviceVector(*pClDevice)); +} + +void ProgramWithZebinFixture::TearDown() { + program->setGlobalSurface(nullptr); + program->setConstantSurface(nullptr); + program->getKernelInfoArray(rootDeviceIndex).clear(); + ProgramTests::TearDown(); +} + +void ProgramWithZebinFixture::addEmptyZebin(NEO::MockProgram *program) { + auto zebin = ZebinTestData::ValidEmptyProgram(); + + program->buildInfos[rootDeviceIndex].unpackedDeviceBinarySize = zebin.storage.size(); + program->buildInfos[rootDeviceIndex].unpackedDeviceBinary.reset(new char[zebin.storage.size()]); + memcpy_s(program->buildInfos[rootDeviceIndex].unpackedDeviceBinary.get(), program->buildInfos[rootDeviceIndex].unpackedDeviceBinarySize, + zebin.storage.data(), zebin.storage.size()); +} + +void ProgramWithZebinFixture::populateProgramWithSegments(NEO::MockProgram *program) { + kernelInfo = std::make_unique(); + kernelInfo->kernelDescriptor.kernelMetadata.kernelName = kernelName; + mockAlloc = std::make_unique(); + kernelInfo->kernelAllocation = mockAlloc.get(); + + program->addKernelInfo(kernelInfo.get(), rootDeviceIndex); + + globalSurface = std::make_unique(); + constantSurface = std::make_unique(); + program->setGlobalSurface(&globalSurface->mockGfxAllocation); + program->setConstantSurface(&constantSurface->mockGfxAllocation); + + program->buildInfos[rootDeviceIndex].constStringSectionData.initData = &strings; + program->buildInfos[rootDeviceIndex].constStringSectionData.size = sizeof(strings); +} + +void ProgramWithDebugDataCreationFixture::SetUp() { + ProgramWithZebinFixture::SetUp(); + programWithDebugDataCreation = std::make_unique(toClDeviceVector(*pClDevice)); +} + +void ProgramWithDebugDataCreationFixture::TearDown() { + ProgramWithZebinFixture::TearDown(); +} \ No newline at end of file diff --git a/opencl/test/unit_test/program/program_with_zebin.h b/opencl/test/unit_test/program/program_with_zebin.h new file mode 100644 index 0000000000..69fad7f819 --- /dev/null +++ b/opencl/test/unit_test/program/program_with_zebin.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "opencl/test/unit_test/mocks/mock_program.h" +#include "opencl/test/unit_test/program/program_tests.h" + +using namespace NEO; + +class MockBuffer; +class ProgramWithZebinFixture : public ProgramTests { + public: + std::unique_ptr program; + std::unique_ptr kernelInfo; + std::unique_ptr mockAlloc; + std::unique_ptr globalSurface; + std::unique_ptr constantSurface; + const char strings[12] = "Hello olleH"; + const char kernelName[8] = "kernel1"; + void SetUp() override; + void TearDown() override; + void addEmptyZebin(MockProgram *program); + void populateProgramWithSegments(MockProgram *program); + ~ProgramWithZebinFixture() = default; +}; + +class ProgramWithDebugDataCreationFixture : public ProgramWithZebinFixture { + + class MockProgramWithDebugDataCreation : public MockProgram { + public: + using Program::createDebugData; + MockProgramWithDebugDataCreation(const ClDeviceVector &deviceVector) : MockProgram(deviceVector) { + } + ~MockProgramWithDebugDataCreation() { + } + bool wasProcessDebugDataCalled = false; + void processDebugData(uint32_t rootDeviceIndex) override { + wasProcessDebugDataCalled = true; + } + bool wasCreateDebugZebinCalled = false; + void createDebugZebin(uint32_t rootDeviceIndex) override { + wasCreateDebugZebinCalled = true; + } + }; + + public: + std::unique_ptr programWithDebugDataCreation; + void SetUp() override; + void TearDown() override; +}; \ No newline at end of file diff --git a/opencl/test/unit_test/program/program_with_zebin_tests.cpp b/opencl/test/unit_test/program/program_with_zebin_tests.cpp new file mode 100644 index 0000000000..d0dc72b8e7 --- /dev/null +++ b/opencl/test/unit_test/program/program_with_zebin_tests.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/test/common/test_macros/test.h" + +#include "opencl/test/unit_test/mocks/mock_buffer.h" +#include "opencl/test/unit_test/program/program_with_zebin.h" + +#include +using namespace NEO; + +TEST_F(ProgramWithZebinFixture, givenNoZebinThenSegmentsAreEmpty) { + auto segments = program->getZebinSegments(pClDevice->getRootDeviceIndex()); + + EXPECT_EQ(std::numeric_limits::max(), segments.constData.address); + EXPECT_TRUE(segments.constData.data.empty()); + + EXPECT_EQ(std::numeric_limits::max(), segments.varData.address); + EXPECT_TRUE(segments.varData.data.empty()); + + EXPECT_EQ(std::numeric_limits::max(), segments.stringData.address); + EXPECT_TRUE(segments.stringData.data.empty()); + + EXPECT_TRUE(segments.nameToSegMap.empty()); +} + +TEST_F(ProgramWithZebinFixture, givenZebinSegmentsThenSegmentsArePopulated) { + populateProgramWithSegments(program.get()); + auto segments = program->getZebinSegments(rootDeviceIndex); + + auto checkGPUSeg = [](NEO::GraphicsAllocation *alloc, NEO::Debug::Segments::Segment segment) { + EXPECT_EQ(static_cast(alloc->getGpuAddressToPatch()), segment.address); + EXPECT_EQ(reinterpret_cast(alloc->getUnderlyingBuffer()), segment.data.begin()); + EXPECT_EQ(static_cast(alloc->getUnderlyingBufferSize()), segment.data.size()); + }; + checkGPUSeg(program->buildInfos[rootDeviceIndex].constantSurface, segments.constData); + checkGPUSeg(program->buildInfos[rootDeviceIndex].globalSurface, segments.varData); + checkGPUSeg(program->getKernelInfoArray(rootDeviceIndex)[0]->getGraphicsAllocation(), segments.nameToSegMap["kernel1"]); + + EXPECT_EQ(reinterpret_cast(program->buildInfos[rootDeviceIndex].constStringSectionData.initData), segments.stringData.address); + EXPECT_EQ(reinterpret_cast(program->buildInfos[rootDeviceIndex].constStringSectionData.initData), segments.stringData.data.begin()); + EXPECT_EQ(program->buildInfos[rootDeviceIndex].constStringSectionData.size, segments.stringData.data.size()); +} + +TEST_F(ProgramWithZebinFixture, givenNonEmptyDebugDataThenDebugZebinIsNotCreated) { + addEmptyZebin(program.get()); + populateProgramWithSegments(program.get()); + program->debugDataSize = 8u; + program->debugData.reset(nullptr); + program->createDebugZebin(rootDeviceIndex); + EXPECT_EQ(nullptr, program->debugData.get()); +} + +TEST_F(ProgramWithZebinFixture, givenEmptyDebugDataThenDebugZebinIsCreatedAndStoredInDebugData) { + addEmptyZebin(program.get()); + populateProgramWithSegments(program.get()); + + program->debugDataSize = 0u; + program->debugData.reset(nullptr); + program->createDebugZebin(rootDeviceIndex); + EXPECT_NE(nullptr, program->debugData.get()); +} + +TEST_F(ProgramWithDebugDataCreationFixture, givenZebinaryFormatInCreateDebugDataThenCreateDebugZebinIsCalled) { + addEmptyZebin(programWithDebugDataCreation.get()); + programWithDebugDataCreation->createDebugData(rootDeviceIndex); + EXPECT_TRUE(programWithDebugDataCreation->wasCreateDebugZebinCalled); + EXPECT_FALSE(programWithDebugDataCreation->wasProcessDebugDataCalled); +} + +TEST_F(ProgramWithDebugDataCreationFixture, givenNonZebinaryFormatInCreateDebugDataThenProcessDebugDataIsCalled) { + size_t fakeBinarySize = 8u; + programWithDebugDataCreation->buildInfos[rootDeviceIndex].unpackedDeviceBinarySize = fakeBinarySize; + programWithDebugDataCreation->buildInfos[rootDeviceIndex].unpackedDeviceBinary.reset(new char[fakeBinarySize]); + programWithDebugDataCreation->createDebugData(rootDeviceIndex); + EXPECT_FALSE(programWithDebugDataCreation->wasCreateDebugZebinCalled); + EXPECT_TRUE(programWithDebugDataCreation->wasProcessDebugDataCalled); +} \ No newline at end of file diff --git a/shared/source/device_binary_format/debug_zebin.cpp b/shared/source/device_binary_format/debug_zebin.cpp index fdcd522422..14daadb053 100644 --- a/shared/source/device_binary_format/debug_zebin.cpp +++ b/shared/source/device_binary_format/debug_zebin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -9,11 +9,30 @@ #include "shared/source/device_binary_format/elf/elf_decoder.h" #include "shared/source/device_binary_format/elf/elf_encoder.h" +#include "shared/source/memory_manager/graphics_allocation.h" namespace NEO { namespace Debug { using namespace Elf; +Segments::Segments() {} + +Segments::Segments(const GraphicsAllocation *globalVarAlloc, const GraphicsAllocation *globalConstAlloc, ArrayRef &globalStrings, std::vector &kernels) { + if (globalVarAlloc) { + varData = {static_cast(globalVarAlloc->getGpuAddressToPatch()), {reinterpret_cast(globalVarAlloc->getUnderlyingBuffer()), globalVarAlloc->getUnderlyingBufferSize()}}; + } + if (globalConstAlloc) { + constData = {static_cast(globalConstAlloc->getGpuAddressToPatch()), {reinterpret_cast(globalConstAlloc->getUnderlyingBuffer()), globalConstAlloc->getUnderlyingBufferSize()}}; + } + if (false == globalStrings.empty()) { + stringData = {reinterpret_cast(globalStrings.begin()), globalStrings}; + } + for (auto &[kernelName, isa] : kernels) { + Debug::Segments::Segment kernelSegment = {static_cast(isa->getGpuAddressToPatch()), {reinterpret_cast(isa->getUnderlyingBuffer()), isa->getUnderlyingBufferSize()}}; + nameToSegMap.insert(std::pair(kernelName, kernelSegment)); + } +} + void DebugZebinCreator::createDebugZebin() { ElfEncoder elfEncoder(false, false); auto &header = elfEncoder.getElfFileHeader(); diff --git a/shared/source/device_binary_format/debug_zebin.h b/shared/source/device_binary_format/debug_zebin.h index eb5f5a19c1..b7edad9809 100644 --- a/shared/source/device_binary_format/debug_zebin.h +++ b/shared/source/device_binary_format/debug_zebin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -15,6 +15,7 @@ #include namespace NEO { +class GraphicsAllocation; namespace Debug { struct Segments { struct Segment { @@ -23,12 +24,15 @@ struct Segments { }; using CPUSegment = Segment; using GPUSegment = Segment; + using KernelNameIsaPairT = std::pair; using KernelNameToSegmentMap = std::unordered_map; GPUSegment varData; GPUSegment constData; CPUSegment stringData; KernelNameToSegmentMap nameToSegMap; + Segments(); + Segments(const GraphicsAllocation *globalVarAlloc, const GraphicsAllocation *globalConstAlloc, ArrayRef &globalStrings, std::vector &kernels); }; class DebugZebinCreator {