Add implementation of module dynamic link

Change-Id: I80c9ed1b5f6b0243e89515c393d89c4f86e5d83a
Signed-off-by: Mateusz Jablonski <mateusz.jablonski@intel.com>
This commit is contained in:
Mateusz Jablonski
2020-07-14 15:40:00 +02:00
committed by sys_ocldev
parent 9bced7da37
commit 92aef012d9
9 changed files with 170 additions and 34 deletions

View File

@@ -678,6 +678,9 @@ ze_result_t KernelImp::initialize(const ze_kernel_desc_t *desc) {
for (auto &alloc : kernelImmData->getResidencyContainer()) {
residencyContainer.push_back(alloc);
}
for (auto &alloc : module->getImportedSymbolAllocations()) {
residencyContainer.push_back(alloc);
}
return ZE_RESULT_SUCCESS;
}

View File

@@ -13,6 +13,7 @@
#include "level_zero/core/source/module/module_build_log.h"
#include <level_zero/ze_api.h>
#include <set>
#include <vector>
struct _ze_module_handle_t {};
@@ -44,6 +45,7 @@ struct Module : _ze_module_handle_t {
virtual const std::vector<std::unique_ptr<KernelImmutableData>> &getKernelImmutableDataVector() const = 0;
virtual uint32_t getMaxGroupSize() const = 0;
virtual bool isDebugEnabled() const = 0;
virtual const std::set<NEO::GraphicsAllocation *> &getImportedSymbolAllocations() const = 0;
Module() = default;
Module(const Module &) = delete;

View File

@@ -404,6 +404,20 @@ ze_result_t ModuleImp::getDebugInfo(size_t *pDebugDataSize, uint8_t *pDebugData)
return ZE_RESULT_SUCCESS;
}
void ModuleImp::copyPatchedSegments(const NEO::Linker::PatchableSegments &isaSegmentsForPatching) {
if (this->translationUnit->programInfo.linkerInput && this->translationUnit->programInfo.linkerInput->getTraits().requiresPatchingOfInstructionSegments) {
for (const auto &kernelImmData : this->kernelImmDatas) {
if (nullptr == kernelImmData->getIsaGraphicsAllocation()) {
continue;
}
auto segmentId = &kernelImmData - &this->kernelImmDatas[0];
this->device->getDriverHandle()->getMemoryManager()->copyMemoryToAllocation(kernelImmData->getIsaGraphicsAllocation(),
isaSegmentsForPatching[segmentId].hostPointer,
isaSegmentsForPatching[segmentId].segmentSize);
}
}
}
bool ModuleImp::linkBinary() {
using namespace NEO;
if (this->translationUnit->programInfo.linkerInput == nullptr) {
@@ -442,7 +456,6 @@ bool ModuleImp::linkBinary() {
}
}
Linker::UnresolvedExternals unresolvedExternalsInfo;
auto linkStatus = linker.link(globals, constants, exportedFunctions,
globalsForPatching, constantsForPatching,
isaSegmentsForPatching, unresolvedExternalsInfo, this->device->getNEODevice(),
@@ -459,16 +472,8 @@ bool ModuleImp::linkBinary() {
moduleBuildLog->appendString(error.c_str(), error.size());
}
return LinkingStatus::LinkedPartially == linkStatus;
} else if (this->translationUnit->programInfo.linkerInput->getTraits().requiresPatchingOfInstructionSegments) {
for (const auto &kernelImmData : this->kernelImmDatas) {
if (nullptr == kernelImmData->getIsaGraphicsAllocation()) {
continue;
}
auto segmentId = &kernelImmData - &this->kernelImmDatas[0];
this->device->getDriverHandle()->getMemoryManager()->copyMemoryToAllocation(kernelImmData->getIsaGraphicsAllocation(),
isaSegmentsForPatching[segmentId].hostPointer,
isaSegmentsForPatching[segmentId].segmentSize);
}
} else {
copyPatchedSegments(isaSegmentsForPatching);
}
DBG_LOG(PrintRelocations, NEO::constructRelocationsDebugMessage(this->symbols));
isFullyLinked = true;
@@ -552,7 +557,47 @@ void ModuleImp::verifyDebugCapabilities() {
ze_result_t ModuleImp::performDynamicLink(uint32_t numModules,
ze_module_handle_t *phModules,
ze_module_build_log_handle_t *phLinkLog) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
for (auto i = 0u; i < numModules; i++) {
auto moduleId = static_cast<ModuleImp *>(Module::fromHandle(phModules[i]));
if (moduleId->isFullyLinked) {
continue;
}
NEO::Linker::PatchableSegments isaSegmentsForPatching;
std::vector<std::vector<char>> patchedIsaTempStorage;
uint32_t numPatchedSymbols = 0u;
if (moduleId->translationUnit->programInfo.linkerInput && moduleId->translationUnit->programInfo.linkerInput->getTraits().requiresPatchingOfInstructionSegments) {
patchedIsaTempStorage.reserve(moduleId->kernelImmDatas.size());
for (const auto &kernelInfo : moduleId->translationUnit->programInfo.kernelInfos) {
auto &kernHeapInfo = kernelInfo->heapInfo;
const char *originalIsa = reinterpret_cast<const char *>(kernHeapInfo.pKernelHeap);
patchedIsaTempStorage.push_back(std::vector<char>(originalIsa, originalIsa + kernHeapInfo.KernelHeapSize));
isaSegmentsForPatching.push_back(NEO::Linker::PatchableSegment{patchedIsaTempStorage.rbegin()->data(), kernHeapInfo.KernelHeapSize});
}
for (const auto &unresolvedExternal : moduleId->unresolvedExternalsInfo) {
for (auto i = 0u; i < numModules; i++) {
auto moduleHandle = static_cast<ModuleImp *>(Module::fromHandle(phModules[i]));
auto symbolIt = moduleHandle->symbols.find(unresolvedExternal.unresolvedRelocation.symbolName);
if (symbolIt != moduleHandle->symbols.end()) {
auto relocAddress = ptrOffset(isaSegmentsForPatching[unresolvedExternal.instructionsSegmentId].hostPointer,
static_cast<uintptr_t>(unresolvedExternal.unresolvedRelocation.offset));
NEO::Linker::patchAddress(relocAddress, symbolIt->second, unresolvedExternal.unresolvedRelocation);
numPatchedSymbols++;
moduleId->importedSymbolAllocations.insert(moduleHandle->exportedFunctionsSurface);
break;
}
}
}
}
if (numPatchedSymbols != moduleId->unresolvedExternalsInfo.size()) {
return ZE_RESULT_ERROR_MODULE_LINK_FAILURE;
}
moduleId->copyPatchedSegments(isaSegmentsForPatching);
moduleId->isFullyLinked = true;
}
return ZE_RESULT_SUCCESS;
}
bool moveBuildOption(std::string &dstOptionsSet, std::string &srcOptionSet, NEO::ConstStringRef dstOptionName, NEO::ConstStringRef srcOptionName) {

View File

@@ -107,7 +107,10 @@ struct ModuleImp : public Module {
return this->translationUnit.get();
}
const std::set<NEO::GraphicsAllocation *> &getImportedSymbolAllocations() const override { return importedSymbolAllocations; }
protected:
void copyPatchedSegments(const NEO::Linker::PatchableSegments &isaSegmentsForPatching);
void verifyDebugCapabilities();
Device *device = nullptr;
PRODUCT_FAMILY productFamily{};
@@ -119,6 +122,8 @@ struct ModuleImp : public Module {
NEO::Linker::RelocatedSymbolsMap symbols;
bool debugEnabled = false;
bool isFullyLinked = false;
NEO::Linker::UnresolvedExternals unresolvedExternalsInfo{};
std::set<NEO::GraphicsAllocation *> importedSymbolAllocations{};
};
bool moveBuildOption(std::string &dstOptionsSet, std::string &srcOptionSet, NEO::ConstStringRef dstOptionName, NEO::ConstStringRef srcOptionName);

View File

@@ -25,6 +25,7 @@ struct WhiteBox<::L0::KernelImmutableData> : public ::L0::KernelImmutableData {
using ::L0::KernelImmutableData::device;
using ::L0::KernelImmutableData::isaGraphicsAllocation;
using ::L0::KernelImmutableData::kernelDescriptor;
using ::L0::KernelImmutableData::KernelImmutableData;
using ::L0::KernelImmutableData::privateMemoryGraphicsAllocation;
using ::L0::KernelImmutableData::residencyContainer;

View File

@@ -24,7 +24,10 @@ struct WhiteBox<::L0::Module> : public ::L0::ModuleImp {
using BaseClass::BaseClass;
using BaseClass::device;
using BaseClass::isFullyLinked;
using BaseClass::kernelImmDatas;
using BaseClass::symbols;
using BaseClass::translationUnit;
using BaseClass::unresolvedExternalsInfo;
};
using Module = WhiteBox<::L0::Module>;

View File

@@ -7,6 +7,7 @@
#include "shared/test/unit_test/compiler_interface/linker_mock.h"
#include "opencl/source/program/kernel_info.h"
#include "test.h"
#include "level_zero/core/source/context/context.h"
@@ -218,19 +219,92 @@ HWTEST_F(ModuleLinkingTest, givenNotFullyLinkedModuleWhenCreatingKernelThenError
EXPECT_EQ(ZE_RESULT_ERROR_MODULE_BUILD_FAILURE, retVal);
}
using ModuleDynamicLinkTests = Test<ModuleFixture>;
struct ModuleDynamicLinkTests : public Test<ModuleFixture> {
void SetUp() override {
Test<ModuleFixture>::SetUp();
module0 = std::make_unique<Module>(device, nullptr);
module1 = std::make_unique<Module>(device, nullptr);
}
std::unique_ptr<Module> module0;
std::unique_ptr<Module> module1;
};
HWTEST_F(ModuleDynamicLinkTests, givenCallToDynamicLinkThenUnsupportedFeatureIsReturned) {
auto module0 = new Module(device, nullptr);
auto module1 = new Module(device, nullptr);
TEST_F(ModuleDynamicLinkTests, givenCallToDynamicLinkOnModulesWithoutUnresolvedSymbolsThenSuccessIsReturned) {
std::vector<ze_module_handle_t> hModules = {module0->toHandle(), module1->toHandle()};
ze_result_t res = module0->performDynamicLink(2, hModules.data(), nullptr);
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
}
TEST_F(ModuleDynamicLinkTests, givenModuleWithUnresolvedSymbolsNotPresentInOtherModulesWhenDynamicLinkThenLinkFailureIsReturned) {
NEO::Linker::RelocationInfo unresolvedRelocation;
unresolvedRelocation.symbolName = "unresolved";
module0->unresolvedExternalsInfo.push_back({unresolvedRelocation});
std::vector<ze_module_handle_t> hModules = {module0->toHandle(), module1->toHandle()};
ze_result_t res = module0->performDynamicLink(2, hModules.data(), nullptr);
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, res);
delete module0;
delete module1;
EXPECT_EQ(ZE_RESULT_ERROR_MODULE_LINK_FAILURE, res);
}
TEST_F(ModuleDynamicLinkTests, whenModuleIsAlreadyLinkedThenThereIsNoSymbolsVerification) {
NEO::Linker::RelocationInfo unresolvedRelocation;
unresolvedRelocation.symbolName = "unresolved";
module0->unresolvedExternalsInfo.push_back({unresolvedRelocation});
module0->isFullyLinked = true;
std::vector<ze_module_handle_t> hModules = {module0->toHandle(), module1->toHandle()};
ze_result_t res = module0->performDynamicLink(2, hModules.data(), nullptr);
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
}
TEST_F(ModuleDynamicLinkTests, givenModuleWithUnresolvedSymbolWhenTheOtherModuleDefinesTheSymbolThenTheSegmentIsPatched) {
uint64_t gpuAddress = 0x12345;
uint32_t offset = 0x20;
NEO::Linker::RelocationInfo unresolvedRelocation;
unresolvedRelocation.symbolName = "unresolved";
unresolvedRelocation.offset = offset;
unresolvedRelocation.type = NEO::Linker::RelocationInfo::Type::Address;
NEO::Linker::UnresolvedExternal unresolvedExternal;
unresolvedExternal.unresolvedRelocation = unresolvedRelocation;
NEO::SymbolInfo symbolInfo{};
NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress};
char kernelHeap[MemoryConstants::pageSize] = {};
auto kernelInfo = std::make_unique<NEO::KernelInfo>();
kernelInfo->heapInfo.pKernelHeap = kernelHeap;
kernelInfo->heapInfo.KernelHeapSize = MemoryConstants::pageSize;
module0->getTranslationUnit()->programInfo.kernelInfos.push_back(kernelInfo.release());
auto linkerInput = std::make_unique<::WhiteBox<NEO::LinkerInput>>();
linkerInput->traits.requiresPatchingOfInstructionSegments = true;
module0->getTranslationUnit()->programInfo.linkerInput = std::move(linkerInput);
module0->unresolvedExternalsInfo.push_back({unresolvedRelocation});
module0->unresolvedExternalsInfo[0].instructionsSegmentId = 0u;
auto kernelImmData = std::make_unique<WhiteBox<::L0::KernelImmutableData>>(device);
kernelImmData->isaGraphicsAllocation.reset(neoDevice->getMemoryManager()->allocateGraphicsMemoryWithProperties(
{device->getRootDeviceIndex(), MemoryConstants::pageSize, NEO::GraphicsAllocation::AllocationType::KERNEL_ISA, neoDevice->getDeviceBitfield()}));
auto isaPtr = kernelImmData->getIsaGraphicsAllocation()->getUnderlyingBuffer();
module0->kernelImmDatas.push_back(std::move(kernelImmData));
module1->symbols[unresolvedRelocation.symbolName] = relocatedSymbol;
std::vector<ze_module_handle_t> hModules = {module0->toHandle(), module1->toHandle()};
ze_result_t res = module0->performDynamicLink(2, hModules.data(), nullptr);
EXPECT_EQ(ZE_RESULT_SUCCESS, res);
EXPECT_EQ(gpuAddress, *reinterpret_cast<uint64_t *>(ptrOffset(isaPtr, offset)));
}
class MultiDeviceModuleSetArgBufferTest : public MultiDeviceModuleFixture, public ::testing::Test {
public:
void SetUp() override {