mirror of
https://github.com/intel/compute-runtime.git
synced 2026-01-05 09:09:04 +08:00
Add implementation of module dynamic link
Change-Id: I80c9ed1b5f6b0243e89515c393d89c4f86e5d83a Signed-off-by: Mateusz Jablonski <mateusz.jablonski@intel.com>
This commit is contained in:
committed by
sys_ocldev
parent
9bced7da37
commit
92aef012d9
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user