diff --git a/shared/source/device_binary_format/device_binary_format_ar.cpp b/shared/source/device_binary_format/device_binary_format_ar.cpp index 27db23641b..a785d4f70a 100644 --- a/shared/source/device_binary_format/device_binary_format_ar.cpp +++ b/shared/source/device_binary_format/device_binary_format_ar.cpp @@ -10,6 +10,9 @@ #include "shared/source/helpers/product_config_helper.h" #include "shared/source/helpers/string.h" +#include +#include + namespace NEO { void searchForBinary(Ar::Ar &archiveData, const ConstStringRef filter, Ar::ArFileEntryHeaderAndData *&matched) { for (auto &file : archiveData.files) { @@ -19,70 +22,112 @@ void searchForBinary(Ar::Ar &archiveData, const ConstStringRef filter, Ar::ArFil } } } - template <> bool isDeviceBinaryFormat(const ArrayRef binary) { return NEO::Ar::isAr(binary); } template <> -SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef archive, const ConstStringRef requestedProductAbbreviation, const TargetDevice &requestedTargetDevice, - std::string &outErrReason, std::string &outWarning) { +SingleDeviceBinary unpackSingleDeviceBinary(const ArrayRef archive, + const ConstStringRef requestedProductAbbreviation, + const TargetDevice &requestedTargetDevice, + std::string &outErrReason, + std::string &outWarning) { auto archiveData = NEO::Ar::decodeAr(archive, outErrReason, outWarning); if (nullptr == archiveData.magic) { return {}; } - std::string pointerSize = ((requestedTargetDevice.maxPointerSizeInBytes == 8) ? "64" : "32"); - std::string filterPointerSizeAndMajorMinorRevision = pointerSize + "." + ProductConfigHelper::parseMajorMinorRevisionValue(requestedTargetDevice.aotConfig); - std::string filterPointerSizeAndMajorMinor = pointerSize + "." + ProductConfigHelper::parseMajorMinorValue(requestedTargetDevice.aotConfig); - std::string filterPointerSizeAndPlatform = pointerSize + "." + requestedProductAbbreviation.str(); - std::string filterPointerSizeAndPlatformAndStepping = filterPointerSizeAndPlatform + "." + std::to_string(requestedTargetDevice.stepping); ConstStringRef filterGenericIrFileName{"generic_ir"}; - - Ar::ArFileEntryHeaderAndData *matchedFiles[5] = {}; - Ar::ArFileEntryHeaderAndData *&matchedPointerSizeAndMajorMinorRevision = matchedFiles[0]; - Ar::ArFileEntryHeaderAndData *&matchedPointerSizeAndPlatformAndStepping = matchedFiles[1]; - Ar::ArFileEntryHeaderAndData *&matchedPointerSizeAndMajorMinor = matchedFiles[2]; - Ar::ArFileEntryHeaderAndData *&matchedPointerSizeAndPlatform = matchedFiles[3]; - Ar::ArFileEntryHeaderAndData *&matchedGenericIr = matchedFiles[4]; - - searchForBinary(archiveData, ConstStringRef(filterPointerSizeAndMajorMinorRevision), matchedPointerSizeAndMajorMinorRevision); - searchForBinary(archiveData, ConstStringRef(filterPointerSizeAndPlatformAndStepping), matchedPointerSizeAndPlatformAndStepping); - searchForBinary(archiveData, ConstStringRef(filterPointerSizeAndMajorMinor), matchedPointerSizeAndMajorMinor); - searchForBinary(archiveData, ConstStringRef(filterPointerSizeAndPlatform), matchedPointerSizeAndPlatform); + Ar::ArFileEntryHeaderAndData *matchedGenericIr = nullptr; searchForBinary(archiveData, filterGenericIrFileName, matchedGenericIr); - std::string unpackErrors; - std::string unpackWarnings; - SingleDeviceBinary binaryForRecompilation = {}; - for (auto matchedFile : matchedFiles) { - if (nullptr == matchedFile) { + SingleDeviceBinary binaryForRecompilation{}; + + auto tryPlatform = [&](ConstStringRef platformAbbreviation) -> std::optional { + std::string pointerSize = ((requestedTargetDevice.maxPointerSizeInBytes == 8) ? "64" : "32"); + std::string filterPointerSizeAndMajorMinorRevision = pointerSize + "." + ProductConfigHelper::parseMajorMinorRevisionValue(requestedTargetDevice.aotConfig); + std::string filterPointerSizeAndMajorMinor = pointerSize + "." + ProductConfigHelper::parseMajorMinorValue(requestedTargetDevice.aotConfig); + std::string filterPointerSizeAndPlatform = pointerSize + "." + platformAbbreviation.str(); + std::string filterPointerSizeAndPlatformAndStepping = filterPointerSizeAndPlatform + "." + std::to_string(requestedTargetDevice.stepping); + + Ar::ArFileEntryHeaderAndData *matchedFiles[4] = {}; + Ar::ArFileEntryHeaderAndData *&matchedPointerSizeAndMajorMinorRevision = matchedFiles[0]; + Ar::ArFileEntryHeaderAndData *&matchedPointerSizeAndPlatformAndStepping = matchedFiles[1]; + Ar::ArFileEntryHeaderAndData *&matchedPointerSizeAndMajorMinor = matchedFiles[2]; + Ar::ArFileEntryHeaderAndData *&matchedPointerSizeAndPlatform = matchedFiles[3]; + + searchForBinary(archiveData, ConstStringRef(filterPointerSizeAndMajorMinorRevision), matchedPointerSizeAndMajorMinorRevision); + searchForBinary(archiveData, ConstStringRef(filterPointerSizeAndPlatformAndStepping), matchedPointerSizeAndPlatformAndStepping); + searchForBinary(archiveData, ConstStringRef(filterPointerSizeAndMajorMinor), matchedPointerSizeAndMajorMinor); + searchForBinary(archiveData, ConstStringRef(filterPointerSizeAndPlatform), matchedPointerSizeAndPlatform); + + std::string unpackErrors; + std::string unpackWarnings; + + for (auto matchedFile : matchedFiles) { + if (nullptr == matchedFile) { + continue; + } + auto unpacked = unpackSingleDeviceBinary(matchedFile->fileData, platformAbbreviation, + requestedTargetDevice, unpackErrors, unpackWarnings); + + if (!unpacked.deviceBinary.empty()) { + if ((matchedFile != matchedPointerSizeAndPlatformAndStepping) && + (matchedFile != matchedPointerSizeAndMajorMinorRevision)) { + outWarning = "Couldn't find perfectly matched binary in AR, using best usable"; + } + if (unpacked.intermediateRepresentation.empty() && matchedGenericIr) { + std::string irErrors, irWarnings; + auto genericIrResult = unpackSingleDeviceBinary(matchedGenericIr->fileData, platformAbbreviation, + requestedTargetDevice, irErrors, irWarnings); + if (!genericIrResult.intermediateRepresentation.empty()) { + unpacked.intermediateRepresentation = genericIrResult.intermediateRepresentation; + } + } + unpacked.packedTargetDeviceBinary = + ArrayRef(matchedFile->fileData.begin(), matchedFile->fileData.size()); + return unpacked; + } + + if (binaryForRecompilation.intermediateRepresentation.empty() && + !unpacked.intermediateRepresentation.empty()) { + binaryForRecompilation = unpacked; + } + } + return std::nullopt; + }; + + if (auto primary = tryPlatform(requestedProductAbbreviation); primary.has_value()) { + return *primary; + } + + auto compatibilityFallbackAbbreviations = + ProductConfigHelper::getCompatibilityFallbackProductAbbreviations(requestedProductAbbreviation.str()); + + for (const auto &compatAbbrev : compatibilityFallbackAbbreviations) { + if (compatAbbrev == requestedProductAbbreviation.str()) { continue; } - auto unpacked = unpackSingleDeviceBinary(matchedFile->fileData, requestedProductAbbreviation, requestedTargetDevice, unpackErrors, unpackWarnings); - if (false == unpacked.deviceBinary.empty()) { - if ((matchedFile != matchedPointerSizeAndPlatformAndStepping) && (matchedFile != matchedPointerSizeAndMajorMinorRevision)) { - outWarning = "Couldn't find perfectly matched binary in AR, using best usable"; - } - if (unpacked.intermediateRepresentation.empty() && matchedGenericIr) { - auto unpackedGenericIr = unpackSingleDeviceBinary(matchedGenericIr->fileData, requestedProductAbbreviation, requestedTargetDevice, unpackErrors, unpackWarnings); - if (!unpackedGenericIr.intermediateRepresentation.empty()) { - unpacked.intermediateRepresentation = unpackedGenericIr.intermediateRepresentation; - } - } - unpacked.packedTargetDeviceBinary = ArrayRef(matchedFile->fileData.begin(), matchedFile->fileData.size()); - return unpacked; - } - if (binaryForRecompilation.intermediateRepresentation.empty() && (false == unpacked.intermediateRepresentation.empty())) { - binaryForRecompilation = unpacked; + ConstStringRef compatRef{compatAbbrev}; + if (auto compatResult = tryPlatform(compatRef); compatResult.has_value()) { + return *compatResult; } } - if (false == binaryForRecompilation.intermediateRepresentation.empty()) { + if (!binaryForRecompilation.intermediateRepresentation.empty()) { return binaryForRecompilation; } + if (matchedGenericIr) { + std::string irErrors, irWarnings; + auto genericIrResult = unpackSingleDeviceBinary(matchedGenericIr->fileData, requestedProductAbbreviation, + requestedTargetDevice, irErrors, irWarnings); + if (!genericIrResult.intermediateRepresentation.empty()) { + return genericIrResult; + } + } + outErrReason = "Couldn't find matching binary in AR archive"; return {}; } diff --git a/shared/source/helpers/product_config_helper.cpp b/shared/source/helpers/product_config_helper.cpp index 997e4c18a5..0a0e1bc2a7 100644 --- a/shared/source/helpers/product_config_helper.cpp +++ b/shared/source/helpers/product_config_helper.cpp @@ -344,3 +344,41 @@ AOT::PRODUCT_CONFIG ProductConfigHelper::getProductConfigFromAcronym(const std:: } return AOT::UNKNOWN_ISA; } + +std::vector ProductConfigHelper::getCompatibilityFallbackProductAbbreviations(const std::string &requestedProductAbbreviation) { + std::vector result; + + AOT::PRODUCT_CONFIG requestedConfig = AOT::PRODUCT_CONFIG::UNKNOWN_ISA; + for (const auto &acronymEntry : AOT::deviceAcronyms) { + if (acronymEntry.first == requestedProductAbbreviation || + acronymEntry.first.rfind(requestedProductAbbreviation + "-", 0) == 0) { + requestedConfig = acronymEntry.second; + break; + } + } + if (requestedConfig == AOT::PRODUCT_CONFIG::UNKNOWN_ISA) { + return result; + } + + for (const auto &compatibilityEntry : AOT::compatibilityMapping) { + bool contains = std::find(compatibilityEntry.second.begin(), + compatibilityEntry.second.end(), + requestedConfig) != compatibilityEntry.second.end(); + if (!contains) { + continue; + } + for (const auto &acronymEntry : AOT::deviceAcronyms) { + if (acronymEntry.second == compatibilityEntry.first) { + std::string name = acronymEntry.first; + if (auto pos = name.find('-'); pos != std::string::npos) { + name = name.substr(0, pos); + } + if (std::find(result.begin(), result.end(), name) == result.end()) { + result.push_back(name); + } + break; + } + } + } + return result; +} diff --git a/shared/source/helpers/product_config_helper.h b/shared/source/helpers/product_config_helper.h index 320c8f823b..00e28f9d46 100644 --- a/shared/source/helpers/product_config_helper.h +++ b/shared/source/helpers/product_config_helper.h @@ -64,6 +64,7 @@ struct ProductConfigHelper { static NEO::ConstStringRef getAcronymFromARelease(AOT::RELEASE release); static uint32_t getProductConfigFromVersionValue(const std::string &device); static AOT::PRODUCT_CONFIG getProductConfigFromAcronym(const std::string &device); + static std::vector getCompatibilityFallbackProductAbbreviations(const std::string &requestedProductAbbreviation); static bool compareConfigs(DeviceAotInfo deviceAotInfo0, DeviceAotInfo deviceAotInfo1); diff --git a/shared/test/unit_test/device_binary_format/device_binary_format_ar_tests.cpp b/shared/test/unit_test/device_binary_format/device_binary_format_ar_tests.cpp index 7eeab44d82..ffa574d594 100644 --- a/shared/test/unit_test/device_binary_format/device_binary_format_ar_tests.cpp +++ b/shared/test/unit_test/device_binary_format/device_binary_format_ar_tests.cpp @@ -613,3 +613,47 @@ TEST(UnpackSingleDeviceBinaryAr, WhenCouldNotFindBinaryWithRightPointerSizeThenU EXPECT_TRUE(unpackWarnings.empty()) << unpackWarnings; EXPECT_STREQ("Couldn't find matching binary in AR archive", unpackErrors.c_str()); } + +TEST(UnpackSingleDeviceBinaryAr, WhenRequestedDeviceHasCompatibleFallbackThenUseFallbackDevice) { + PatchTokensTestData::ValidEmptyProgram programTokens; + + std::string requestedProduct = "lnl"; + std::string fallbackProduct = "bmg"; + + auto compatibleDevices = ProductConfigHelper::getCompatibilityFallbackProductAbbreviations(requestedProduct); + + if (compatibleDevices.empty() || + std::find(compatibleDevices.begin(), compatibleDevices.end(), fallbackProduct) == compatibleDevices.end()) { + GTEST_SKIP(); + } + + NEO::Ar::ArEncoder encoder{true}; + std::string pointerSize = (programTokens.header->GPUPointerSizeInBytes == 4) ? "32" : "64"; + + ASSERT_TRUE(encoder.appendFileEntry(pointerSize + "." + fallbackProduct, programTokens.storage)); + + NEO::TargetDevice target; + target.coreFamily = static_cast(programTokens.header->Device); + target.stepping = programTokens.header->SteppingId; + target.maxPointerSizeInBytes = programTokens.header->GPUPointerSizeInBytes; + + auto arData = encoder.encode(); + std::string unpackErrors; + std::string unpackWarnings; + + auto unpacked = NEO::unpackSingleDeviceBinary(arData, requestedProduct, target, unpackErrors, unpackWarnings); + + EXPECT_TRUE(unpackErrors.empty()); + EXPECT_FALSE(unpacked.deviceBinary.empty()); + EXPECT_EQ(NEO::DeviceBinaryFormat::patchtokens, unpacked.format); + + EXPECT_STREQ("Couldn't find perfectly matched binary in AR, using best usable", unpackWarnings.c_str()); +} + +TEST(ProductConfigHelper, GivenUnknownDeviceWhenGettingCompatibilityFallbacksThenReturnEmpty) { + const std::string requestedProduct = "nonexistent_device_acronym_xyz"; + + auto result = ProductConfigHelper::getCompatibilityFallbackProductAbbreviations(requestedProduct); + + EXPECT_TRUE(result.empty()); +} \ No newline at end of file