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 <kacper.nowak@intel.com>
This commit is contained in:
Kacper Nowak
2022-01-14 15:39:43 +00:00
committed by Compute-Runtime-Automation
parent 59683ec491
commit fc224202d6
11 changed files with 275 additions and 32 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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<const uint8_t> strings = {reinterpret_cast<const uint8_t *>(buildInfos[rootDeviceIndex].constStringSectionData.initData),
buildInfos[rootDeviceIndex].constStringSectionData.size};
std::vector<std::pair<std::string_view, NEO::GraphicsAllocation *>> 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<const uint8_t>(reinterpret_cast<const uint8_t *>(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<const uint8_t>(reinterpret_cast<const uint8_t *>(buildInfos[rootDeviceIndex].unpackedDeviceBinary.get()), buildInfos[rootDeviceIndex].unpackedDeviceBinarySize);
if (isDeviceBinaryFormat<DeviceBinaryFormat::Zebin>(refBin)) {
createDebugZebin(rootDeviceIndex);
} else {
processDebugData(rootDeviceIndex);
}
}
} // namespace NEO

View File

@ -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<char[]> packedDeviceBinary;
size_t packedDeviceBinarySize = 0U;
ProgramInfo::GlobalSurfaceInfo constStringSectionData;
};
std::vector<BuildInfo> buildInfos;

View File

@ -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)

View File

@ -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<MockProgram>(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>();
kernelInfo->kernelDescriptor.kernelMetadata.kernelName = kernelName;
mockAlloc = std::make_unique<MockGraphicsAllocation>();
kernelInfo->kernelAllocation = mockAlloc.get();
program->addKernelInfo(kernelInfo.get(), rootDeviceIndex);
globalSurface = std::make_unique<MockBuffer>();
constantSurface = std::make_unique<MockBuffer>();
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<MockProgramWithDebugDataCreation>(toClDeviceVector(*pClDevice));
}
void ProgramWithDebugDataCreationFixture::TearDown() {
ProgramWithZebinFixture::TearDown();
}

View File

@ -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<MockProgram> program;
std::unique_ptr<KernelInfo> kernelInfo;
std::unique_ptr<MockGraphicsAllocation> mockAlloc;
std::unique_ptr<MockBuffer> globalSurface;
std::unique_ptr<MockBuffer> 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<MockProgramWithDebugDataCreation> programWithDebugDataCreation;
void SetUp() override;
void TearDown() override;
};

View File

@ -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 <memory>
using namespace NEO;
TEST_F(ProgramWithZebinFixture, givenNoZebinThenSegmentsAreEmpty) {
auto segments = program->getZebinSegments(pClDevice->getRootDeviceIndex());
EXPECT_EQ(std::numeric_limits<uintptr_t>::max(), segments.constData.address);
EXPECT_TRUE(segments.constData.data.empty());
EXPECT_EQ(std::numeric_limits<uintptr_t>::max(), segments.varData.address);
EXPECT_TRUE(segments.varData.data.empty());
EXPECT_EQ(std::numeric_limits<uintptr_t>::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<uintptr_t>(alloc->getGpuAddressToPatch()), segment.address);
EXPECT_EQ(reinterpret_cast<uint8_t *>(alloc->getUnderlyingBuffer()), segment.data.begin());
EXPECT_EQ(static_cast<size_t>(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<uintptr_t>(program->buildInfos[rootDeviceIndex].constStringSectionData.initData), segments.stringData.address);
EXPECT_EQ(reinterpret_cast<const uint8_t *>(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);
}