From 1d7b99140cddfa05c6da549396fff20b14b9dfc6 Mon Sep 17 00:00:00 2001 From: Patryk Wrobel Date: Tue, 26 Apr 2022 13:10:51 +0000 Subject: [PATCH] Test buildFatBinary() This change introduces ULTs for buildFatBinary() function. It is intended to improve code coverage. Related-To: NEO-6834 Signed-off-by: Patryk Wrobel --- .../ocloc_fatbinary_tests.cpp | 133 +++++++++++++++++- .../source/ocloc_fatbinary.cpp | 6 +- 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp b/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp index f7645545f0..84e01d4e07 100644 --- a/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp +++ b/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp @@ -9,6 +9,7 @@ #include "shared/offline_compiler/source/ocloc_arg_helper.h" #include "shared/offline_compiler/source/ocloc_error_code.h" +#include "shared/source/compiler_interface/compiler_options/compiler_options_base.h" #include "shared/source/device_binary_format/ar/ar.h" #include "shared/source/device_binary_format/ar/ar_decoder.h" #include "shared/source/device_binary_format/elf/elf_decoder.h" @@ -36,6 +37,21 @@ auto searchInArchiveByFilename(const Ar::Ar &archive, const ConstStringRef &name return std::find_if(arFiles.begin(), arFiles.end(), isSearchedFile); } +auto allFilesInArchiveExceptPaddingStartsWith(const Ar::Ar &archive, const ConstStringRef &prefix) { + const auto &arFiles = archive.files; + for (const auto &file : arFiles) { + if (file.fileName.startsWith("pad")) { + continue; + } + + if (!file.fileName.startsWith(prefix.data())) { + return false; + } + } + + return true; +} + std::string prepareTwoDevices(MockOclocArgHelper *argHelper) { auto allEnabledDeviceConfigs = argHelper->getAllSupportedDeviceConfigs(); if (allEnabledDeviceConfigs.size() < 2) { @@ -347,7 +363,6 @@ TEST(OclocFatBinaryAsGfxCoreIdList, GivenEnabledGfxCoreNameThenReturnsNonNullIGF } TEST(OclocFatBinaryAsGfxCoreIdList, GivenDisabledGfxCoreNameThenReturnsNullIGFX) { - std::unique_ptr argHelper = std::make_unique(); EXPECT_EQ(argHelper->returnIGFXforGen(ConstStringRef("genA").str()), 0u); @@ -1142,6 +1157,122 @@ TEST_F(OclocFatBinaryTest, GivenSpirvInputWhenFatBinaryIsRequestedThenArchiveCon EXPECT_TRUE(isSpirvDataEqualsInputFileData); } +TEST_F(OclocFatBinaryTest, GivenDeviceFlagWithoutConsecutiveArgumentWhenBuildingFatbinaryThenErrorIsReported) { + const std::vector args = { + "ocloc", + "-device"}; + + ::testing::internal::CaptureStdout(); + const auto result = buildFatBinary(args, &mockArgHelper); + const auto output{::testing::internal::GetCapturedStdout()}; + + EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, result); + + const std::string expectedErrorMessage{"Error! Command does not contain device argument!\n"}; + EXPECT_EQ(expectedErrorMessage, output); +} + +TEST_F(OclocFatBinaryTest, GivenFlagsWhichRequireMoreArgsWithoutThemWhenBuildingFatbinaryThenErrorIsReported) { + const auto devices = prepareTwoDevices(&mockArgHelper); + if (devices.empty()) { + GTEST_SKIP(); + } + + const std::array flagsToTest = {"-file", "-output", "-out_dir"}; + + for (const auto &flag : flagsToTest) { + const std::vector args = { + "ocloc", + "-device", + devices, + flag}; + + ::testing::internal::CaptureStdout(); + const auto result = buildFatBinary(args, &mockArgHelper); + const auto output{::testing::internal::GetCapturedStdout()}; + + EXPECT_EQ(OclocErrorCode::INVALID_COMMAND_LINE, result); + + const std::string expectedErrorMessage{"Invalid option (arg 3): " + flag + "\nError! Couldn't create OfflineCompiler. Exiting.\n"}; + EXPECT_EQ(expectedErrorMessage, output); + } +} + +TEST_F(OclocFatBinaryTest, GivenBitFlagsWhenBuildingFatbinaryThenFilesInArchiveHaveCorrectPointerSize) { + const auto devices = prepareTwoDevices(&mockArgHelper); + if (devices.empty()) { + GTEST_SKIP(); + } + + using TestDescription = std::pair; + + const std::array flagsToTest{ + TestDescription{"-32", "32"}, + TestDescription{NEO::CompilerOptions::arch32bit.str(), "32"}, + TestDescription{"-64", "64"}, + TestDescription{NEO::CompilerOptions::arch64bit.str(), "64"}}; + + for (const auto &[flag, expectedFilePrefix] : flagsToTest) { + const std::vector args = { + "ocloc", + "-output", + outputArchiveName, + "-file", + spirvFilename, + "-output_no_suffix", + "-spirv_input", + "-exclude_ir", + flag, + "-device", + devices}; + + const auto buildResult = buildFatBinary(args, &mockArgHelper); + ASSERT_EQ(OclocErrorCode::SUCCESS, buildResult); + ASSERT_EQ(1u, mockArgHelper.interceptedFiles.count(outputArchiveName)); + + const auto &rawArchive = mockArgHelper.interceptedFiles[outputArchiveName]; + const auto archiveBytes = ArrayRef::fromAny(rawArchive.data(), rawArchive.size()); + + std::string outErrReason{}; + std::string outWarning{}; + const auto decodedArchive = NEO::Ar::decodeAr(archiveBytes, outErrReason, outWarning); + + ASSERT_NE(nullptr, decodedArchive.magic); + ASSERT_TRUE(outErrReason.empty()); + ASSERT_TRUE(outWarning.empty()); + + EXPECT_TRUE(allFilesInArchiveExceptPaddingStartsWith(decodedArchive, expectedFilePrefix)); + } +} + +TEST_F(OclocFatBinaryTest, GivenOutputDirectoryFlagWhenBuildingFatbinaryThenArchiveIsStoredInThatDirectory) { + const auto devices = prepareTwoDevices(&mockArgHelper); + if (devices.empty()) { + GTEST_SKIP(); + } + + const std::string outputDirectory{"someOutputDir"}; + + const std::vector args = { + "ocloc", + "-output", + outputArchiveName, + "-out_dir", + outputDirectory, + "-file", + spirvFilename, + "-output_no_suffix", + "-spirv_input", + "-device", + devices}; + + const auto buildResult = buildFatBinary(args, &mockArgHelper); + ASSERT_EQ(OclocErrorCode::SUCCESS, buildResult); + + const auto expectedArchivePath{outputDirectory + "/" + outputArchiveName}; + ASSERT_EQ(1u, mockArgHelper.interceptedFiles.count(expectedArchivePath)); +} + TEST_F(OclocFatBinaryTest, GivenSpirvInputAndExcludeIrFlagWhenFatBinaryIsRequestedThenArchiveDoesNotContainGenericIrFile) { const auto devices = prepareTwoDevices(&mockArgHelper); if (devices.empty()) { diff --git a/shared/offline_compiler/source/ocloc_fatbinary.cpp b/shared/offline_compiler/source/ocloc_fatbinary.cpp index 1fd5a0b77f..fb382f5fbd 100644 --- a/shared/offline_compiler/source/ocloc_fatbinary.cpp +++ b/shared/offline_compiler/source/ocloc_fatbinary.cpp @@ -378,8 +378,12 @@ int buildFatBinary(const std::vector &args, OclocArgHelper *argHelp argsCopy.push_back("-exclude_ir"); } - Ar::ArEncoder fatbinary(true); + if (deviceArgIndex == static_cast(-1)) { + argHelper->printf("Error! Command does not contain device argument!\n"); + return OclocErrorCode::INVALID_COMMAND_LINE; + } + Ar::ArEncoder fatbinary(true); if (isDeviceWithPlatformAbbreviation(ConstStringRef(args[deviceArgIndex]), argHelper)) { std::vector targetPlatforms; targetPlatforms = getTargetPlatformsForFatbinary(ConstStringRef(args[deviceArgIndex]), argHelper);