Zebin: Add support for querying device globals by host name

This commit adds support for querying global pointers via decorated
names passed in zeInfo.
Related-To: NEO-6734
Signed-off-by: Kacper Nowak <kacper.nowak@intel.com>
This commit is contained in:
Kacper Nowak
2022-02-23 11:48:31 +00:00
committed by Compute-Runtime-Automation
parent 999c6424a4
commit 38086029ed
11 changed files with 289 additions and 8 deletions

View File

@@ -543,6 +543,9 @@ bool ModuleImp::initialize(const ze_module_desc_t *desc, NEO::Device *neoDevice)
success = this->linkBinary();
success &= populateHostGlobalSymbolsMap(this->translationUnit->programInfo.globalsDeviceToHostNameMap);
this->updateBuildLog(neoDevice);
if (debugEnabled) {
passDebugData();
}
@@ -815,15 +818,25 @@ ze_result_t ModuleImp::getFunctionPointer(const char *pFunctionName, void **pfnF
}
ze_result_t ModuleImp::getGlobalPointer(const char *pGlobalName, size_t *pSize, void **pPtr) {
auto symbolIt = symbols.find(pGlobalName);
if ((symbolIt == symbols.end()) || (symbolIt->second.symbol.segment == NEO::SegmentType::Instructions)) {
uint64_t address;
size_t size;
if (hostGlobalSymbolsMap.count(pGlobalName) == 1) {
address = hostGlobalSymbolsMap[pGlobalName].address;
size = hostGlobalSymbolsMap[pGlobalName].size;
} else if (symbols.count(pGlobalName) == 1) {
if (symbols[pGlobalName].symbol.segment == NEO::SegmentType::Instructions) {
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
}
address = symbols[pGlobalName].gpuAddress;
size = symbols[pGlobalName].symbol.size;
} else {
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
}
if (pPtr) {
*pPtr = reinterpret_cast<void *>(symbolIt->second.gpuAddress);
*pPtr = reinterpret_cast<void *>(address);
}
if (pSize) {
*pSize = symbolIt->second.symbol.size;
*pSize = size;
}
return ZE_RESULT_SUCCESS;
}
@@ -992,6 +1005,29 @@ ze_result_t ModuleImp::performDynamicLink(uint32_t numModules,
return ZE_RESULT_SUCCESS;
}
bool ModuleImp::populateHostGlobalSymbolsMap(std::unordered_map<std::string, std::string> &devToHostNameMapping) {
bool retVal = true;
for (auto &[devName, hostName] : devToHostNameMapping) {
auto findSymbolRes = symbols.find(devName);
if (findSymbolRes != symbols.end()) {
auto symbol = findSymbolRes->second;
if (isDataSegment(symbol.symbol.segment)) {
GlobalSymbol hostSymbol;
hostSymbol.address = symbol.gpuAddress;
hostSymbol.size = symbol.symbol.size;
hostGlobalSymbolsMap[hostName] = hostSymbol;
} else {
translationUnit->buildLog.append("Error: Symbol with given device name: " + devName + " is not in globals* segment.\n");
retVal = false;
}
} else {
translationUnit->buildLog.append("Error: No symbol found with given device name: " + devName + ".\n");
retVal = false;
}
}
return retVal;
}
void ModuleImp::registerElfInDebuggerL0() {
if (device->getL0Debugger() == nullptr) {
return;

View File

@@ -147,6 +147,7 @@ struct ModuleImp : public Module {
void passDebugData();
void createDebugZebin();
void registerElfInDebuggerL0();
bool populateHostGlobalSymbolsMap(std::unordered_map<std::string, std::string> &devToHostNameMapping);
Device *device = nullptr;
PRODUCT_FAMILY productFamily{};
@@ -156,6 +157,14 @@ struct ModuleImp : public Module {
uint32_t maxGroupSize = 0U;
std::vector<std::unique_ptr<KernelImmutableData>> kernelImmDatas;
NEO::Linker::RelocatedSymbolsMap symbols;
struct GlobalSymbol {
uintptr_t address = std::numeric_limits<uintptr_t>::max();
size_t size = 0U;
};
std::unordered_map<std::string, GlobalSymbol> hostGlobalSymbolsMap;
bool debugEnabled = false;
bool isFullyLinked = false;
bool allocatePrivateMemoryPerDispatch = true;

View File

@@ -76,6 +76,8 @@ struct MockModule : public L0::ModuleImp {
using ModuleImp::debugEnabled;
using ModuleImp::debugModuleHandle;
using ModuleImp::kernelImmDatas;
using ModuleImp::populateHostGlobalSymbolsMap;
using ModuleImp::symbols;
using ModuleImp::translationUnit;
MockModule(L0::Device *device,

View File

@@ -2095,6 +2095,75 @@ TEST_F(ModuleTest, givenModuleWithSymbolWhenGettingGlobalPointerWithNullptrInput
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
}
TEST_F(ModuleTest, givenModuleWithGlobalSymbolMapWhenGettingGlobalPointerByHostSymbolNameExistingInMapThenCorrectPointerAndSuccessIsReturned) {
std::unordered_map<std::string, std::string> mapping;
mapping["devSymbolOne"] = "hostSymbolOne";
mapping["devSymbolTwo"] = "hostSymbolTwo";
size_t symbolsSize = 1024u;
uint64_t globalVarGpuAddress = 0x12345000;
NEO::SymbolInfo globalVariablesSymbolInfo{0, static_cast<uint32_t>(symbolsSize), SegmentType::GlobalVariables};
NEO::Linker::RelocatedSymbol globalVariablesRelocatedSymbol{globalVariablesSymbolInfo, globalVarGpuAddress};
uint64_t globalConstGpuAddress = 0x12347000;
NEO::SymbolInfo globalConstantsSymbolInfo{0, static_cast<uint32_t>(symbolsSize), SegmentType::GlobalConstants};
NEO::Linker::RelocatedSymbol globalConstansRelocatedSymbol{globalConstantsSymbolInfo, globalConstGpuAddress};
auto module0 = std::make_unique<MockModule>(device, nullptr, ModuleType::User);
module0->symbols["devSymbolOne"] = globalVariablesRelocatedSymbol;
module0->symbols["devSymbolTwo"] = globalConstansRelocatedSymbol;
auto success = module0->populateHostGlobalSymbolsMap(mapping);
EXPECT_TRUE(success);
EXPECT_TRUE(module0->getTranslationUnit()->buildLog.empty());
size_t size = 0;
void *ptr = nullptr;
auto result = module0->getGlobalPointer("hostSymbolOne", &size, &ptr);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(symbolsSize, size);
EXPECT_EQ(globalVarGpuAddress, reinterpret_cast<uint64_t>(ptr));
result = module0->getGlobalPointer("hostSymbolTwo", &size, &ptr);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(symbolsSize, size);
EXPECT_EQ(globalConstGpuAddress, reinterpret_cast<uint64_t>(ptr));
}
TEST_F(ModuleTest, givenModuleWithGlobalSymbolsMapWhenPopulatingMapWithSymbolNotFoundInRelocatedSymbolsMapThenPrintErrorStringAndReturnFalse) {
std::unordered_map<std::string, std::string> mapping;
std::string notFoundDevSymbolName = "anotherDevSymbolOne";
mapping[notFoundDevSymbolName] = "anotherHostSymbolOne";
auto module0 = std::make_unique<MockModule>(device, nullptr, ModuleType::User);
EXPECT_EQ(0u, module0->symbols.count(notFoundDevSymbolName));
auto result = module0->populateHostGlobalSymbolsMap(mapping);
EXPECT_FALSE(result);
std::string expectedErrorOutput = "Error: No symbol found with given device name: " + notFoundDevSymbolName + ".\n";
EXPECT_STREQ(expectedErrorOutput.c_str(), module0->getTranslationUnit()->buildLog.c_str());
}
TEST_F(ModuleTest, givenModuleWithGlobalSymbolsMapWhenPopulatingMapWithSymbolFromIncorrectSegmentThenPrintErrorStringAndReturnFalse) {
std::unordered_map<std::string, std::string> mapping;
std::string incorrectDevSymbolName = "incorrectSegmentDevSymbolOne";
mapping[incorrectDevSymbolName] = "incorrectSegmentHostSymbolOne";
size_t symbolSize = 1024u;
uint64_t gpuAddress = 0x12345000;
NEO::SymbolInfo symbolInfo{0, static_cast<uint32_t>(symbolSize), SegmentType::Instructions};
NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress};
auto module0 = std::make_unique<MockModule>(device, nullptr, ModuleType::User);
module0->symbols[incorrectDevSymbolName] = relocatedSymbol;
auto result = module0->populateHostGlobalSymbolsMap(mapping);
EXPECT_FALSE(result);
std::string expectedErrorOutput = "Error: Symbol with given device name: " + incorrectDevSymbolName + " is not in globals* segment.\n";
EXPECT_STREQ(expectedErrorOutput.c_str(), module0->getTranslationUnit()->buildLog.c_str());
}
using ModuleTests = Test<DeviceFixture>;
TEST_F(ModuleTests, whenCopyingPatchedSegmentsThenAllocationsAreSetWritableForTbxAndAub) {
auto pModule = std::make_unique<Module>(device, nullptr, ModuleType::User);

View File

@@ -242,5 +242,8 @@ std::string constructRelocationsDebugMessage(const Linker::RelocatedSymbolsMap &
constexpr bool shouldIgnoreRelocation(const LinkerInput::RelocationInfo &relocation) {
return LinkerInput::RelocationInfo::Type::PerThreadPayloadOffset == relocation.type;
}
inline bool isDataSegment(const SegmentType &segment) {
return segment == SegmentType::GlobalConstants || segment == SegmentType::GlobalVariables;
}
} // namespace NEO

View File

@@ -157,6 +157,7 @@ namespace ZebinKernelMetadata {
namespace Tags {
static constexpr ConstStringRef kernels("kernels");
static constexpr ConstStringRef version("version");
static constexpr ConstStringRef globalHostAccessTable("global_host_access_table");
namespace Kernel {
static constexpr ConstStringRef name("name");
static constexpr ConstStringRef executionEnv("execution_env");
@@ -278,6 +279,10 @@ static constexpr ConstStringRef hasNonKernelArgStore("has_non_kernel_arg_store")
static constexpr ConstStringRef hasNonKernelArgAtomic("has_non_kernel_arg_atomic");
} // namespace ExperimentalProperties
} // namespace Kernel
namespace GlobalHostAccessTable {
static constexpr ConstStringRef deviceName("device_name");
static constexpr ConstStringRef hostName("host_name");
} // namespace GlobalHostAccessTable
} // namespace Tags
namespace Types {
@@ -529,6 +534,12 @@ struct PerThreadMemoryBufferBaseT {
} // namespace Kernel
namespace GlobalHostAccessTable {
struct globalHostAccessTableT {
std::string deviceName;
std::string hostName;
};
} // namespace GlobalHostAccessTable
} // namespace Types
} // namespace ZebinKernelMetadata

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2021 Intel Corporation
* Copyright (C) 2020-2022 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -664,6 +664,16 @@ inline bool YamlParser::readValueChecked<bool>(const Node &node, bool &outValue)
return true;
}
template <>
inline bool YamlParser::readValueChecked<std::string>(const Node &node, std::string &outValue) const {
const auto &token = tokens[node.value];
if (Token::Type::LiteralString != token.traits.type) {
return false;
}
outValue.resize(token.len);
std::copy(token.pos, token.pos + token.len, outValue.begin());
return true;
}
} // namespace Yaml
} // namespace NEO

View File

@@ -645,6 +645,28 @@ DecodeError readZeInfoPerThreadMemoryBuffers(const NEO::Yaml::YamlParser &parser
return validBuffer ? DecodeError::Success : DecodeError::InvalidBinary;
}
DecodeError readZeInfoGlobalHostAceessTable(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
ZeInfoGlobalHostAccessTables &outDeviceNameToHostTable,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning) {
bool validTable = true;
for (const auto &globalHostAccessNameNd : parser.createChildrenRange(node)) {
outDeviceNameToHostTable.resize(outDeviceNameToHostTable.size() + 1);
for (const auto &globalHostAccessNameMemberNd : parser.createChildrenRange(globalHostAccessNameNd)) {
auto &globalHostAccessMetadata = *outDeviceNameToHostTable.rbegin();
auto key = parser.readKey(globalHostAccessNameMemberNd);
if (NEO::Elf::ZebinKernelMetadata::Tags::GlobalHostAccessTable::deviceName == key) {
validTable &= readZeInfoValueChecked(parser, globalHostAccessNameMemberNd, globalHostAccessMetadata.deviceName, context, outErrReason);
} else if (NEO::Elf::ZebinKernelMetadata::Tags::GlobalHostAccessTable::hostName == key) {
validTable &= readZeInfoValueChecked(parser, globalHostAccessNameMemberNd, globalHostAccessMetadata.hostName, context, outErrReason);
} else {
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + key.str() + "\" for payload argument in context of " + context.str() + "\n");
}
}
}
return validTable ? DecodeError::Success : DecodeError::InvalidBinary;
}
template <typename ElSize, size_t Len>
bool setVecArgIndicesBasedOnSize(CrossThreadDataOffset (&vec)[Len], size_t vecSize, CrossThreadDataOffset baseOffset) {
switch (vecSize) {
@@ -1276,6 +1298,7 @@ DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo
UniqueNode kernelsSectionNodes;
UniqueNode versionSectionNodes;
UniqueNode globalHostAccessTableNodes;
for (const auto &globalScopeNd : yamlParser.createChildrenRange(*yamlParser.getRoot())) {
auto key = yamlParser.readKey(globalScopeNd);
if (NEO::Elf::ZebinKernelMetadata::Tags::kernels == key) {
@@ -1284,8 +1307,12 @@ DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo
} else if (NEO::Elf::ZebinKernelMetadata::Tags::version == key) {
versionSectionNodes.push_back(&globalScopeNd);
continue;
} else if (NEO::Elf::ZebinKernelMetadata::Tags::globalHostAccessTable == key) {
globalHostAccessTableNodes.push_back(&globalScopeNd);
continue;
} else {
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + yamlParser.readKey(globalScopeNd).str() + "\" in global scope of " + NEO::Elf::SectionsNamesZebin::zeInfo.str() + "\n");
}
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + yamlParser.readKey(globalScopeNd).str() + "\" in global scope of " + NEO::Elf::SectionsNamesZebin::zeInfo.str() + "\n");
}
if (versionSectionNodes.size() > 1U) {
@@ -1330,6 +1357,17 @@ DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo
}
}
if (false == globalHostAccessTableNodes.empty()) {
ZeInfoGlobalHostAccessTables globalHostAccessMapping;
auto zeInfoErr = readZeInfoGlobalHostAceessTable(yamlParser, *globalHostAccessTableNodes[0], globalHostAccessMapping, "globalHostAccessTable", outErrReason, outWarning);
if (DecodeError::Success != zeInfoErr) {
return zeInfoErr;
}
for (auto it = globalHostAccessMapping.begin(); it != globalHostAccessMapping.end(); it++) {
dst.globalsDeviceToHostNameMap[it->deviceName] = it->hostName;
}
}
return DecodeError::Success;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2021 Intel Corporation
* Copyright (C) 2020-2022 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -100,6 +100,11 @@ DecodeError readZeInfoPerThreadMemoryBuffers(const NEO::Yaml::YamlParser &parser
ZeInfoPerThreadMemoryBuffers &outPerThreadMemoryBuffers,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning);
using ZeInfoGlobalHostAccessTables = StackVec<NEO::Elf::ZebinKernelMetadata::Types::GlobalHostAccessTable::globalHostAccessTableT, 32>;
DecodeError readZeInfoGlobalHostAceessTable(const NEO::Yaml::YamlParser &parser, const NEO::Yaml::Node &node,
ZeInfoGlobalHostAccessTables &outDeviceNameToHostTable,
ConstStringRef context,
std::string &outErrReason, std::string &outWarning);
NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Types::Kernel::PerThreadPayloadArgument::PerThreadPayloadArgumentBaseT &src, NEO::KernelDescriptor &dst, const uint32_t grfSize,
std::string &outErrReason, std::string &outWarning);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2021 Intel Corporation
* Copyright (C) 2020-2022 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -11,6 +11,7 @@
#include <cstddef>
#include <memory>
#include <unordered_map>
#include <vector>
namespace NEO {
@@ -39,6 +40,7 @@ struct ProgramInfo {
GlobalSurfaceInfo globalVariables;
GlobalSurfaceInfo globalStrings;
std::unique_ptr<LinkerInput> linkerInput;
std::unordered_map<std::string, std::string> globalsDeviceToHostNameMap;
std::vector<KernelInfo *> kernelInfos;
Elf::Elf<Elf::EI_CLASS_64> decodedElf;

View File

@@ -5145,4 +5145,100 @@ TEST_F(IntelGTNotesFixture, WhenValidatingTargetDeviceGivenValidTargetDeviceAndI
ASSERT_TRUE(outErrReason.empty());
EXPECT_FALSE(validateTargetDevice(elf, targetDevice));
}
TEST(PopulateGlobalDeviceHostNameMapping, givenValidZebinWithGlobalHostAccessTableSectionThenPopulateHostDeviceNameMapCorrectly) {
NEO::ConstStringRef zeinfo = R"===(
kernels:
- name : some_kernel
execution_env:
simd_size: 32
global_host_access_table:
- device_name: int_var
host_name: IntVarName
- device_name: bool_var
host_name: BoolVarName
)===";
ZebinTestData::ValidEmptyProgram zebin;
zebin.removeSection(NEO::Elf::SHT_ZEBIN::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo);
zebin.appendSection(NEO::Elf::SHT_ZEBIN::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo, ArrayRef<const uint8_t>::fromAny(zeinfo.data(), zeinfo.size()));
zebin.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::textPrefix.str() + "some_kernel", {});
NEO::ProgramInfo programInfo;
NEO::SingleDeviceBinary singleBinary;
singleBinary.deviceBinary = zebin.storage;
std::string decodeErrors;
std::string decodeWarnings;
auto error = NEO::decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(programInfo, singleBinary, decodeErrors, decodeWarnings);
EXPECT_EQ(NEO::DecodeError::Success, error);
EXPECT_TRUE(decodeErrors.empty()) << decodeErrors;
EXPECT_EQ(2u, programInfo.globalsDeviceToHostNameMap.size());
EXPECT_STREQ("IntVarName", programInfo.globalsDeviceToHostNameMap["int_var"].c_str());
EXPECT_STREQ("BoolVarName", programInfo.globalsDeviceToHostNameMap["bool_var"].c_str());
}
TEST(PopulateGlobalDeviceHostNameMapping, givenZebinWithGlobalHostAccessTableSectionAndInvalidValuesThenReturnInvalidBinaryError) {
std::vector<NEO::ConstStringRef> invalidZeInfos{R"===(
kernels:
- name : some_kernel
execution_env:
simd_size: 32
global_host_access_table:
- device_name: 2
host_name: HostSymboName
)===",
R"===(
kernels:
- name : some_kernel
execution_env:
simd_size: 32
global_host_access_table:
- device_name: DeviceSymbolName
host_name: 0xddd
)==="};
for (auto &zeInfo : invalidZeInfos) {
ZebinTestData::ValidEmptyProgram zebin;
zebin.removeSection(NEO::Elf::SHT_ZEBIN::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo);
zebin.appendSection(NEO::Elf::SHT_ZEBIN::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo, ArrayRef<const uint8_t>::fromAny(zeInfo.data(), zeInfo.size()));
zebin.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::textPrefix.str() + "some_kernel", {});
NEO::ProgramInfo programInfo;
NEO::SingleDeviceBinary singleBinary;
singleBinary.deviceBinary = zebin.storage;
std::string decodeErrors;
std::string decodeWarnings;
auto error = NEO::decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(programInfo, singleBinary, decodeErrors, decodeWarnings);
EXPECT_EQ(NEO::DecodeError::InvalidBinary, error);
}
}
TEST(PopulateGlobalDeviceHostNameMapping, givenZebinWithGlobalHostAccessTableSectionAndUnrecognizableKeyThenEmitWarning) {
NEO::ConstStringRef yaml = R"===(
kernels:
- name : some_kernel
execution_env:
simd_size: 32
global_host_access_table:
- device_name: int_var
host_name: IntVarName
banana_type: slight_curve
)===";
std::string parserErrors;
std::string parserWarnings;
NEO::Yaml::YamlParser parser;
bool success = parser.parse(yaml, parserErrors, parserWarnings);
ASSERT_TRUE(success);
auto &tableNode = *parser.findNodeWithKeyDfs("global_host_access_table");
std::string errors;
std::string warnings;
NEO::ZeInfoGlobalHostAccessTables tables;
auto err = NEO::readZeInfoGlobalHostAceessTable(parser, tableNode, tables, "global_host_access_table", errors, warnings);
EXPECT_EQ(NEO::DecodeError::Success, err);
EXPECT_TRUE(errors.empty()) << errors;
std::string expectedWarning("DeviceBinaryFormat::Zebin::.ze_info : Unknown entry \"banana_type\" for payload argument in context of global_host_access_table\n");
EXPECT_STREQ(expectedWarning.c_str(), warnings.c_str());
}