diff --git a/opencl/source/program/build.cpp b/opencl/source/program/build.cpp index c28b170704..f197245474 100644 --- a/opencl/source/program/build.cpp +++ b/opencl/source/program/build.cpp @@ -41,14 +41,6 @@ cl_int Program::build( UNRECOVERABLE_IF(defaultClDevice == nullptr); auto &defaultDevice = defaultClDevice->getDevice(); - enum class BuildPhase { - Init, - SourceCodeNotification, - BinaryCreation, - BinaryProcessing, - DebugDataNotification - }; - std::unordered_map phaseReached; for (const auto &clDevice : deviceVector) { phaseReached[clDevice->getRootDeviceIndex()] = BuildPhase::Init; @@ -194,14 +186,7 @@ cl_int Program::build( } if (isKernelDebugEnabled() || gtpinIsGTPinInitialized()) { - for (auto &clDevice : deviceVector) { - auto rootDeviceIndex = clDevice->getRootDeviceIndex(); - if (BuildPhase::DebugDataNotification == phaseReached[rootDeviceIndex]) { - continue; - } - notifyDebuggerWithDebugData(clDevice); - phaseReached[rootDeviceIndex] = BuildPhase::DebugDataNotification; - } + debugNotify(deviceVector, phaseReached); } } while (false); @@ -269,4 +254,15 @@ void Program::extractInternalOptions(const std::string &options, std::string &in } } +void Program::debugNotify(const ClDeviceVector &deviceVector, std::unordered_map &phasesReached) { + for (auto &clDevice : deviceVector) { + auto rootDeviceIndex = clDevice->getRootDeviceIndex(); + if (BuildPhase::DebugDataNotification == phasesReached[rootDeviceIndex]) { + continue; + } + notifyDebuggerWithDebugData(clDevice); + phasesReached[rootDeviceIndex] = BuildPhase::DebugDataNotification; + } +} + } // namespace NEO diff --git a/opencl/source/program/program.h b/opencl/source/program/program.h index c4144c74c3..415ca62a2f 100644 --- a/opencl/source/program/program.h +++ b/opencl/source/program/program.h @@ -30,6 +30,7 @@ namespace PatchTokenBinary { struct ProgramFromPatchtokens; } +enum class BuildPhase; class BuiltinDispatchInfoBuilder; class ClDevice; class Context; @@ -72,6 +73,14 @@ class Program : public BaseObject<_cl_program> { public: static const cl_ulong objectMagic = 0x5651C89100AAACFELL; + enum class BuildPhase { + Init, + SourceCodeNotification, + BinaryCreation, + BinaryProcessing, + DebugDataNotification + }; + enum class CreatedFrom { SOURCE, IL, @@ -276,6 +285,7 @@ class Program : public BaseObject<_cl_program> { this->context = pContext; } + MOCKABLE_VIRTUAL void debugNotify(const ClDeviceVector &deviceVector, std::unordered_map &phasesReached); void notifyDebuggerWithDebugData(ClDevice *clDevice); MOCKABLE_VIRTUAL void createDebugZebin(uint32_t rootDeviceIndex); Debug::Segments getZebinSegments(uint32_t rootDeviceIndex); diff --git a/opencl/test/unit_test/mocks/mock_program.h b/opencl/test/unit_test/mocks/mock_program.h index 1fbc59b93a..6db83f2195 100644 --- a/opencl/test/unit_test/mocks/mock_program.h +++ b/opencl/test/unit_test/mocks/mock_program.h @@ -189,6 +189,11 @@ class MockProgram : public Program { wasCreateDebugZebinCalled = true; } + void debugNotify(const ClDeviceVector &deviceVector, std::unordered_map &phasesReached) override { + Program::debugNotify(deviceVector, phasesReached); + wasDebuggerNotified = true; + } + std::vector externalFunctions; std::map processGenBinaryCalledPerRootDevice; std::map replaceDeviceBinaryCalledPerRootDevice; @@ -198,6 +203,7 @@ class MockProgram : public Program { int isOptionValueValidOverride = -1; bool wasProcessDebugDataCalled = false; bool wasCreateDebugZebinCalled = false; + bool wasDebuggerNotified = false; }; class MockProgramAppendKernelDebugOptions : public Program { diff --git a/opencl/test/unit_test/program/process_elf_binary_tests.cpp b/opencl/test/unit_test/program/process_elf_binary_tests.cpp index 8286b6ed0a..06a14c3ea6 100644 --- a/opencl/test/unit_test/program/process_elf_binary_tests.cpp +++ b/opencl/test/unit_test/program/process_elf_binary_tests.cpp @@ -15,12 +15,12 @@ #include "shared/test/common/helpers/test_files.h" #include "shared/test/common/mocks/mock_device.h" #include "shared/test/common/mocks/mock_elf.h" +#include "shared/test/unit_test/device_binary_format/elf/elf_tests_data.h" #include "shared/test/unit_test/device_binary_format/patchtokens_tests.h" #include "shared/test/unit_test/helpers/gtest_helpers.h" #include "opencl/test/unit_test/mocks/mock_cl_device.h" #include "opencl/test/unit_test/mocks/mock_program.h" -#include "opencl/test/unit_test/test_files/patch_list.h" #include "compiler_options.h" #include "gtest/gtest.h" @@ -29,52 +29,6 @@ using namespace NEO; -enum class enabledIrFormat { - NONE, - ENABLE_SPIRV, - ENABLE_LLVM -}; - -template -struct MockElfBinaryPatchtokens { - MockElfBinaryPatchtokens(const HardwareInfo &hwInfo) : MockElfBinaryPatchtokens(std::string{}, hwInfo){}; - MockElfBinaryPatchtokens(const std::string &buildOptions, const HardwareInfo &hwInfo) { - mockDevBinaryHeader.Device = hwInfo.platform.eRenderCoreFamily; - mockDevBinaryHeader.GPUPointerSizeInBytes = sizeof(void *); - mockDevBinaryHeader.Version = iOpenCL::CURRENT_ICBE_VERSION; - constexpr size_t mockDevBinaryDataSize = sizeof(mockDevBinaryHeader) + mockDataSize; - constexpr size_t mockSpirvBinaryDataSize = sizeof(spirvMagic) + mockDataSize; - constexpr size_t mockLlvmBinaryDataSize = sizeof(llvmBcMagic) + mockDataSize; - - char mockDevBinaryData[mockDevBinaryDataSize]; - memcpy_s(mockDevBinaryData, mockDevBinaryDataSize, &mockDevBinaryHeader, sizeof(mockDevBinaryHeader)); - memset(mockDevBinaryData + sizeof(mockDevBinaryHeader), '\x01', mockDataSize); - - char mockSpirvBinaryData[mockSpirvBinaryDataSize]; - memcpy_s(mockSpirvBinaryData, mockSpirvBinaryDataSize, spirvMagic.data(), spirvMagic.size()); - memset(mockSpirvBinaryData + spirvMagic.size(), '\x02', mockDataSize); - - char mockLlvmBinaryData[mockLlvmBinaryDataSize]; - memcpy_s(mockLlvmBinaryData, mockLlvmBinaryDataSize, llvmBcMagic.data(), llvmBcMagic.size()); - memset(mockLlvmBinaryData + llvmBcMagic.size(), '\x03', mockDataSize); - - Elf::ElfEncoder enc; - enc.getElfFileHeader().identity = Elf::ElfFileHeaderIdentity(Elf::EI_CLASS_64); - enc.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; - enc.appendSection(Elf::SHT_OPENCL_DEV_BINARY, Elf::SectionNamesOpenCl::deviceBinary, ArrayRef::fromAny(mockDevBinaryData, mockDevBinaryDataSize)); - if (irFormat == enabledIrFormat::ENABLE_SPIRV) - enc.appendSection(Elf::SHT_OPENCL_SPIRV, Elf::SectionNamesOpenCl::spirvObject, ArrayRef::fromAny(mockSpirvBinaryData, mockSpirvBinaryDataSize)); - else if (irFormat == enabledIrFormat::ENABLE_LLVM) - enc.appendSection(Elf::SHT_OPENCL_LLVM_BINARY, Elf::SectionNamesOpenCl::llvmObject, ArrayRef::fromAny(mockLlvmBinaryData, mockLlvmBinaryDataSize)); - if (false == buildOptions.empty()) - enc.appendSection(Elf::SHT_OPENCL_OPTIONS, Elf::SectionNamesOpenCl::buildOptions, ArrayRef::fromAny(buildOptions.data(), buildOptions.size())); - storage = enc.encode(); - } - static constexpr size_t mockDataSize = 0x10; - SProgramBinaryHeader mockDevBinaryHeader = SProgramBinaryHeader{MAGIC_CL, 0, 0, 0, 0, 0, 0}; - std::vector storage; -}; - class ProcessElfBinaryTests : public ::testing::Test { public: void SetUp() override { diff --git a/opencl/test/unit_test/program/program_with_kernel_debug_tests.cpp b/opencl/test/unit_test/program/program_with_kernel_debug_tests.cpp index 455b7a6fae..5706f0dfc2 100644 --- a/opencl/test/unit_test/program/program_with_kernel_debug_tests.cpp +++ b/opencl/test/unit_test/program/program_with_kernel_debug_tests.cpp @@ -5,12 +5,14 @@ * */ +#include "shared/source/device_binary_format/patchtokens_decoder.h" #include "shared/test/common/helpers/debug_manager_state_restore.h" #include "shared/test/common/helpers/kernel_binary_helper.h" #include "shared/test/common/helpers/kernel_filename_helper.h" #include "shared/test/common/libult/global_environment.h" #include "shared/test/common/mocks/mock_source_level_debugger.h" #include "shared/test/common/test_macros/test.h" +#include "shared/test/unit_test/device_binary_format/elf/elf_tests_data.h" #include "shared/test/unit_test/helpers/gtest_helpers.h" #include "opencl/test/unit_test/fixtures/program_fixture.h" @@ -20,6 +22,7 @@ #include "compiler_options.h" #include "gtest/gtest.h" +#include "program_debug_data.h" #include #include @@ -300,6 +303,11 @@ TEST_F(ProgramWithKernelDebuggingTest, givenEnabledKernelDebugWhenProgramIsLinke } TEST_F(ProgramWithKernelDebuggingTest, givenProgramWithKernelDebugEnabledWhenBuiltThenPatchTokenAllocateSipSurfaceHasSizeGreaterThanZero) { + auto &refBin = pProgram->buildInfos[pDevice->getRootDeviceIndex()].unpackedDeviceBinary; + auto refBinSize = pProgram->buildInfos[pDevice->getRootDeviceIndex()].unpackedDeviceBinarySize; + if (NEO::isDeviceBinaryFormat(ArrayRef::fromAny(refBin.get(), refBinSize))) { + GTEST_SKIP(); + } auto retVal = pProgram->build(pProgram->getDevices(), CompilerOptions::debugKernelEnable.data(), false); EXPECT_EQ(CL_SUCCESS, retVal); @@ -313,9 +321,7 @@ TEST_F(ProgramWithKernelDebuggingTest, givenGtpinInitializedWhenCreatingProgramF auto retVal = pProgram->build(pProgram->getDevices(), CompilerOptions::debugKernelEnable.data(), false); EXPECT_EQ(CL_SUCCESS, retVal); - auto kernelInfo = pProgram->getKernelInfo("CopyBuffer", pDevice->getRootDeviceIndex()); - EXPECT_NE(kernelInfo->debugData.vIsa, nullptr); - EXPECT_NE(0u, kernelInfo->debugData.vIsaSize); + EXPECT_TRUE(pProgram->wasDebuggerNotified); NEO::isGTPinInitialized = gtpinInitializedBackup; } @@ -327,9 +333,7 @@ TEST_F(ProgramWithKernelDebuggingTest, givenGtpinNotInitializedWhenCreatingProgr auto retVal = pProgram->build(pProgram->getDevices(), CompilerOptions::debugKernelEnable.data(), false); EXPECT_EQ(CL_SUCCESS, retVal); - auto kernelInfo = pProgram->getKernelInfo("CopyBuffer", pDevice->getRootDeviceIndex()); - EXPECT_EQ(kernelInfo->debugData.vIsa, nullptr); - EXPECT_EQ(0u, kernelInfo->debugData.vIsaSize); + EXPECT_FALSE(pProgram->wasDebuggerNotified); NEO::isGTPinInitialized = gtpinInitializedBackup; } @@ -344,15 +348,41 @@ TEST_F(ProgramWithKernelDebuggingTest, givenKernelDebugEnabledWhenProgramIsBuilt } TEST_F(ProgramWithKernelDebuggingTest, givenProgramWithKernelDebugEnabledWhenProcessDebugDataIsCalledThenKernelInfosAreFilledWithDebugData) { - auto retVal = pProgram->build(pProgram->getDevices(), nullptr, false); - EXPECT_EQ(CL_SUCCESS, retVal); + iOpenCL::SProgramDebugDataHeaderIGC debugDataHeader{}; + debugDataHeader.NumberOfKernels = 1u; + + char mockKernelName[] = "CopyBuffer"; + constexpr size_t mockKernelDebugDataSize = 0x10; + PatchTokenBinary::SKernelDebugDataHeaderIGC mockKernelDebugHeader{}; + mockKernelDebugHeader.KernelNameSize = sizeof(mockKernelName); + mockKernelDebugHeader.SizeVisaDbgInBytes = mockKernelDebugDataSize; + + char mockKerneDebugData[mockKernelDebugDataSize]; + memset(mockKerneDebugData, '\x01', mockKernelDebugDataSize); + + KernelInfo *mockKernelInfo = new KernelInfo{}; + mockKernelInfo->kernelDescriptor.kernelMetadata.kernelName = "CopyBuffer"; + pProgram->addKernelInfo(mockKernelInfo, pDevice->getRootDeviceIndex()); + + constexpr size_t mockDebugDataSize = sizeof(iOpenCL::SProgramDebugDataHeaderIGC) + sizeof(PatchTokenBinary::KernelFromPatchtokens) + sizeof(mockKernelName) + mockKernelDebugDataSize; + + char *mockDebugData = new char[mockDebugDataSize]; + auto dataPtr = mockDebugData; + + memcpy_s(dataPtr, mockDebugDataSize, &debugDataHeader, sizeof(iOpenCL::SProgramDebugDataHeaderIGC)); + dataPtr = ptrOffset(dataPtr, sizeof(iOpenCL::SProgramDebugDataHeaderIGC)); + memcpy_s(dataPtr, mockDebugDataSize, &mockKernelDebugHeader, sizeof(PatchTokenBinary::SKernelDebugDataHeaderIGC)); + dataPtr = ptrOffset(dataPtr, sizeof(PatchTokenBinary::SKernelDebugDataHeaderIGC)); + memcpy_s(dataPtr, mockDebugDataSize, &mockKernelName, sizeof(mockKernelName)); + dataPtr = ptrOffset(dataPtr, sizeof(mockKernelName)); + memcpy_s(dataPtr, mockDebugDataSize, mockKerneDebugData, mockKernelDebugDataSize); + pProgram->buildInfos[pDevice->getRootDeviceIndex()].debugData.reset(mockDebugData); pProgram->processDebugData(pDevice->getRootDeviceIndex()); + auto receivedKernelInfo = pProgram->getKernelInfo("CopyBuffer", pDevice->getRootDeviceIndex()); - auto kernelInfo = pProgram->getKernelInfo("CopyBuffer", pDevice->getRootDeviceIndex()); - - EXPECT_NE(0u, kernelInfo->debugData.vIsaSize); - EXPECT_NE(nullptr, kernelInfo->debugData.vIsa); + EXPECT_NE(0u, receivedKernelInfo->debugData.vIsaSize); + EXPECT_NE(nullptr, receivedKernelInfo->debugData.vIsa); } TEST_F(ProgramWithKernelDebuggingTest, givenProgramWithNonZebinaryFormatAndKernelDebugEnabledWhenProgramIsBuiltThenProcessDebugDataIsCalledAndDebuggerNotified) { @@ -360,9 +390,25 @@ TEST_F(ProgramWithKernelDebuggingTest, givenProgramWithNonZebinaryFormatAndKerne pDevice->executionEnvironment->rootDeviceEnvironments[pDevice->getRootDeviceIndex()]->debugger.reset(sourceLevelDebugger); pProgram->enableKernelDebug(); - cl_int retVal = pProgram->build(pProgram->getDevices(), nullptr, false); - EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_FALSE(pProgram->wasCreateDebugZebinCalled); - EXPECT_TRUE(pProgram->wasProcessDebugDataCalled); - EXPECT_EQ(1u, sourceLevelDebugger->notifyKernelDebugDataCalled); + auto mockElf = std::make_unique>(pDevice->getHardwareInfo()); + auto mockElfSize = mockElf->storage.size(); + auto mockElfData = mockElf->storage.data(); + + pProgram->buildInfos[pDevice->getRootDeviceIndex()].unpackedDeviceBinarySize = mockElfSize; + pProgram->buildInfos[pDevice->getRootDeviceIndex()].unpackedDeviceBinary.reset(new char[mockElfSize]); + memcpy_s(pProgram->buildInfos[pDevice->getRootDeviceIndex()].unpackedDeviceBinary.get(), pProgram->buildInfos[pDevice->getRootDeviceIndex()].unpackedDeviceBinarySize, + mockElfData, mockElfSize); + + KernelInfo *mockKernelInfo = new KernelInfo{}; + mockKernelInfo->kernelDescriptor.kernelMetadata.kernelName = "CopyBuffer"; + pProgram->addKernelInfo(mockKernelInfo, pDevice->getRootDeviceIndex()); + + auto counter = 0u; + for (const auto &device : pProgram->getDevices()) { + pProgram->notifyDebuggerWithDebugData(device); + + EXPECT_FALSE(pProgram->wasCreateDebugZebinCalled); + EXPECT_TRUE(pProgram->wasProcessDebugDataCalled); + EXPECT_EQ(++counter, sourceLevelDebugger->notifyKernelDebugDataCalled); + } } \ No newline at end of file diff --git a/shared/test/unit_test/device_binary_format/CMakeLists.txt b/shared/test/unit_test/device_binary_format/CMakeLists.txt index 3aed07d987..d06948aaeb 100644 --- a/shared/test/unit_test/device_binary_format/CMakeLists.txt +++ b/shared/test/unit_test/device_binary_format/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_decoder_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_encoder_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_tests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_tests_data.h ${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_decoder_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_dumper_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_tests.h diff --git a/shared/test/unit_test/device_binary_format/elf/elf_tests_data.h b/shared/test/unit_test/device_binary_format/elf/elf_tests_data.h new file mode 100644 index 0000000000..1952c6b2e0 --- /dev/null +++ b/shared/test/unit_test/device_binary_format/elf/elf_tests_data.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "shared/source/compiler_interface/intermediate_representations.h" +#include "shared/source/device_binary_format/elf/elf_encoder.h" +#include "shared/source/device_binary_format/elf/ocl_elf.h" + +#include "patch_list.h" + +using namespace NEO; + +enum class enabledIrFormat { + NONE, + ENABLE_SPIRV, + ENABLE_LLVM +}; + +template +struct MockElfBinaryPatchtokens { + MockElfBinaryPatchtokens(const HardwareInfo &hwInfo) : MockElfBinaryPatchtokens(std::string{}, hwInfo){}; + MockElfBinaryPatchtokens(const std::string &buildOptions, const HardwareInfo &hwInfo) { + mockDevBinaryHeader.Device = hwInfo.platform.eRenderCoreFamily; + mockDevBinaryHeader.GPUPointerSizeInBytes = sizeof(void *); + mockDevBinaryHeader.Version = iOpenCL::CURRENT_ICBE_VERSION; + constexpr size_t mockDevBinaryDataSize = sizeof(mockDevBinaryHeader) + mockDataSize; + constexpr size_t mockSpirvBinaryDataSize = sizeof(spirvMagic) + mockDataSize; + constexpr size_t mockLlvmBinaryDataSize = sizeof(llvmBcMagic) + mockDataSize; + + char mockDevBinaryData[mockDevBinaryDataSize]{}; + memcpy_s(mockDevBinaryData, mockDevBinaryDataSize, &mockDevBinaryHeader, sizeof(mockDevBinaryHeader)); + memset(mockDevBinaryData + sizeof(mockDevBinaryHeader), '\x01', mockDataSize); + + char mockSpirvBinaryData[mockSpirvBinaryDataSize]{}; + memcpy_s(mockSpirvBinaryData, mockSpirvBinaryDataSize, spirvMagic.data(), spirvMagic.size()); + memset(mockSpirvBinaryData + spirvMagic.size(), '\x02', mockDataSize); + + char mockLlvmBinaryData[mockLlvmBinaryDataSize]{}; + memcpy_s(mockLlvmBinaryData, mockLlvmBinaryDataSize, llvmBcMagic.data(), llvmBcMagic.size()); + memset(mockLlvmBinaryData + llvmBcMagic.size(), '\x03', mockDataSize); + + Elf::ElfEncoder enc; + enc.getElfFileHeader().identity = Elf::ElfFileHeaderIdentity(Elf::EI_CLASS_64); + enc.getElfFileHeader().type = NEO::Elf::ET_OPENCL_EXECUTABLE; + enc.appendSection(Elf::SHT_OPENCL_DEV_BINARY, Elf::SectionNamesOpenCl::deviceBinary, ArrayRef::fromAny(mockDevBinaryData, mockDevBinaryDataSize)); + if (irFormat == enabledIrFormat::ENABLE_SPIRV) + enc.appendSection(Elf::SHT_OPENCL_SPIRV, Elf::SectionNamesOpenCl::spirvObject, ArrayRef::fromAny(mockSpirvBinaryData, mockSpirvBinaryDataSize)); + else if (irFormat == enabledIrFormat::ENABLE_LLVM) + enc.appendSection(Elf::SHT_OPENCL_LLVM_BINARY, Elf::SectionNamesOpenCl::llvmObject, ArrayRef::fromAny(mockLlvmBinaryData, mockLlvmBinaryDataSize)); + if (false == buildOptions.empty()) + enc.appendSection(Elf::SHT_OPENCL_OPTIONS, Elf::SectionNamesOpenCl::buildOptions, ArrayRef::fromAny(buildOptions.data(), buildOptions.size())); + storage = enc.encode(); + } + static constexpr size_t mockDataSize = 0x10; + iOpenCL::SProgramBinaryHeader mockDevBinaryHeader = iOpenCL::SProgramBinaryHeader{iOpenCL::MAGIC_CL, 0, 0, 0, 0, 0, 0}; + std::vector storage; +}; \ No newline at end of file