/* * Copyright (C) 2018-2024 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "offline_compiler_tests.h" #include "shared/offline_compiler/source/ocloc_api.h" #include "shared/offline_compiler/source/ocloc_fatbinary.h" #include "shared/source/compiler_interface/compiler_options.h" #include "shared/source/compiler_interface/intermediate_representations.h" #include "shared/source/compiler_interface/oclc_extensions.h" #include "shared/source/debug_settings/debug_settings_manager.h" #include "shared/source/device_binary_format/elf/elf_decoder.h" #include "shared/source/device_binary_format/elf/ocl_elf.h" #include "shared/source/helpers/compiler_product_helper.h" #include "shared/source/helpers/file_io.h" #include "shared/source/helpers/hw_info.h" #include "shared/source/helpers/product_config_helper.h" #include "shared/test/common/helpers/debug_manager_state_restore.h" #include "shared/test/common/helpers/gtest_helpers.h" #include "shared/test/common/helpers/variable_backup.h" #include "shared/test/common/mocks/mock_compiler_cache.h" #include "shared/test/common/mocks/mock_compilers.h" #include "shared/test/common/mocks/mock_modules_zebin.h" #include "shared/test/common/mocks/mock_release_helper.h" #include "shared/test/common/test_macros/hw_test.h" #include "opencl/test/unit_test/offline_compiler/mock/mock_ocloc_fcl_facade.h" #include "opencl/test/unit_test/offline_compiler/mock/mock_ocloc_igc_facade.h" #include "environment.h" #include "gtest/gtest.h" #include "mock/mock_argument_helper.h" #include "mock/mock_multi_command.h" #include "mock/mock_offline_compiler.h" #include "platforms.h" #include #include #include #include #include extern Environment *gEnvironment; namespace NEO { void MultiCommandTests::createFileWithArgs(const std::vector &singleArgs, int numOfBuild) { std::ofstream myfile(nameOfFileWithArgs); if (myfile.is_open()) { for (int i = 0; i < numOfBuild; i++) { for (auto singleArg : singleArgs) myfile << singleArg + " "; myfile << std::endl; } myfile.close(); } else ASSERT_TRUE(false) << "Unable to open file\n"; } void MultiCommandTests::deleteFileWithArgs() { remove(nameOfFileWithArgs.c_str()); } void MultiCommandTests::deleteOutFileList() { remove(outFileList.c_str()); } std::string getCompilerOutputFileName(const std::string &fileName, const std::string &type) { std::string fName(fileName); fName.append("_"); fName.append(gEnvironment->devicePrefix); fName.append("."); fName.append(type); return fName; } bool compilerOutputExists(const std::string &fileName, const std::string &type) { return fileExists(getCompilerOutputFileName(fileName, type)); } void compilerOutputRemove(const std::string &fileName, const std::string &type) { std::remove(getCompilerOutputFileName(fileName, type).c_str()); } template bool isAnyIrSectionDefined(const SectionHeaders §ionHeaders) { const auto isIrSection = [](const auto §ion) { return section.header && (section.header->type == Elf::SHT_OPENCL_SPIRV || section.header->type == Elf::SHT_OPENCL_LLVM_BINARY); }; return std::any_of(sectionHeaders.begin(), sectionHeaders.end(), isIrSection); } TEST_F(MultiCommandTests, WhenBuildingMultiCommandThenSuccessIsReturned) { nameOfFileWithArgs = "ImAMulitiComandMinimalGoodFile.txt"; std::vector argv = { "ocloc", "multi", nameOfFileWithArgs.c_str(), "-q", }; std::vector singleArgs = { "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; int numOfBuild = 4; createFileWithArgs(singleArgs, numOfBuild); auto pMultiCommand = std::unique_ptr(MultiCommand::create(argv, retVal, oclocArgHelperWithoutInput.get())); EXPECT_NE(nullptr, pMultiCommand); EXPECT_EQ(CL_SUCCESS, retVal); deleteFileWithArgs(); } TEST_F(MultiCommandTests, GivenOutputFileWhenBuildingMultiCommandThenSuccessIsReturned) { nameOfFileWithArgs = "ImAMulitiComandMinimalGoodFile.txt"; std::vector argv = { "ocloc", "multi", nameOfFileWithArgs.c_str(), "-q", }; std::vector singleArgs = { "-gen_file", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; int numOfBuild = 4; createFileWithArgs(singleArgs, numOfBuild); auto pMultiCommand = std::unique_ptr(MultiCommand::create(argv, retVal, oclocArgHelperWithoutInput.get())); EXPECT_NE(nullptr, pMultiCommand); EXPECT_EQ(CL_SUCCESS, retVal); for (int i = 0; i < numOfBuild; i++) { std::string outFileName = pMultiCommand->outDirForBuilds + "/build_no_" + std::to_string(i + 1); EXPECT_TRUE(compilerOutputExists(outFileName, "bc") || compilerOutputExists(outFileName, "spv")); EXPECT_TRUE(compilerOutputExists(outFileName, "gen")); EXPECT_TRUE(compilerOutputExists(outFileName, "bin")); } deleteFileWithArgs(); } TEST_F(MultiCommandTests, GivenSpecifiedOutputDirWhenBuildingMultiCommandThenSuccessIsReturned) { nameOfFileWithArgs = "ImAMulitiComandMinimalGoodFile.txt"; std::vector argv = { "ocloc", "multi", nameOfFileWithArgs.c_str(), "-q", }; std::vector singleArgs = { "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-out_dir", "offline_compiler_test"}; int numOfBuild = 4; createFileWithArgs(singleArgs, numOfBuild); pMultiCommand = MultiCommand::create(argv, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pMultiCommand); EXPECT_EQ(CL_SUCCESS, retVal); for (int i = 0; i < numOfBuild; i++) { std::string outFileName = "offline_compiler_test/build_no_" + std::to_string(i + 1); EXPECT_TRUE(compilerOutputExists(outFileName, "bc") || compilerOutputExists(outFileName, "spv")); EXPECT_FALSE(compilerOutputExists(outFileName, "gen")); EXPECT_TRUE(compilerOutputExists(outFileName, "bin")); } deleteFileWithArgs(); delete pMultiCommand; } TEST_F(MultiCommandTests, GivenSpecifiedOutputDirWithProductConfigValueWhenBuildingMultiCommandThenSuccessIsReturned) { auto &allEnabledDeviceConfigs = oclocArgHelperWithoutInput->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } std::string configStr; for (auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { configStr = ProductConfigHelper::parseMajorMinorRevisionValue(deviceMapConfig.aotConfig); break; } } nameOfFileWithArgs = "ImAMulitiComandMinimalGoodFile.txt"; std::vector argv = { "ocloc", "multi", nameOfFileWithArgs.c_str(), "-q", }; std::vector singleArgs = { "-file", clFiles + "copybuffer.cl", "-device", configStr, "-out_dir", "offline_compiler_test"}; int numOfBuild = 4; createFileWithArgs(singleArgs, numOfBuild); pMultiCommand = MultiCommand::create(argv, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pMultiCommand); EXPECT_EQ(CL_SUCCESS, retVal); for (int i = 0; i < numOfBuild; i++) { std::string outFileName = "offline_compiler_test/build_no_" + std::to_string(i + 1); EXPECT_TRUE(compilerOutputExists(outFileName, "bc") || compilerOutputExists(outFileName, "spv")); EXPECT_FALSE(compilerOutputExists(outFileName, "gen")); EXPECT_TRUE(compilerOutputExists(outFileName, "bin")); } deleteFileWithArgs(); delete pMultiCommand; } TEST_F(MultiCommandTests, GivenMissingTextFileWithArgsWhenBuildingMultiCommandThenInvalidFileErrorIsReturned) { nameOfFileWithArgs = "ImANotExistedComandFile.txt"; std::vector argv = { "ocloc", "multi", "ImANaughtyFile.txt", "-q", }; testing::internal::CaptureStdout(); auto pMultiCommand = std::unique_ptr(MultiCommand::create(argv, retVal, oclocArgHelperWithoutInput.get())); std::string output = testing::internal::GetCapturedStdout(); EXPECT_STRNE(output.c_str(), ""); EXPECT_EQ(nullptr, pMultiCommand); EXPECT_EQ(OCLOC_INVALID_FILE, retVal); debugManager.flags.PrintDebugMessages.set(false); } TEST_F(MultiCommandTests, GivenLackOfClFileWhenBuildingMultiCommandThenInvalidFileErrorIsReturned) { nameOfFileWithArgs = "ImAMulitiComandMinimalGoodFile.txt"; std::vector argv = { "ocloc", "multi", nameOfFileWithArgs.c_str(), "-q", }; std::vector singleArgs = { "-file", clFiles + "ImANaughtyFile.cl", "-device", gEnvironment->devicePrefix.c_str()}; int numOfBuild = 4; createFileWithArgs(singleArgs, numOfBuild); testing::internal::CaptureStdout(); auto pMultiCommand = std::unique_ptr(MultiCommand::create(argv, retVal, oclocArgHelperWithoutInput.get())); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pMultiCommand); EXPECT_EQ(OCLOC_INVALID_FILE, retVal); debugManager.flags.PrintDebugMessages.set(false); deleteFileWithArgs(); } TEST_F(MultiCommandTests, GivenOutputFileListFlagWhenBuildingMultiCommandThenSuccessIsReturned) { nameOfFileWithArgs = "ImAMulitiComandMinimalGoodFile.txt"; std::vector argv = { "ocloc", "multi", nameOfFileWithArgs.c_str(), "-q", "-output_file_list", "outFileList.txt", }; std::vector singleArgs = { "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; int numOfBuild = 4; createFileWithArgs(singleArgs, numOfBuild); pMultiCommand = MultiCommand::create(argv, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pMultiCommand); EXPECT_EQ(CL_SUCCESS, retVal); outFileList = pMultiCommand->outputFileList; EXPECT_TRUE(fileExists(outFileList)); for (int i = 0; i < numOfBuild; i++) { std::string outFileName = pMultiCommand->outDirForBuilds + "/build_no_" + std::to_string(i + 1); EXPECT_TRUE(compilerOutputExists(outFileName, "bc") || compilerOutputExists(outFileName, "spv")); EXPECT_FALSE(compilerOutputExists(outFileName, "gen")); EXPECT_TRUE(compilerOutputExists(outFileName, "bin")); } deleteFileWithArgs(); deleteOutFileList(); delete pMultiCommand; } TEST(MultiCommandWhiteboxTest, GivenVerboseModeWhenShowingResultsThenLogsArePrintedForEachBuild) { MockMultiCommand mockMultiCommand{}; mockMultiCommand.retValues = {OCLOC_SUCCESS, OCLOC_INVALID_FILE}; mockMultiCommand.quiet = false; ::testing::internal::CaptureStdout(); const auto result = mockMultiCommand.showResults(); const auto output = testing::internal::GetCapturedStdout(); const auto maskedResult = result | OCLOC_INVALID_FILE; EXPECT_NE(OCLOC_SUCCESS, result); EXPECT_EQ(OCLOC_INVALID_FILE, maskedResult); const auto expectedOutput{"Build command 0: successful\n" "Build command 1: failed. Error code: -5151\n"}; EXPECT_EQ(expectedOutput, output); } TEST(MultiCommandWhiteboxTest, GivenVerboseModeAndDefinedOutputFilenameAndDirectoryWhenAddingAdditionalOptionsToSingleCommandLineThenNothingIsDone) { MockMultiCommand mockMultiCommand{}; mockMultiCommand.quiet = false; std::vector singleArgs = { "-file", clFiles + "copybuffer.cl", "-output", "SpecialOutputFilename", "-out_dir", "SomeOutputDirectory", "-device", gEnvironment->devicePrefix.c_str()}; const auto singleArgsCopy{singleArgs}; const size_t buildId{0}; ::testing::internal::CaptureStdout(); mockMultiCommand.addAdditionalOptionsToSingleCommandLine(singleArgs, buildId); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(singleArgsCopy, singleArgs); } TEST(MultiCommandWhiteboxTest, GivenHelpArgumentsWhenInitializingThenHelpIsPrinted) { MockMultiCommand mockMultiCommand{}; mockMultiCommand.quiet = false; std::vector singleArgs = { "--help"}; const auto args{singleArgs}; ::testing::internal::CaptureStdout(); const auto result = mockMultiCommand.initialize(args); const auto output = testing::internal::GetCapturedStdout(); const auto expectedOutput = R"===(Compiles multiple files using a config file. Usage: ocloc multi Input file containing a list of arguments for subsequent ocloc invocations. Expected format of each line inside such file is: '-file -device [compile_options]'. See 'ocloc compile --help' for available compile_options. Results of subsequent compilations will be dumped into a directory with name identical file_name's base name. -output_file_list Name of optional file containing paths to outputs .bin files )==="; EXPECT_EQ(expectedOutput, output); EXPECT_EQ(-1, result); } TEST(MultiCommandWhiteboxTest, GivenCommandLineWithApostrophesWhenSplittingLineInSeparateArgsThenTextBetweenApostrophesIsReadAsSingleArg) { MockMultiCommand mockMultiCommand{}; mockMultiCommand.quiet = false; const std::string commandLine{" -out_dir \"Some Directory\" -output \'Some Filename\'"}; std::vector outputArgs{}; const std::size_t numberOfBuild{0}; ::testing::internal::CaptureStdout(); const auto result = mockMultiCommand.splitLineInSeparateArgs(outputArgs, commandLine, numberOfBuild); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(OCLOC_SUCCESS, result); EXPECT_TRUE(output.empty()) << output; ASSERT_EQ(4u, outputArgs.size()); EXPECT_EQ("-out_dir", outputArgs[0]); EXPECT_EQ("Some Directory", outputArgs[1]); EXPECT_EQ("-output", outputArgs[2]); EXPECT_EQ("Some Filename", outputArgs[3]); } TEST(MultiCommandWhiteboxTest, GivenCommandLineWithMissingApostropheWhenSplittingLineInSeparateArgsThenErrorIsReturned) { MockMultiCommand mockMultiCommand{}; mockMultiCommand.quiet = false; const std::string commandLine{"-out_dir \"Some Directory"}; std::vector outputArgs{}; const std::size_t numberOfBuild{0}; ::testing::internal::CaptureStdout(); const auto result = mockMultiCommand.splitLineInSeparateArgs(outputArgs, commandLine, numberOfBuild); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(OCLOC_INVALID_FILE, result); const auto expectedOutput = "One of the quotes is open in build number 1\n"; EXPECT_EQ(expectedOutput, output); } TEST(MultiCommandWhiteboxTest, GivenCommandLineWithMissingApostropheWhenRunningBuildsThenErrorIsReturnedAndBuildIsNotStarted) { MockMultiCommand mockMultiCommand{}; mockMultiCommand.quiet = true; mockMultiCommand.callBaseSingleBuild = false; mockMultiCommand.lines.push_back("-out_dir \"Some Directory"); mockMultiCommand.argHelper->getPrinterRef().setSuppressMessages(true); mockMultiCommand.runBuilds("ocloc"); EXPECT_EQ(0, mockMultiCommand.singleBuildCalledCount); ASSERT_EQ(1u, mockMultiCommand.retValues.size()); EXPECT_EQ(OCLOC_INVALID_FILE, mockMultiCommand.retValues[0]); } TEST(MultiCommandWhiteboxTest, GivenTwoValidCommandLinesAndVerboseModeWhenRunningBuildsThenBuildsAreStartedReturnValuesAreStoredAndLogsArePrinted) { MockMultiCommand mockMultiCommand{}; mockMultiCommand.quiet = false; mockMultiCommand.callBaseSingleBuild = false; const std::string validLine{"-file test_files/copybuffer.cl -output SpecialOutputFilename -out_dir SomeOutputDirectory -device " + gEnvironment->devicePrefix}; mockMultiCommand.lines.push_back(validLine); mockMultiCommand.lines.push_back(validLine); ::testing::internal::CaptureStdout(); mockMultiCommand.runBuilds("ocloc"); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(2, mockMultiCommand.singleBuildCalledCount); ASSERT_EQ(2u, mockMultiCommand.retValues.size()); EXPECT_EQ(OCLOC_SUCCESS, mockMultiCommand.retValues[0]); EXPECT_EQ(OCLOC_SUCCESS, mockMultiCommand.retValues[1]); const auto expectedOutput{"Command number 1: \n" "Command number 2: \n"}; EXPECT_EQ(expectedOutput, output); } TEST(MultiCommandWhiteboxTest, GivenArgsWithQuietModeAndEmptyMulticommandFileWhenInitializingThenQuietFlagIsSetAndErrorIsReturned) { MockMultiCommand mockMultiCommand{}; mockMultiCommand.quiet = false; mockMultiCommand.uniqueHelper->callBaseFileExists = false; mockMultiCommand.uniqueHelper->callBaseReadFileToVectorOfStrings = false; mockMultiCommand.uniqueHelper->shouldReturnEmptyVectorOfStrings = true; mockMultiCommand.filesMap["commands.txt"] = ""; const std::vector args = { "ocloc", "multi", "commands.txt", "-q"}; ::testing::internal::CaptureStdout(); const auto result = mockMultiCommand.initialize(args); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(OCLOC_INVALID_FILE, result); const auto expectedOutput = "Command file was empty.\n"; EXPECT_EQ(expectedOutput, output); EXPECT_TRUE(mockMultiCommand.quiet); } TEST(MultiCommandWhiteboxTest, GivenInvalidArgsWhenInitializingThenErrorIsReturned) { MockMultiCommand mockMultiCommand{}; mockMultiCommand.quiet = false; const std::vector args = { "ocloc", "multi", "commands.txt", "-invalid_option"}; ::testing::internal::CaptureStdout(); const auto result = mockMultiCommand.initialize(args); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, result); const auto expectedError = "Invalid option (arg 3): -invalid_option\n"; const auto errorPosition = output.find(expectedError); EXPECT_NE(std::string::npos, errorPosition); } using MockOfflineCompilerTests = ::testing::Test; TEST_F(MockOfflineCompilerTests, givenProductConfigValueWhenInitHwInfoThenCorrectValueIsSet) { MockOfflineCompiler mockOfflineCompiler; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } auto config = AOT::UNKNOWN_ISA; for (const auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { config = static_cast(deviceMapConfig.aotConfig.value); break; } } mockOfflineCompiler.deviceName = ProductConfigHelper::parseMajorMinorRevisionValue(config); EXPECT_FALSE(mockOfflineCompiler.deviceName.empty()); mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName); EXPECT_EQ(mockOfflineCompiler.deviceConfig, config); } TEST_F(MockOfflineCompilerTests, givenDeviceIdsFromDevicesFileWhenInitHwInfoThenDeviceConfigValuesIsSet) { std::vector deviceIds{ #define NAMEDDEVICE(devId, ignored_product, ignored_devName) devId, #define DEVICE(devId, ignored_product) devId, #include "devices.inl" #undef DEVICE #undef NAMEDDEVICE }; if (deviceIds.empty()) { GTEST_SKIP(); } MockOfflineCompiler mockOfflineCompiler; mockOfflineCompiler.argHelper->getPrinterRef().setSuppressMessages(true); for (const auto &deviceId : deviceIds) { std::stringstream deviceIDStr; deviceIDStr << "0x" << std::hex << deviceId; mockOfflineCompiler.initHardwareInfo(deviceIDStr.str()); EXPECT_NE(mockOfflineCompiler.deviceConfig, AOT::UNKNOWN_ISA); } } TEST_F(MockOfflineCompilerTests, givenDeviceIdValueWhenInitHwInfoThenCorrectValuesAreSet) { MockOfflineCompiler mockOfflineCompiler; uint32_t deviceID = 0; std::stringstream deviceIDStr, expectedOutput; std::string deviceStr; uint32_t productConfig = AOT::UNKNOWN_ISA; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } for (const auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { deviceID = deviceMapConfig.deviceIds->front(); deviceIDStr << "0x" << std::hex << deviceID; deviceStr = mockOfflineCompiler.argHelper->productConfigHelper->getAcronymForProductConfig(deviceMapConfig.aotConfig.value); productConfig = deviceMapConfig.aotConfig.value; break; } } mockOfflineCompiler.deviceName = deviceIDStr.str(); EXPECT_FALSE(mockOfflineCompiler.deviceName.empty()); testing::internal::CaptureStdout(); mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName); std::string output = testing::internal::GetCapturedStdout(); expectedOutput << "Auto-detected target based on " << deviceIDStr.str() << " device id: " << deviceStr << "\n"; EXPECT_STREQ(output.c_str(), expectedOutput.str().c_str()); EXPECT_EQ(mockOfflineCompiler.hwInfo.platform.usDeviceID, deviceID); EXPECT_EQ(mockOfflineCompiler.deviceConfig, productConfig); } TEST_F(MockOfflineCompilerTests, givenDeviceIdAndRevisionIdValueWhenInitHwInfoThenCorrectValuesAreSet) { MockOfflineCompiler mockOfflineCompiler; uint32_t deviceID = 0; std::stringstream deviceIDStr, expectedOutput; std::string deviceStr; uint32_t productConfig = AOT::UNKNOWN_ISA; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } for (const auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { deviceID = deviceMapConfig.deviceIds->front(); deviceIDStr << "0x" << std::hex << deviceID; deviceStr = mockOfflineCompiler.argHelper->productConfigHelper->getAcronymForProductConfig(deviceMapConfig.aotConfig.value); productConfig = deviceMapConfig.aotConfig.value; break; } } mockOfflineCompiler.deviceName = deviceIDStr.str(); mockOfflineCompiler.revisionId = 0x0; EXPECT_FALSE(mockOfflineCompiler.deviceName.empty()); testing::internal::CaptureStdout(); mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName); std::string output = testing::internal::GetCapturedStdout(); expectedOutput << "Auto-detected target based on " << deviceIDStr.str() << " device id: " << deviceStr << "\n"; EXPECT_STREQ(output.c_str(), expectedOutput.str().c_str()); EXPECT_EQ(mockOfflineCompiler.hwInfo.platform.usDeviceID, deviceID); EXPECT_EQ(mockOfflineCompiler.hwInfo.platform.usRevId, mockOfflineCompiler.revisionId); EXPECT_EQ(mockOfflineCompiler.deviceConfig, productConfig); } TEST_F(MockOfflineCompilerTests, givenProductConfigValueWhenInitHwInfoThenBaseHardwareInfoValuesAreSet) { MockOfflineCompiler mockOfflineCompiler; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } for (const auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { mockOfflineCompiler.deviceName = ProductConfigHelper::parseMajorMinorRevisionValue(deviceMapConfig.aotConfig); break; } } EXPECT_FALSE(mockOfflineCompiler.deviceName.empty()); mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName); EXPECT_EQ(mockOfflineCompiler.hwInfo.platform.eProductFamily, productFamily); EXPECT_NE(mockOfflineCompiler.hwInfo.gtSystemInfo.MaxEuPerSubSlice, 0u); EXPECT_NE(mockOfflineCompiler.hwInfo.gtSystemInfo.MaxSlicesSupported, 0u); EXPECT_NE(mockOfflineCompiler.hwInfo.gtSystemInfo.MaxSubSlicesSupported, 0u); } TEST_F(MockOfflineCompilerTests, givenDeprecatedAcronymsWithRevisionWhenInitHwInfoThenValuesAreSetAndSuccessIsReturned) { MockOfflineCompiler mockOfflineCompiler; auto deprecatedAcronyms = mockOfflineCompiler.argHelper->productConfigHelper->getDeprecatedAcronyms(); if (deprecatedAcronyms.empty()) { GTEST_SKIP(); } for (const auto &acronym : deprecatedAcronyms) { mockOfflineCompiler.deviceName = acronym.str(); mockOfflineCompiler.revisionId = 0x3; EXPECT_EQ(OCLOC_SUCCESS, mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName)); auto defaultIpVersion = mockOfflineCompiler.compilerProductHelper->getDefaultHwIpVersion(); auto productConfig = mockOfflineCompiler.compilerProductHelper->matchRevisionIdWithProductConfig(defaultIpVersion, mockOfflineCompiler.revisionId); if (mockOfflineCompiler.argHelper->productConfigHelper->isSupportedProductConfig(productConfig)) { EXPECT_EQ(mockOfflineCompiler.hwInfo.ipVersion.value, productConfig); } else { EXPECT_EQ(mockOfflineCompiler.hwInfo.ipVersion.value, defaultIpVersion); } EXPECT_EQ(mockOfflineCompiler.revisionId, static_cast(mockOfflineCompiler.hwInfo.platform.usRevId)); } } TEST_F(MockOfflineCompilerTests, givenDeprecatedAcronymThenSameAcronymIsReturnedAsProduct) { MockOfflineCompiler mockOfflineCompiler; auto deprecatedAcronyms = mockOfflineCompiler.argHelper->productConfigHelper->getDeprecatedAcronyms(); if (deprecatedAcronyms.empty()) { GTEST_SKIP(); } for (const auto &acronym : deprecatedAcronyms) { NEO::CompilerOptions::TokenizedString srcAcronym; srcAcronym.push_back(acronym); auto products = NEO::getProductForSpecificTarget(srcAcronym, mockOfflineCompiler.argHelper); ASSERT_EQ(1U, products.size()); EXPECT_STREQ(acronym.data(), products[0].data()); } } TEST_F(MockOfflineCompilerTests, givenValidAcronymAndRevisionIdWhenInitHardwareInfoForProductConfigThenInvalidDeviceIsReturned) { MockOfflineCompiler mockOfflineCompiler; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } for (const auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { if (!deviceMapConfig.deviceAcronyms.empty()) { mockOfflineCompiler.deviceName = deviceMapConfig.deviceAcronyms.front().str(); break; } else if (!deviceMapConfig.rtlIdAcronyms.empty()) { mockOfflineCompiler.deviceName = deviceMapConfig.rtlIdAcronyms.front().str(); break; } } } if (mockOfflineCompiler.deviceName.empty()) { GTEST_SKIP(); } mockOfflineCompiler.revisionId = 0x3; EXPECT_EQ(OCLOC_INVALID_DEVICE, mockOfflineCompiler.initHardwareInfoForProductConfig(mockOfflineCompiler.deviceName)); } TEST_F(MockOfflineCompilerTests, givenHwInfoConfigWhenSetHwInfoForProductConfigThenCorrectValuesAreSet) { MockOfflineCompiler mockOfflineCompiler; auto enabledProductAcronyms = mockOfflineCompiler.argHelper->productConfigHelper->getRepresentativeProductAcronyms(); if (enabledProductAcronyms.empty()) { GTEST_SKIP(); } for (const auto &acronym : enabledProductAcronyms) { mockOfflineCompiler.deviceName = acronym.str(); mockOfflineCompiler.hwInfoConfig = 0x100020003; EXPECT_EQ(mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName), OCLOC_SUCCESS); uint32_t sliceCount = static_cast(mockOfflineCompiler.hwInfoConfig >> 32); uint32_t subSlicePerSliceCount = static_cast(mockOfflineCompiler.hwInfoConfig >> 16); uint32_t euPerSubSliceCount = static_cast(mockOfflineCompiler.hwInfoConfig); uint32_t subSliceCount = subSlicePerSliceCount * sliceCount; auto >SysInfo = mockOfflineCompiler.hwInfo.gtSystemInfo; EXPECT_EQ(gtSysInfo.SliceCount, sliceCount); EXPECT_EQ(gtSysInfo.SubSliceCount, subSliceCount); EXPECT_EQ(gtSysInfo.EUCount, euPerSubSliceCount * subSliceCount); EXPECT_EQ(gtSysInfo.DualSubSliceCount, subSlicePerSliceCount * sliceCount); EXPECT_NE(gtSysInfo.ThreadCount, 0u); } } TEST_F(MockOfflineCompilerTests, givenHwInfoConfigWhenSetHwInfoForDeprecatedAcronymsThenCorrectValuesAreSet) { MockOfflineCompiler mockOfflineCompiler; auto deprecatedAcronyms = mockOfflineCompiler.argHelper->productConfigHelper->getDeprecatedAcronyms(); if (deprecatedAcronyms.empty()) { GTEST_SKIP(); } for (const auto &acronym : deprecatedAcronyms) { mockOfflineCompiler.deviceName = acronym.str(); mockOfflineCompiler.hwInfoConfig = 0x100020003; EXPECT_EQ(mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName), OCLOC_SUCCESS); uint32_t sliceCount = static_cast(mockOfflineCompiler.hwInfoConfig >> 32); uint32_t subSlicePerSliceCount = static_cast(mockOfflineCompiler.hwInfoConfig >> 16); uint32_t euPerSubSliceCount = static_cast(mockOfflineCompiler.hwInfoConfig); uint32_t subSliceCount = subSlicePerSliceCount * sliceCount; auto >SysInfo = mockOfflineCompiler.hwInfo.gtSystemInfo; EXPECT_EQ(gtSysInfo.SliceCount, sliceCount); EXPECT_EQ(gtSysInfo.SubSliceCount, subSliceCount); EXPECT_EQ(gtSysInfo.EUCount, euPerSubSliceCount * subSliceCount); EXPECT_NE(gtSysInfo.ThreadCount, 0u); } } TEST_F(MockOfflineCompilerTests, givenAcronymWithUppercaseWhenInitHwInfoThenSuccessIsReturned) { MockOfflineCompiler mockOfflineCompiler; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } for (const auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { if (!deviceMapConfig.deviceAcronyms.empty()) { mockOfflineCompiler.deviceName = deviceMapConfig.deviceAcronyms.front().str(); break; } else if (!deviceMapConfig.rtlIdAcronyms.empty()) { mockOfflineCompiler.deviceName = deviceMapConfig.rtlIdAcronyms.front().str(); break; } } } if (mockOfflineCompiler.deviceName.empty()) { GTEST_SKIP(); } std::transform(mockOfflineCompiler.deviceName.begin(), mockOfflineCompiler.deviceName.end(), mockOfflineCompiler.deviceName.begin(), ::toupper); EXPECT_EQ(mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName), OCLOC_SUCCESS); } TEST_F(MockOfflineCompilerTests, givenDeprecatedAcronymsWithUppercaseWhenInitHwInfoThenSuccessIsReturned) { MockOfflineCompiler mockOfflineCompiler; auto deprecatedAcronyms = mockOfflineCompiler.argHelper->productConfigHelper->getDeprecatedAcronyms(); if (deprecatedAcronyms.empty()) { GTEST_SKIP(); } for (const auto &acronym : deprecatedAcronyms) { mockOfflineCompiler.deviceName = acronym.str(); std::transform(mockOfflineCompiler.deviceName.begin(), mockOfflineCompiler.deviceName.end(), mockOfflineCompiler.deviceName.begin(), ::toupper); EXPECT_EQ(mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName), OCLOC_SUCCESS); } } HWTEST2_F(MockOfflineCompilerTests, givenProductConfigValueWhenInitHwInfoThenMaxDualSubSlicesSupportedIsSet, IsAtLeastGen12lp) { MockOfflineCompiler mockOfflineCompiler; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } for (const auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { mockOfflineCompiler.deviceName = ProductConfigHelper::parseMajorMinorRevisionValue(deviceMapConfig.aotConfig); break; } } mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName); EXPECT_NE(mockOfflineCompiler.hwInfo.gtSystemInfo.MaxDualSubSlicesSupported, 0u); } TEST_F(MockOfflineCompilerTests, givenDeviceIpVersionWhenInitHwInfoThenCorrectResultsIsReturned) { MockOfflineCompiler mockOfflineCompiler; std::stringstream config; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } for (const auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { config << deviceMapConfig.aotConfig.value; mockOfflineCompiler.deviceName = config.str(); break; } } EXPECT_EQ(OCLOC_SUCCESS, mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName)); } TEST_F(MockOfflineCompilerTests, givenTheSameProductConfigWhenDifferentDeviceFormParameterIsPassedThenSameResultsAreReturned) { MockOfflineCompiler mockOfflineCompiler; std::stringstream ipVersion; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } for (const auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { ipVersion << deviceMapConfig.aotConfig.value; mockOfflineCompiler.deviceName = ProductConfigHelper::parseMajorMinorRevisionValue(deviceMapConfig.aotConfig); break; } } EXPECT_EQ(OCLOC_SUCCESS, mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName)); EXPECT_NE(AOT::UNKNOWN_ISA, mockOfflineCompiler.deviceConfig); auto expectedConfig = mockOfflineCompiler.deviceConfig; mockOfflineCompiler.deviceName = ipVersion.str(); EXPECT_EQ(OCLOC_SUCCESS, mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName)); EXPECT_EQ(expectedConfig, mockOfflineCompiler.deviceConfig); } TEST_F(OfflineCompilerTests, GivenHelpOptionOnQueryThenSuccessIsReturned) { std::vector argv = { "ocloc", "query", "--help"}; testing::internal::CaptureStdout(); int retVal = OfflineCompiler::query(argv.size(), argv, oclocArgHelperWithoutInput.get()); std::string output = testing::internal::GetCapturedStdout(); EXPECT_STREQ(OfflineCompiler::queryHelp.data(), output.c_str()); EXPECT_EQ(OCLOC_SUCCESS, retVal); } TEST_F(OfflineCompilerTests, GivenHelpOptionOnIdsThenSuccessIsReturned) { std::vector helpFlags = {"-h", "--help"}; for (const auto &helpFlag : helpFlags) { std::vector argv = { "ocloc", "ids", helpFlag.str()}; testing::internal::CaptureStdout(); int retVal = OfflineCompiler::queryAcronymIds(argv.size(), argv, oclocArgHelperWithoutInput.get()); std::string output = testing::internal::GetCapturedStdout(); std::stringstream expectedOutput; expectedOutput << R"===( Depending on will return all matched versions (..) that correspond to the given name. All supported acronyms: )==="; expectedOutput << getSupportedDevices(oclocArgHelperWithoutInput.get()) << ".\n"; EXPECT_STREQ(output.c_str(), expectedOutput.str().c_str()); EXPECT_EQ(OCLOC_SUCCESS, retVal); } } TEST_F(OfflineCompilerTests, givenFamilyAcronymWhenIdsCommandIsInvokeThenSuccessAndCorrectIdsAreReturned) { auto enabledFamilies = oclocArgHelperWithoutInput->productConfigHelper->getFamiliesAcronyms(); if (enabledFamilies.empty()) { GTEST_SKIP(); } auto &supportedDevicesConfigs = oclocArgHelperWithoutInput->productConfigHelper->getDeviceAotInfo(); for (const auto &familyAcronym : enabledFamilies) { std::vector expected{}; auto family = oclocArgHelperWithoutInput->productConfigHelper->getFamilyFromDeviceName(familyAcronym.str()); for (const auto &device : supportedDevicesConfigs) { if (device.family == family) { auto config = ProductConfigHelper::parseMajorMinorRevisionValue(device.aotConfig); expected.push_back(config); } } std::vector argv = { "ocloc", "ids", familyAcronym.str()}; std::stringstream expectedOutput; testing::internal::CaptureStdout(); int retVal = OfflineCompiler::queryAcronymIds(argv.size(), argv, oclocArgHelperWithoutInput.get()); std::string output = testing::internal::GetCapturedStdout(); expectedOutput << "Matched ids:\n"; for (const auto &prefix : expected) { expectedOutput << prefix << "\n"; } EXPECT_STREQ(expectedOutput.str().c_str(), output.c_str()); EXPECT_EQ(OCLOC_SUCCESS, retVal); } } TEST_F(OfflineCompilerTests, givenReleaseAcronymWhenIdsCommandIsInvokeThenSuccessAndCorrectIdsAreReturned) { auto enabledReleases = oclocArgHelperWithoutInput->productConfigHelper->getReleasesAcronyms(); if (enabledReleases.empty()) { GTEST_SKIP(); } auto &supportedDevicesConfigs = oclocArgHelperWithoutInput->productConfigHelper->getDeviceAotInfo(); for (const auto &releaseAcronym : enabledReleases) { std::vector expected{}; auto release = oclocArgHelperWithoutInput->productConfigHelper->getReleaseFromDeviceName(releaseAcronym.str()); for (const auto &device : supportedDevicesConfigs) { if (device.release == release) { auto config = ProductConfigHelper::parseMajorMinorRevisionValue(device.aotConfig); expected.push_back(config); } } std::vector argv = { "ocloc", "ids", releaseAcronym.str()}; std::stringstream expectedOutput; testing::internal::CaptureStdout(); int retVal = OfflineCompiler::queryAcronymIds(argv.size(), argv, oclocArgHelperWithoutInput.get()); std::string output = testing::internal::GetCapturedStdout(); expectedOutput << "Matched ids:\n"; for (const auto &prefix : expected) { expectedOutput << prefix << "\n"; } EXPECT_STREQ(expectedOutput.str().c_str(), output.c_str()); EXPECT_EQ(OCLOC_SUCCESS, retVal); } } TEST_F(OfflineCompilerTests, givenProductAcronymWhenIdsCommandIsInvokeThenSuccessAndCorrectIdsAreReturned) { auto enabledProducts = oclocArgHelperWithoutInput->productConfigHelper->getAllProductAcronyms(); if (enabledProducts.empty()) { GTEST_SKIP(); } auto &supportedDevicesConfigs = oclocArgHelperWithoutInput->productConfigHelper->getDeviceAotInfo(); for (const auto &productAcronym : enabledProducts) { std::vector expected{}; auto product = ProductConfigHelper::getProductConfigFromAcronym(productAcronym.str()); for (const auto &device : supportedDevicesConfigs) { if (device.aotConfig.value == product) { auto config = ProductConfigHelper::parseMajorMinorRevisionValue(device.aotConfig); expected.push_back(config); } } std::vector argv = { "ocloc", "ids", productAcronym.str()}; std::stringstream expectedOutput; testing::internal::CaptureStdout(); int retVal = OfflineCompiler::queryAcronymIds(argv.size(), argv, oclocArgHelperWithoutInput.get()); std::string output = testing::internal::GetCapturedStdout(); expectedOutput << "Matched ids:\n"; for (const auto &prefix : expected) { expectedOutput << prefix << "\n"; } EXPECT_STREQ(expectedOutput.str().c_str(), output.c_str()); EXPECT_EQ(OCLOC_SUCCESS, retVal); } } TEST_F(OfflineCompilerTests, GivenFlagsWhichRequireMoreArgsWithoutThemWhenParsingThenErrorIsReported) { const std::array flagsToTest = { "-file", "-output", "-device", "-options", "-internal_options", "-out_dir", "-cache_dir", "-revision_id", "-config"}; for (const auto &flag : flagsToTest) { const std::vector argv = { "ocloc", "compile", flag}; MockOfflineCompiler mockOfflineCompiler{}; ::testing::internal::CaptureStdout(); const auto result = mockOfflineCompiler.parseCommandLine(argv.size(), argv); const auto output{::testing::internal::GetCapturedStdout()}; EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, result); const std::string expectedErrorMessage{"Invalid option (arg 2): " + flag + "\n"}; EXPECT_EQ(expectedErrorMessage, output); } } TEST_F(OfflineCompilerTests, Given32BitModeFlagWhenParsingThenInternalOptionsContain32BitModeFlag) { const std::array flagsToTest = { "-32", CompilerOptions::arch32bit.str()}; for (const auto &flag : flagsToTest) { const std::vector argv = { "ocloc", "compile", "-file", clFiles + "copybuffer.cl", flag, "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; const auto result = mockOfflineCompiler.parseCommandLine(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, result); const auto is32BitModeSet{mockOfflineCompiler.internalOptions.find(CompilerOptions::arch32bit.data()) != std::string::npos}; EXPECT_TRUE(is32BitModeSet); } } TEST_F(OfflineCompilerTests, givenConfigFlagWhenParsingCommandLineThenCorrectValueIsSet) { std::string configStr = "1x2x3"; const std::vector argv = { "ocloc", "compile", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-config", configStr}; MockOfflineCompiler mockOfflineCompiler{}; uint64_t config = 0u; parseHwInfoConfigString(configStr, config); const auto result = mockOfflineCompiler.parseCommandLine(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, result); EXPECT_EQ(mockOfflineCompiler.hwInfoConfig, config); } TEST_F(OfflineCompilerTests, givenIncorrectConfigFlagWhenParsingCommandLineThenErrorLogIsPrintedAndFailureIsReturned) { std::string configStr = "1xabcf"; const std::vector argv = { "ocloc", "compile", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-config", configStr}; MockOfflineCompiler mockOfflineCompiler{}; ::testing::internal::CaptureStdout(); const auto result = mockOfflineCompiler.parseCommandLine(argv.size(), argv); const auto output{::testing::internal::GetCapturedStdout()}; EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, result); EXPECT_EQ(mockOfflineCompiler.hwInfoConfig, 0u); const std::string expectedErrorMessage{"Error: Invalid config.\n"}; EXPECT_EQ(expectedErrorMessage, output); } TEST_F(OfflineCompilerTests, Given64BitModeFlagWhenParsingThenInternalOptionsContain64BitModeFlag) { const std::array flagsToTest = { "-64", CompilerOptions::arch64bit.str()}; for (const auto &flag : flagsToTest) { const std::vector argv = { "ocloc", "compile", "-file", clFiles + "copybuffer.cl", flag, "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; const auto result = mockOfflineCompiler.parseCommandLine(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, result); const auto is64BitModeSet{mockOfflineCompiler.internalOptions.find(CompilerOptions::arch64bit.data()) != std::string::npos}; EXPECT_TRUE(is64BitModeSet); } } TEST_F(OfflineCompilerTests, Given32BitModeFlagAnd64BitModeFlagWhenParsingThenErrorLogIsPrintedAndFailureIsReturned) { const std::vector argv = { "ocloc", "compile", "-file", clFiles + "copybuffer.cl", "-32", "-64", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; ::testing::internal::CaptureStdout(); const auto result = mockOfflineCompiler.parseCommandLine(argv.size(), argv); const auto output{::testing::internal::GetCapturedStdout()}; EXPECT_NE(OCLOC_SUCCESS, result); const auto maskedResult = result | OCLOC_INVALID_COMMAND_LINE; EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, maskedResult); const std::string expectedErrorMessage{"Error: Cannot compile for 32-bit and 64-bit, please choose one.\n"}; EXPECT_EQ(expectedErrorMessage, output); } TEST_F(OfflineCompilerTests, GivenFlagStringWhenParsingThenInternalBooleanIsSetAndSuccessIsReturned) { using namespace std::string_literals; const std::array flagsToTest = { std::pair{"-options_name"s, &MockOfflineCompiler::useOptionsSuffix}, std::pair{"-gen_file"s, &MockOfflineCompiler::useGenFile}, std::pair{"-llvm_bc"s, &MockOfflineCompiler::useLlvmBc}}; for (const auto &[flagString, memberBoolean] : flagsToTest) { const std::vector argv = { "ocloc", "compile", "-file", clFiles + "copybuffer.cl", flagString, "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; const auto result = mockOfflineCompiler.parseCommandLine(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, result); EXPECT_TRUE(mockOfflineCompiler.*memberBoolean); } } TEST_F(OfflineCompilerTests, GivenArgsWhenQueryIsCalledThenSuccessIsReturned) { std::vector argv = { "ocloc", "query", "NEO_REVISION"}; int retVal = OfflineCompiler::query(argv.size(), argv, oclocArgHelperWithoutInput.get()); EXPECT_EQ(OCLOC_SUCCESS, retVal); } TEST_F(OfflineCompilerTests, GivenArgsWhenOfflineCompilerIsCreatedThenSuccessIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pOfflineCompiler); EXPECT_EQ(CL_SUCCESS, retVal); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, givenDeviceIdHexValueWhenInitHwInfoThenItHasCorrectlySetValues) { auto deviceAotInfo = oclocArgHelperWithoutInput->productConfigHelper->getDeviceAotInfo(); if (deviceAotInfo.empty()) { GTEST_SKIP(); } MockOfflineCompiler mockOfflineCompiler; std::stringstream deviceString, productString; auto deviceId = deviceAotInfo[0].deviceIds->front(); deviceString << "0x" << std::hex << deviceId; mockOfflineCompiler.argHelper->getPrinterRef().setSuppressMessages(true); mockOfflineCompiler.initHardwareInfo(deviceString.str()); EXPECT_EQ(mockOfflineCompiler.hwInfo.platform.usDeviceID, deviceId); } TEST_F(OfflineCompilerTests, givenProperDeviceIdHexAsDeviceArgumentThenSuccessIsReturned) { auto deviceAotInfo = oclocArgHelperWithoutInput->productConfigHelper->getDeviceAotInfo(); if (deviceAotInfo.empty()) { GTEST_SKIP(); } std::stringstream deviceString, productString; AOT::PRODUCT_CONFIG config = static_cast(deviceAotInfo[0].aotConfig.value); auto deviceId = deviceAotInfo[0].deviceIds->front(); productString << oclocArgHelperWithoutInput->productConfigHelper->getAcronymForProductConfig(config); deviceString << "0x" << std::hex << deviceId; std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", deviceString.str()}; oclocArgHelperWithoutInput->getPrinterRef().setSuppressMessages(false); testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); EXPECT_EQ(pOfflineCompiler->getHardwareInfo().platform.usDeviceID, deviceId); auto output = testing::internal::GetCapturedStdout(); std::stringstream resString; resString << "Auto-detected target based on " << deviceString.str() << " device id: " << productString.str() << "\n"; EXPECT_NE(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), resString.str().c_str()); EXPECT_EQ(CL_SUCCESS, retVal); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, givenIncorrectDeviceIdHexThenInvalidDeviceIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", "0x0"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), "Could not determine device target: 0x0.\nError: Cannot get HW Info for device 0x0.\n"); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, givenDeviceNumerationWithMissingRevisionValueWhenInvalidPatternIsPassedThenInvalidDeviceIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", "9.1."}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), "Could not determine device target: 9.1..\nError: Cannot get HW Info for device 9.1..\n"); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, givenDeviceNumerationWithInvalidPatternThenInvalidDeviceIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", "9.1.."}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), "Could not determine device target: 9.1...\nError: Cannot get HW Info for device 9.1...\n"); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, givenDeviceNumerationWithMissingMajorValueWhenInvalidPatternIsPassedThenInvalidDeviceIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", ".1.2"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), "Could not determine device target: .1.2.\nError: Cannot get HW Info for device .1.2.\n"); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, givenDeviceNumerationWhenInvalidRevisionValueIsPassedThenInvalidDeviceIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", "9.0.a"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), "Could not determine device target: 9.0.a.\nError: Cannot get HW Info for device 9.0.a.\n"); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, givenDeviceNumerationWhenInvalidMinorValueIsPassedThenInvalidDeviceIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", "9.a"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), "Could not determine device target: 9.a.\nError: Cannot get HW Info for device 9.a.\n"); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, givenDeviceNumerationWhenPassedValuesAreOutOfRangeThenInvalidDeviceIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", "256.350"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), "Could not determine device target: 256.350.\nError: Cannot get HW Info for device 256.350.\n"); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, givenDeviceIpVersionWhenPassedValueNotExistThenInvalidDeviceIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", "1234"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), "Could not determine device target: 1234.\nError: Cannot get HW Info for device 1234.\n"); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, givenInitHardwareInfowhenDeviceConfigContainsDeviceIdsThenSetFirstDeviceId) { MockOfflineCompiler mockOfflineCompiler; auto &allEnabledDeviceConfigs = mockOfflineCompiler.argHelper->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { GTEST_SKIP(); } std::vector deviceIdsForTests = {0xfffd, 0xfffe, 0xffff}; for (auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { mockOfflineCompiler.deviceName = ProductConfigHelper::parseMajorMinorRevisionValue(deviceMapConfig.aotConfig); deviceMapConfig.deviceIds = &deviceIdsForTests; break; } } mockOfflineCompiler.initHardwareInfo(mockOfflineCompiler.deviceName); EXPECT_EQ(mockOfflineCompiler.hwInfo.platform.eProductFamily, productFamily); EXPECT_EQ(mockOfflineCompiler.hwInfo.platform.usDeviceID, deviceIdsForTests.front()); } TEST_F(OfflineCompilerTests, givenIncorrectDeviceIdWithIncorrectHexPatternThenInvalidDeviceIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", "0xnonexist"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_STREQ(output.c_str(), "Could not determine device target: 0xnonexist.\nError: Cannot get HW Info for device 0xnonexist.\n"); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, givenDebugOptionThenInternalOptionShouldNotContainKernelDebugEnable) { if (gEnvironment->devicePrefix == "bdw") { GTEST_SKIP(); } std::vector argv = { "ocloc", "-options", "-g", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->initialize(argv.size(), argv); std::string internalOptions = mockOfflineCompiler->internalOptions; EXPECT_FALSE(hasSubstr(internalOptions, "-cl-kernel-debug-enable")); } TEST_F(OfflineCompilerTests, givenDebugOptionAndNonSpirvInputThenOptionsShouldContainDashSOptionAppendedAutomatically) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); mockOfflineCompiler->uniqueHelper->callBaseFileExists = false; mockOfflineCompiler->uniqueHelper->callBaseLoadDataFromFile = false; mockOfflineCompiler->uniqueHelper->filesMap["some_input.cl"] = ""; std::vector argv = { "ocloc", "-q", "-options", "-g", "-file", "some_input.cl", "-device", gEnvironment->devicePrefix.c_str()}; mockOfflineCompiler->initialize(argv.size(), argv); const auto &options = mockOfflineCompiler->options; std::string appendedOption{"-s \"some_input.cl\""}; EXPECT_TRUE(hasSubstr(options, appendedOption)); } TEST_F(OfflineCompilerTests, givenDebugOptionAndNonSpirvInputWhenFilenameIsSeparatedWithSpacesThenAppendedSourcePathIsSetCorrectly) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); mockOfflineCompiler->uniqueHelper->callBaseFileExists = false; mockOfflineCompiler->uniqueHelper->callBaseLoadDataFromFile = false; mockOfflineCompiler->uniqueHelper->filesMap["filename with spaces.cl"] = ""; std::vector argv = { "ocloc", "-q", "-options", "-g", "-file", "filename with spaces.cl", "-device", gEnvironment->devicePrefix.c_str()}; const auto result = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, result); const auto &options = mockOfflineCompiler->options; std::string appendedOption{"-s \"filename with spaces.cl\""}; EXPECT_TRUE(hasSubstr(options, appendedOption)); } TEST_F(OfflineCompilerTests, givenDebugOptionAndSpirvInputThenDoNotAppendDashSOptionAutomatically) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); mockOfflineCompiler->uniqueHelper->callBaseFileExists = false; mockOfflineCompiler->uniqueHelper->callBaseLoadDataFromFile = false; mockOfflineCompiler->uniqueHelper->filesMap["some_input.spirv"] = ""; std::vector argvSpirvInput = { "ocloc", "-q", "-spirv_input", "-options", "-g", "-file", "some_input.spirv", "-device", gEnvironment->devicePrefix.c_str()}; mockOfflineCompiler->initialize(argvSpirvInput.size(), argvSpirvInput); const auto &options = mockOfflineCompiler->options; std::string notAppendedOption{"-s \"some_input.spirv\""}; EXPECT_FALSE(hasSubstr(options, notAppendedOption)); } TEST_F(OfflineCompilerTests, givenDebugOptionWhenCompilerIsCMCThenDoNotAppendDashSOptionAutomatically) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); mockOfflineCompiler->uniqueHelper->callBaseFileExists = false; mockOfflineCompiler->uniqueHelper->callBaseLoadDataFromFile = false; mockOfflineCompiler->uniqueHelper->filesMap["some_input.cl"] = ""; std::vector argvSpirvInput = { "ocloc", "-q", "-options", "-g -cmc", "-file", "some_input.cl", "-device", gEnvironment->devicePrefix.c_str()}; mockOfflineCompiler->initialize(argvSpirvInput.size(), argvSpirvInput); const auto &options = mockOfflineCompiler->options; std::string notAppendedOption{"-s \"some_input.spirv\""}; EXPECT_FALSE(hasSubstr(options, notAppendedOption)); } TEST_F(OfflineCompilerTests, givenDebugOptionAndDashSOptionPassedManuallyThenDoNotAppendDashSOptionAutomatically) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); mockOfflineCompiler->uniqueHelper->callBaseFileExists = false; mockOfflineCompiler->uniqueHelper->callBaseLoadDataFromFile = false; mockOfflineCompiler->uniqueHelper->filesMap["some_input.cl"] = ""; std::vector argvDashSPassed = { "ocloc", "-q", "-options", "-g -s \"mockPath/some_input.cl\"", "-file", "some_input.cl", "-device", gEnvironment->devicePrefix.c_str()}; mockOfflineCompiler->initialize(argvDashSPassed.size(), argvDashSPassed); const auto &options = mockOfflineCompiler->options; std::string appendedOption{"-s"}; auto occurrences = 0u; size_t pos = 0u; while ((pos = options.find(appendedOption, pos)) != std::string::npos) { occurrences++; pos++; } EXPECT_EQ(1u, occurrences); } TEST_F(OfflineCompilerTests, givenDashGInBiggerOptionStringWhenInitializingThenInternalOptionsShouldNotContainKernelDebugEnable) { std::vector argv = { "ocloc", "-options", "-gNotRealDashGOption", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->initialize(argv.size(), argv); std::string internalOptions = mockOfflineCompiler->internalOptions; EXPECT_FALSE(hasSubstr(internalOptions, "-cl-kernel-debug-enable")); } TEST_F(OfflineCompilerTests, givenExcludeIrFromZebinInternalOptionWhenInitIsPerformedThenIrExcludeFlagsShouldBeUnified) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-internal_options", "-ze-exclude-ir-from-zebin", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.initialize(argv.size(), argv); EXPECT_TRUE(mockOfflineCompiler.excludeIr); } TEST_F(OfflineCompilerTests, givenValidArgumentsAndFclInitFailureWhenInitIsPerformedThenFailureIsPropagatedAndErrorIsPrinted) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.mockFclFacade->shouldFailLoadingOfFclLib = true; testing::internal::CaptureStdout(); const auto initResult = mockOfflineCompiler.initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, initResult); auto output = testing::internal::GetCapturedStdout(); testing::internal::CaptureStdout(); const auto buildResult = mockOfflineCompiler.build(); output = testing::internal::GetCapturedStdout(); std::stringstream expectedErrorMessage; expectedErrorMessage << "Error! Loading of FCL library has failed! Filename: " << Os::frontEndDllName << "\n" << "Error! FCL initialization failure. Error code = -6\n"; EXPECT_EQ(OCLOC_OUT_OF_HOST_MEMORY, buildResult); EXPECT_EQ(expectedErrorMessage.str(), output); } TEST_F(OfflineCompilerTests, givenValidArgumentsAndIgcInitFailureWhenInitIsPerformedThenFailureIsPropagatedAndErrorIsPrinted) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.mockIgcFacade->shouldFailLoadingOfIgcLib = true; testing::internal::CaptureStdout(); const auto initResult = mockOfflineCompiler.initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, initResult); auto output = testing::internal::GetCapturedStdout(); testing::internal::CaptureStdout(); const auto buildResult = mockOfflineCompiler.build(); output = testing::internal::GetCapturedStdout(); std::stringstream expectedErrorMessage; expectedErrorMessage << "Error! Loading of IGC library has failed! Filename: " << Os::igcDllName << "\n" << "Error! IGC initialization failure. Error code = -6\n"; EXPECT_EQ(OCLOC_OUT_OF_HOST_MEMORY, buildResult); EXPECT_EQ(expectedErrorMessage.str(), output); } TEST_F(OfflineCompilerTests, givenExcludeIrArgumentWhenInitIsPerformedThenIrExcludeFlagsShouldBeUnified) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-exclude_ir", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.initialize(argv.size(), argv); const auto expectedInternalOption{"-ze-exclude-ir-from-zebin"}; const auto excludeIrFromZebinEnabled{mockOfflineCompiler.internalOptions.find(expectedInternalOption) != std::string::npos}; EXPECT_TRUE(excludeIrFromZebinEnabled); } TEST_F(OfflineCompilerTests, givenExcludeIrArgumentAndExcludeIrFromZebinInternalOptionWhenInitIsPerformedThenExcludeIrFromZebinInternalOptionOccursJustOnce) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-exclude_ir", "-internal_options", "-ze-exclude-ir-from-zebin", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.initialize(argv.size(), argv); const auto expectedInternalOption{"-ze-exclude-ir-from-zebin"}; const auto firstExcludeIrFromZebin{mockOfflineCompiler.internalOptions.find(expectedInternalOption)}; ASSERT_NE(std::string::npos, firstExcludeIrFromZebin); const auto lastExcludeIrFromZebin{mockOfflineCompiler.internalOptions.rfind(expectedInternalOption)}; EXPECT_EQ(firstExcludeIrFromZebin, lastExcludeIrFromZebin); } bool containsAnyIRSection(ArrayRef elfBinary, std::string &outErrors, std::string &outWarnings) { if (Elf::isElf(elfBinary)) { auto elf = Elf::decodeElf(elfBinary, outErrors, outWarnings); return isAnyIrSectionDefined(elf.sectionHeaders); } auto elf = Elf::decodeElf(elfBinary, outErrors, outWarnings); return isAnyIrSectionDefined(elf.sectionHeaders); } TEST_F(OfflineCompilerTests, givenExcludeIrArgumentWhenGeneratingElfBinaryFromPatchtokensThenIrSectionIsNotPresent) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-exclude_ir", "-device", gEnvironment->devicePrefix.c_str(), "--format", "patchtokens"}; MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.initialize(argv.size(), argv); std::vector storage; iOpenCL::SProgramBinaryHeader headerTok = {}; headerTok.Magic = iOpenCL::MAGIC_CL; headerTok.Version = iOpenCL::CURRENT_ICBE_VERSION; headerTok.GPUPointerSizeInBytes = sizeof(uintptr_t); storage.insert(storage.end(), reinterpret_cast(&headerTok), reinterpret_cast(&headerTok) + sizeof(iOpenCL::SProgramBinaryHeader)); mockOfflineCompiler.genBinary = new char[storage.size()]; mockOfflineCompiler.genBinarySize = storage.size(); memcpy_s(mockOfflineCompiler.genBinary, mockOfflineCompiler.genBinarySize, storage.data(), storage.size()); mockOfflineCompiler.generateElfBinary(); std::string errorReason{}; std::string warning{}; auto hasIR = containsAnyIRSection(mockOfflineCompiler.elfBinary, errorReason, warning); ASSERT_TRUE(errorReason.empty()); ASSERT_TRUE(warning.empty()); EXPECT_FALSE(hasIR); } TEST_F(OfflineCompilerTests, givenLackOfExcludeIrArgumentWhenCompilingKernelThenIrShouldBeIncluded) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.initialize(argv.size(), argv); const auto buildResult{mockOfflineCompiler.build()}; ASSERT_EQ(OCLOC_SUCCESS, buildResult); std::string errorReason{}; std::string warning{}; auto hasIR = containsAnyIRSection(mockOfflineCompiler.elfBinary, errorReason, warning); ASSERT_TRUE(errorReason.empty()); ASSERT_TRUE(warning.empty()); EXPECT_TRUE(hasIR); } TEST_F(OfflineCompilerTests, givenZeroSizeInputFileWhenInitializationIsPerformedThenInvalidFileIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.uniqueHelper->callBaseLoadDataFromFile = false; mockOfflineCompiler.uniqueHelper->shouldLoadDataFromFileReturnZeroSize = true; const auto initResult = mockOfflineCompiler.initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, initResult); const auto buildResult = mockOfflineCompiler.build(); EXPECT_EQ(OCLOC_INVALID_FILE, buildResult); } TEST_F(OfflineCompilerTests, givenInvalidIgcOutputWhenCompilingKernelThenOutOfHostMemoryIsReturned) { MockCompilerDebugVars igcDebugVars{gEnvironment->igcDebugVars}; igcDebugVars.shouldReturnInvalidTranslationOutput = true; NEO::setIgcDebugVars(igcDebugVars); std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; const auto initResult = mockOfflineCompiler.initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, initResult); const auto buildResult{mockOfflineCompiler.build()}; EXPECT_EQ(OCLOC_OUT_OF_HOST_MEMORY, buildResult); NEO::setIgcDebugVars(gEnvironment->igcDebugVars); } TEST_F(OfflineCompilerTests, givenIgcBuildFailureWhenCompilingKernelThenBuildProgramFailureIsReturned) { MockCompilerDebugVars igcDebugVars{gEnvironment->igcDebugVars}; igcDebugVars.forceBuildFailure = true; NEO::setIgcDebugVars(igcDebugVars); std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; const auto initResult = mockOfflineCompiler.initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, initResult); const auto buildResult{mockOfflineCompiler.build()}; EXPECT_EQ(OCLOC_BUILD_PROGRAM_FAILURE, buildResult); NEO::setIgcDebugVars(gEnvironment->igcDebugVars); } TEST_F(OfflineCompilerTests, givenInvalidFclOutputWhenCompilingKernelThenOutOfHostMemoryIsReturned) { MockCompilerDebugVars fclDebugVars{gEnvironment->fclDebugVars}; fclDebugVars.shouldReturnInvalidTranslationOutput = true; NEO::setFclDebugVars(fclDebugVars); std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; const auto initResult = mockOfflineCompiler.initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, initResult); const auto buildResult{mockOfflineCompiler.build()}; EXPECT_EQ(OCLOC_OUT_OF_HOST_MEMORY, buildResult); NEO::setFclDebugVars(gEnvironment->fclDebugVars); } TEST_F(OfflineCompilerTests, givenFclTranslationContextCreationFailureWhenCompilingKernelThenOutOfHostMemoryIsReturned) { MockCompilerDebugVars fclDebugVars{gEnvironment->fclDebugVars}; fclDebugVars.shouldFailCreationOfTranslationContext = true; NEO::setFclDebugVars(fclDebugVars); std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; const auto initResult = mockOfflineCompiler.initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, initResult); const auto buildResult{mockOfflineCompiler.build()}; EXPECT_EQ(OCLOC_OUT_OF_HOST_MEMORY, buildResult); NEO::setFclDebugVars(gEnvironment->fclDebugVars); } TEST_F(OfflineCompilerTests, givenFclTranslationContextCreationFailureAndErrorMessageWhenCompilingKernelThenProgramBuildFailureIsReturnedAndBuildLogIsUpdated) { MockCompilerDebugVars fclDebugVars{gEnvironment->fclDebugVars}; fclDebugVars.shouldFailCreationOfTranslationContext = true; fclDebugVars.translationContextCreationError = "Error: Could not create context!"; NEO::setFclDebugVars(fclDebugVars); std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; MockOfflineCompiler mockOfflineCompiler{}; const auto initResult = mockOfflineCompiler.initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, initResult); const auto buildResult{mockOfflineCompiler.build()}; EXPECT_EQ(OCLOC_BUILD_PROGRAM_FAILURE, buildResult); EXPECT_EQ("Error: Could not create context!", mockOfflineCompiler.getBuildLog()); NEO::setFclDebugVars(gEnvironment->fclDebugVars); } TEST_F(OfflineCompilerTests, givenVariousClStdValuesWhenCompilingSourceThenCorrectExtensionsArePassed) { std::string clStdOptionValues[] = {"", "-cl-std=CL1.2", "-cl-std=CL2.0", "-cl-std=CL3.0"}; for (auto &clStdOptionValue : clStdOptionValues) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; if (!clStdOptionValue.empty()) { argv.push_back("-options"); argv.push_back(clStdOptionValue); } auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->initialize(argv.size(), argv); std::string internalOptions = mockOfflineCompiler->internalOptions; std::string oclVersionOption = getOclVersionCompilerInternalOption(mockOfflineCompiler->hwInfo.capabilityTable.clVersionSupport); EXPECT_TRUE(hasSubstr(internalOptions, oclVersionOption)); if (clStdOptionValue == "-cl-std=CL2.0") { auto expectedRegex = std::string{"cl_khr_3d_image_writes"}; if (mockOfflineCompiler->hwInfo.capabilityTable.supportsImages) { expectedRegex += ".+" + std::string{"cl_khr_3d_image_writes"}; } EXPECT_TRUE(containsRegex(internalOptions, expectedRegex)); } OpenClCFeaturesContainer openclCFeatures; auto compilerProductHelper = CompilerProductHelper::create(mockOfflineCompiler->hwInfo.platform.eProductFamily); getOpenclCFeaturesList(mockOfflineCompiler->hwInfo, openclCFeatures, *compilerProductHelper.get(), nullptr); for (auto &feature : openclCFeatures) { if (clStdOptionValue == "-cl-std=CL3.0") { EXPECT_TRUE(hasSubstr(internalOptions, std::string{feature.name})); } else { EXPECT_FALSE(hasSubstr(internalOptions, std::string{feature.name})); } } if (mockOfflineCompiler->hwInfo.capabilityTable.supportsImages) { EXPECT_TRUE(hasSubstr(internalOptions, CompilerOptions::enableImageSupport.data())); } else { EXPECT_FALSE(hasSubstr(internalOptions, CompilerOptions::enableImageSupport.data())); } } } TEST_F(OfflineCompilerTests, GivenArgsWhenBuildingThenBuildSucceeds) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "--format", "patchtokens"}; pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pOfflineCompiler); EXPECT_EQ(CL_SUCCESS, retVal); testing::internal::CaptureStdout(); retVal = pOfflineCompiler->build(); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(compilerOutputExists("copybuffer", "bc") || compilerOutputExists("copybuffer", "spv")); EXPECT_FALSE(compilerOutputExists("copybuffer", "gen")); EXPECT_TRUE(compilerOutputExists("copybuffer", "bin")); std::string buildLog = pOfflineCompiler->getBuildLog(); EXPECT_STREQ(buildLog.c_str(), ""); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenArgsWhenBuildingWithDeviceConfigValueThenBuildSucceeds) { auto &allEnabledDeviceConfigs = oclocArgHelperWithoutInput->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { return; } std::string configStr; for (auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { configStr = ProductConfigHelper::parseMajorMinorRevisionValue(deviceMapConfig.aotConfig); break; } } std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", configStr, "--format", "patchtokens"}; pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pOfflineCompiler); EXPECT_EQ(CL_SUCCESS, retVal); testing::internal::CaptureStdout(); retVal = pOfflineCompiler->build(); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(compilerOutputExists("copybuffer", "bc") || compilerOutputExists("copybuffer", "spv")); EXPECT_FALSE(compilerOutputExists("copybuffer", "gen")); EXPECT_TRUE(compilerOutputExists("copybuffer", "bin")); std::string buildLog = pOfflineCompiler->getBuildLog(); EXPECT_STREQ(buildLog.c_str(), ""); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenArgsWhenBuildingWithDeviceIpVersionValueThenBuildSucceeds) { auto &allEnabledDeviceConfigs = oclocArgHelperWithoutInput->productConfigHelper->getDeviceAotInfo(); if (allEnabledDeviceConfigs.empty()) { return; } std::stringstream ipVersion; for (auto &deviceMapConfig : allEnabledDeviceConfigs) { if (productFamily == deviceMapConfig.hwInfo->platform.eProductFamily) { ipVersion << deviceMapConfig.aotConfig.value; break; } } std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", ipVersion.str(), "--format", "patchtokens"}; pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pOfflineCompiler); EXPECT_EQ(CL_SUCCESS, retVal); testing::internal::CaptureStdout(); retVal = pOfflineCompiler->build(); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(compilerOutputExists("copybuffer", "bc") || compilerOutputExists("copybuffer", "spv")); EXPECT_FALSE(compilerOutputExists("copybuffer", "gen")); EXPECT_TRUE(compilerOutputExists("copybuffer", "bin")); std::string buildLog = pOfflineCompiler->getBuildLog(); EXPECT_STREQ(buildLog.c_str(), ""); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenLlvmTextWhenBuildingThenBuildSucceeds) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-llvm_text", "--format", "patchtokens"}; pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pOfflineCompiler); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pOfflineCompiler->build(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(compilerOutputExists("copybuffer", "ll")); EXPECT_FALSE(compilerOutputExists("copybuffer", "gen")); EXPECT_TRUE(compilerOutputExists("copybuffer", "bin")); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, WhenGenFileFlagIsNotProvidedThenGenFileIsNotCreated) { uint32_t numOutputs = 0u; uint64_t *lenOutputs = nullptr; uint8_t **dataOutputs = nullptr; char **nameOutputs = nullptr; std::string filePath = clFiles + "copybuffer.cl"; bool isSpvFile = false; bool isGenFile = false; bool isBinFile = false; const char *argv[] = { "ocloc", "-q", "-file", filePath.c_str(), "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, &numOutputs, &dataOutputs, &lenOutputs, &nameOutputs); EXPECT_EQ(retVal, CL_SUCCESS); EXPECT_EQ(numOutputs, 3u); for (unsigned int i = 0; i < numOutputs; i++) { std::string nameOutput(nameOutputs[i]); if (nameOutput.find(".spv") != std::string::npos) { isSpvFile = true; } if (nameOutput.find(".gen") != std::string::npos) { isGenFile = true; } if (nameOutput.find(".bin") != std::string::npos) { isBinFile = true; } } EXPECT_TRUE(isSpvFile); EXPECT_FALSE(isGenFile); EXPECT_TRUE(isBinFile); oclocFreeOutput(&numOutputs, &dataOutputs, &lenOutputs, &nameOutputs); } TEST_F(OfflineCompilerTests, WhenGenFileFlagIsProvidedThenGenFileIsCreated) { uint32_t numOutputs = 0u; uint64_t *lenOutputs = nullptr; uint8_t **dataOutputs = nullptr; char **nameOutputs = nullptr; std::string filePath = clFiles + "copybuffer.cl"; bool isSpvFile = false; bool isGenFile = false; bool isBinFile = false; const char *argv[] = { "ocloc", "-q", "-gen_file", "-file", filePath.c_str(), "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, &numOutputs, &dataOutputs, &lenOutputs, &nameOutputs); EXPECT_EQ(retVal, CL_SUCCESS); EXPECT_EQ(numOutputs, 4u); for (unsigned int i = 0; i < numOutputs; i++) { std::string nameOutput(nameOutputs[i]); if (nameOutput.find(".spv") != std::string::npos) { isSpvFile = true; } if (nameOutput.find(".gen") != std::string::npos) { isGenFile = true; } if (nameOutput.find(".bin") != std::string::npos) { isBinFile = true; } } EXPECT_TRUE(isSpvFile); EXPECT_TRUE(isGenFile); EXPECT_TRUE(isBinFile); oclocFreeOutput(&numOutputs, &dataOutputs, &lenOutputs, &nameOutputs); } TEST_F(OfflineCompilerTests, WhenFclNotNeededThenDontLoadIt) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-spirv_input"}; MockOfflineCompiler offlineCompiler; testing::internal::CaptureStdout(); auto ret = offlineCompiler.initialize(argv.size(), argv, true); EXPECT_EQ(OCLOC_SUCCESS, ret); ret = offlineCompiler.build(); EXPECT_EQ(OCLOC_SUCCESS, ret); EXPECT_FALSE(offlineCompiler.fclFacade->isInitialized()); EXPECT_TRUE(offlineCompiler.igcFacade->isInitialized()); std::string output = testing::internal::GetCapturedStdout(); auto expectedString = "Compilation from IR - skipping loading of FCL"; EXPECT_TRUE(hasSubstr(output, expectedString)); } TEST_F(OfflineCompilerTests, WhenParsingBinToCharArrayThenCorrectFileIsGenerated) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); // clang-format off uint8_t binary[] = { 0x02, 0x23, 0x3, 0x40, 0x56, 0x7, 0x80, 0x90, 0x1, 0x03, 0x34, 0x5, 0x60, 0x78, 0x9, 0x66, 0xff, 0x10, 0x10, 0x10, 0x02, 0x23, 0x3, 0x40, 0x56, 0x7, 0x80, 0x90, 0x1, 0x03, 0x34, 0x5, 0x60, 0x78, 0x9, 0x66, 0xff, }; // clang-format on std::string devicePrefix = gEnvironment->devicePrefix; std::string fileName = "scheduler"; std::string retArray = pOfflineCompiler->parseBinAsCharArray(binary, sizeof(binary), fileName); std::string target = "#include \n" "#include \n\n" "size_t SchedulerBinarySize_" + devicePrefix + " = 37;\n" "uint32_t SchedulerBinary_" + devicePrefix + "[10] = {\n" " 0x40032302, 0x90800756, 0x05340301, 0x66097860, 0x101010ff, 0x40032302, 0x90800756, 0x05340301, \n" " 0x66097860, 0xff000000};\n"; EXPECT_EQ(retArray, target); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenCppFileWhenBuildingThenBuildSucceeds) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-cpp_file", "--format", "patchtokens"}; pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pOfflineCompiler); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pOfflineCompiler->build(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(compilerOutputExists("copybuffer", "cpp")); EXPECT_TRUE(compilerOutputExists("copybuffer", "bc") || compilerOutputExists("copybuffer", "spv")); EXPECT_FALSE(compilerOutputExists("copybuffer", "gen")); EXPECT_TRUE(compilerOutputExists("copybuffer", "bin")); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenOutputDirWhenBuildingThenBuildSucceeds) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-out_dir", "offline_compiler_test"}; pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pOfflineCompiler); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pOfflineCompiler->build(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(compilerOutputExists("offline_compiler_test/copybuffer", "bc") || compilerOutputExists("offline_compiler_test/copybuffer", "spv")); EXPECT_FALSE(compilerOutputExists("offline_compiler_test/copybuffer", "gen")); EXPECT_TRUE(compilerOutputExists("offline_compiler_test/copybuffer", "bin")); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenHelpOptionThenBuildDoesNotOccur) { std::vector argv = { "ocloc", "--help"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); std::string output = testing::internal::GetCapturedStdout(); EXPECT_STRNE("", output.c_str()); EXPECT_EQ(OCLOC_SUCCESS, retVal); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenInvalidFileWhenBuildingThenInvalidFileErrorIsReturned) { debugManager.flags.PrintDebugMessages.set(true); std::vector argv = { "ocloc", "-file", clFiles + "ImANaughtyFile.cl", "-device", gEnvironment->devicePrefix.c_str()}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); retVal = pOfflineCompiler->build(); std::string output = testing::internal::GetCapturedStdout(); EXPECT_STRNE(output.c_str(), ""); EXPECT_EQ(OCLOC_INVALID_FILE, retVal); debugManager.flags.PrintDebugMessages.set(false); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenInvalidFlagWhenBuildingThenInvalidCommandLineErrorIsReturned) { std::vector argv = { "ocloc", "-n", clFiles + "ImANaughtyFile.cl", "-device", gEnvironment->devicePrefix.c_str()}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); std::string output = testing::internal::GetCapturedStdout(); EXPECT_STRNE(output.c_str(), ""); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, retVal); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenInvalidOptionsWhenBuildingThenInvalidCommandLineErrorIsReturned) { std::vector argvA = { "ocloc", "-file", }; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argvA.size(), argvA, true, retVal, oclocArgHelperWithoutInput.get()); std::string output = testing::internal::GetCapturedStdout(); EXPECT_STRNE(output.c_str(), ""); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, retVal); delete pOfflineCompiler; std::vector argvB = { "ocloc", "-file", clFiles + "ImANaughtyFile.cl", "-device"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argvB.size(), argvB, true, retVal, oclocArgHelperWithoutInput.get()); output = testing::internal::GetCapturedStdout(); EXPECT_STRNE(output.c_str(), ""); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, retVal); delete pOfflineCompiler; } TEST_F(OfflineCompilerTests, GivenNonexistantDeviceWhenCompilingThenInvalidDeviceErrorAndErrorMessageAreReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", "foobar"}; testing::internal::CaptureStdout(); pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); std::string output = testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.c_str(), "Could not determine device target: foobar.\nError: Cannot get HW Info for device foobar.\n"); EXPECT_EQ(nullptr, pOfflineCompiler); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } TEST_F(OfflineCompilerTests, GivenInvalidKernelWhenBuildingThenBuildProgramFailureErrorIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "shouldfail.cl", "-qq", "-device", gEnvironment->devicePrefix.c_str()}; pOfflineCompiler = OfflineCompiler::create(argv.size(), argv, true, retVal, oclocArgHelperWithoutInput.get()); EXPECT_NE(nullptr, pOfflineCompiler); EXPECT_EQ(CL_SUCCESS, retVal); gEnvironment->SetInputFileName("invalid_file_name"); testing::internal::CaptureStdout(); retVal = pOfflineCompiler->build(); EXPECT_EQ(CL_BUILD_PROGRAM_FAILURE, retVal); std::string output = testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.c_str(), ""); std::string buildLog = pOfflineCompiler->getBuildLog(); EXPECT_STRNE(buildLog.c_str(), ""); gEnvironment->SetInputFileName("copybuffer"); delete pOfflineCompiler; } TEST(OfflineCompilerTest, GivenAllowCachingWhenBuildingThenBinaryIsCached) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-allow_caching", "-cache_dir", "cache_dir"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->interceptCreatedDirs = true; auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); auto cacheMock = new CompilerCacheMock(); mockOfflineCompiler->cache.reset(cacheMock); retVal = mockOfflineCompiler->build(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(cacheMock->cacheInvoked, 0u); } TEST(OfflineCompilerTest, GivenCachedBinaryWhenBuildIrBinaryThenIrBinaryIsLoaded) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-allow_caching"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->interceptCreatedDirs = true; auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); auto cacheMock = new CompilerCacheMock(); cacheMock->loadResult = true; mockOfflineCompiler->cache.reset(cacheMock); retVal = mockOfflineCompiler->buildIrBinary(); EXPECT_EQ(CL_SUCCESS, retVal); ASSERT_NE(nullptr, mockOfflineCompiler->irBinary); EXPECT_NE(0u, static_cast(mockOfflineCompiler->irBinarySize)); } TEST(OfflineCompilerTest, GivenCachedBinaryWhenBuildSourceCodeThenSuccessIsReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-allow_caching"}; { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->interceptCreatedDirs = true; auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); auto cacheMock = new CompilerCacheMock(); mockOfflineCompiler->cache.reset(cacheMock); cacheMock->numberOfLoadResult = 1u; mockOfflineCompiler->sourceCode = "__kernel void k(){}"; retVal = mockOfflineCompiler->buildSourceCode(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(nullptr, mockOfflineCompiler->genBinary); EXPECT_NE(0u, static_cast(mockOfflineCompiler->genBinarySize)); } { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->interceptCreatedDirs = true; auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); auto cacheMock = new CompilerCacheMock(); mockOfflineCompiler->cache.reset(cacheMock); cacheMock->numberOfLoadResult = 2u; mockOfflineCompiler->sourceCode = "__kernel void k(){}"; retVal = mockOfflineCompiler->buildSourceCode(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(nullptr, mockOfflineCompiler->genBinary); EXPECT_NE(0u, static_cast(mockOfflineCompiler->genBinarySize)); } { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); argv.push_back("-options"); argv.push_back("-g"); auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); auto cacheMock = new CompilerCacheMock(); mockOfflineCompiler->cache.reset(cacheMock); cacheMock->numberOfLoadResult = 3u; mockOfflineCompiler->sourceCode = "__kernel void k(){}"; retVal = mockOfflineCompiler->buildSourceCode(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(nullptr, mockOfflineCompiler->debugDataBinary); EXPECT_NE(0u, static_cast(mockOfflineCompiler->debugDataBinarySize)); } } TEST(OfflineCompilerTest, GivenGenBinaryWhenGenerateElfBinaryThenElfIsLoaded) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-allow_caching"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->interceptCreatedDirs = true; auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); auto cacheMock = new CompilerCacheMock(); cacheMock->loadResult = true; mockOfflineCompiler->cache.reset(cacheMock); mockOfflineCompiler->genBinary = new char[1]; mockOfflineCompiler->genBinarySize = sizeof(char); retVal = mockOfflineCompiler->generateElfBinary(); EXPECT_TRUE(retVal); EXPECT_FALSE(mockOfflineCompiler->elfBinary.empty()); EXPECT_NE(0u, static_cast(mockOfflineCompiler->elfBinarySize)); } TEST(OfflineCompilerTest, givenAllowCachingWhenBuildSourceCodeThenGenBinaryIsCachedUsingHashBasedOnNonNullIrBinary) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-allow_caching"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); auto cacheMock = new CompilerCacheMock(); mockOfflineCompiler->cache.reset(cacheMock); mockOfflineCompiler->sourceCode = "__kernel void k(){}"; retVal = mockOfflineCompiler->buildSourceCode(); EXPECT_EQ(CL_SUCCESS, retVal); ASSERT_NE(nullptr, mockOfflineCompiler->irBinary); ASSERT_NE(0u, mockOfflineCompiler->irBinarySize); // 0 - buildIrBinary > irBinary // 1 - buildSourceCode > genBinary // 2 - buildSourceCode > debugDataBinary const auto givenCacheBinaryGenHash = cacheMock->cacheBinaryKernelFileHashes[1]; const auto expectedCacheBinaryGenHash = cacheMock->getCachedFileName(mockOfflineCompiler->getHardwareInfo(), ArrayRef(mockOfflineCompiler->irBinary, mockOfflineCompiler->irBinarySize), mockOfflineCompiler->options, mockOfflineCompiler->internalOptions, ArrayRef(), ArrayRef(), std::string(mockOfflineCompiler->igcFacade->getIgcRevision()), mockOfflineCompiler->igcFacade->getIgcLibSize(), mockOfflineCompiler->igcFacade->getIgcLibMTime()); EXPECT_EQ(expectedCacheBinaryGenHash, givenCacheBinaryGenHash); } TEST(OfflineCompilerTest, WhenParsingCmdLineThenOptionsAreReadCorrectly) { std::vector argv = { "ocloc", NEO::CompilerOptions::greaterThan4gbBuffersRequired.data()}; auto mockOfflineCompiler = std::make_unique(); testing::internal::CaptureStdout(); mockOfflineCompiler->parseCommandLine(argv.size(), argv); std::string output = testing::internal::GetCapturedStdout(); std::string internalOptions = mockOfflineCompiler->internalOptions; size_t found = internalOptions.find(argv.begin()[1]); EXPECT_NE(std::string::npos, found); } TEST(OfflineCompilerTest, GivenUnknownIsaConfigValueWhenInitHardwareInfoThenInvalidDeviceIsReturned) { auto mockOfflineCompiler = std::make_unique(); auto deviceName = ProductConfigHelper::parseMajorMinorRevisionValue(AOT::UNKNOWN_ISA); std::stringstream resString; auto retVal = mockOfflineCompiler->initHardwareInfoForProductConfig(deviceName); EXPECT_EQ(retVal, OCLOC_INVALID_DEVICE); } TEST(OfflineCompilerTest, GivenUnsupportedDeviceConfigWhenInitHardwareInfoThenInvalidDeviceIsReturned) { auto mockOfflineCompiler = std::make_unique(); auto deviceName = "00.01.02"; std::stringstream resString; auto retVal = mockOfflineCompiler->initHardwareInfoForProductConfig(deviceName); EXPECT_EQ(retVal, OCLOC_INVALID_DEVICE); } TEST(OfflineCompilerTest, GivenUnsupportedDeviceWhenInitHardwareInfoThenInvalidDeviceIsReturned) { auto mockOfflineCompiler = std::make_unique(); auto deviceName = "unk"; std::stringstream resString; testing::internal::CaptureStdout(); auto retVal = mockOfflineCompiler->initHardwareInfo(deviceName); EXPECT_EQ(retVal, OCLOC_INVALID_DEVICE); auto output = testing::internal::GetCapturedStdout(); resString << "Could not determine device target: " << deviceName << ".\n"; EXPECT_STREQ(output.c_str(), resString.str().c_str()); } TEST(OfflineCompilerTest, givenStatelessToStatefulOptimizationEnabledWhenDebugSettingsAreParsedThenOptimizationStringIsPresent) { DebugManagerStateRestore stateRestore; MockOfflineCompiler mockOfflineCompiler; debugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.set(1); mockOfflineCompiler.parseDebugSettings(); std::string internalOptions = mockOfflineCompiler.internalOptions; size_t found = internalOptions.find(NEO::CompilerOptions::hasBufferOffsetArg.data()); EXPECT_NE(std::string::npos, found); } TEST(OfflineCompilerTest, givenStatelessToStatefullOptimizationEnabledWhenDebugSettingsAreParsedThenOptimizationStringIsSetToDefault) { DebugManagerStateRestore stateRestore; MockOfflineCompiler mockOfflineCompiler; debugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.set(-1); mockOfflineCompiler.parseDebugSettings(); std::string internalOptions = mockOfflineCompiler.internalOptions; size_t found = internalOptions.find(NEO::CompilerOptions::hasBufferOffsetArg.data()); EXPECT_NE(std::string::npos, found); } TEST(OfflineCompilerTest, GivenDelimitersWhenGettingStringThenParseIsCorrect) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); std::string kernelFileName(sharedBuiltinsDir + "/copy_buffer_to_buffer.builtin_kernel"); size_t srcSize = 0; auto ptrSrc = loadDataFromFile(kernelFileName.c_str(), srcSize); const std::string src = ptrSrc.get(); ASSERT_EQ(srcSize, src.size()); // assert that pattern was found ASSERT_NE(std::string::npos, src.find("R\"===(")); ASSERT_NE(std::string::npos, src.find(")===\"")); auto dst = mockOfflineCompiler->getStringWithinDelimiters(src); size_t size = dst.size(); char nullChar = '\0'; EXPECT_EQ(nullChar, dst[size - 1]); // expect that pattern was not found EXPECT_EQ(std::string::npos, dst.find("R\"===(")); EXPECT_EQ(std::string::npos, dst.find(")===\"")); } TEST(OfflineCompilerTest, WhenConvertingToPascalCaseThenResultIsCorrect) { EXPECT_EQ(0, strcmp("AuxTranslation", convertToPascalCase("aux_translation").c_str())); EXPECT_EQ(0, strcmp("CopyBufferToBuffer", convertToPascalCase("copy_buffer_to_buffer").c_str())); EXPECT_EQ(0, strcmp("CopyBufferRect", convertToPascalCase("copy_buffer_rect").c_str())); EXPECT_EQ(0, strcmp("FillBuffer", convertToPascalCase("fill_buffer").c_str())); EXPECT_EQ(0, strcmp("CopyBufferToImage3d", convertToPascalCase("copy_buffer_to_image3d").c_str())); EXPECT_EQ(0, strcmp("CopyImage3dToBuffer", convertToPascalCase("copy_image3d_to_buffer").c_str())); EXPECT_EQ(0, strcmp("CopyImageToImage1d", convertToPascalCase("copy_image_to_image1d").c_str())); EXPECT_EQ(0, strcmp("CopyImageToImage2d", convertToPascalCase("copy_image_to_image2d").c_str())); EXPECT_EQ(0, strcmp("CopyImageToImage3d", convertToPascalCase("copy_image_to_image3d").c_str())); EXPECT_EQ(0, strcmp("FillImage1d", convertToPascalCase("fill_image1d").c_str())); EXPECT_EQ(0, strcmp("FillImage2d", convertToPascalCase("fill_image2d").c_str())); EXPECT_EQ(0, strcmp("FillImage3d", convertToPascalCase("fill_image3d").c_str())); EXPECT_EQ(0, strcmp("VmeBlockMotionEstimateIntel", convertToPascalCase("vme_block_motion_estimate_intel").c_str())); EXPECT_EQ(0, strcmp("VmeBlockAdvancedMotionEstimateCheckIntel", convertToPascalCase("vme_block_advanced_motion_estimate_check_intel").c_str())); EXPECT_EQ(0, strcmp("VmeBlockAdvancedMotionEstimateBidirectionalCheckIntel", convertToPascalCase("vme_block_advanced_motion_estimate_bidirectional_check_intel").c_str())); EXPECT_EQ(0, strcmp("Scheduler", convertToPascalCase("scheduler").c_str())); EXPECT_EQ(0, strcmp("", convertToPascalCase("").c_str())); } TEST(OfflineCompilerTest, GivenValidParamWhenGettingHardwareInfoThenSuccessIsReturned) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); testing::internal::CaptureStdout(); EXPECT_EQ(CL_INVALID_DEVICE, mockOfflineCompiler->initHardwareInfo("invalid")); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(PRODUCT_FAMILY::IGFX_UNKNOWN, mockOfflineCompiler->getHardwareInfo().platform.eProductFamily); EXPECT_EQ(CL_SUCCESS, mockOfflineCompiler->initHardwareInfo(gEnvironment->devicePrefix.c_str())); EXPECT_NE(PRODUCT_FAMILY::IGFX_UNKNOWN, mockOfflineCompiler->getHardwareInfo().platform.eProductFamily); EXPECT_STREQ("Could not determine device target: invalid.\n", output.c_str()); } TEST(OfflineCompilerTest, WhenStoringBinaryThenStoredCorrectly) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); const char pSrcBinary[] = {0x01, 0x02, 0x03, 0x04, 0x05}; const size_t srcBinarySize = sizeof(pSrcBinary); char *pDstBinary = new char[srcBinarySize]; size_t dstBinarySize = srcBinarySize; mockOfflineCompiler->storeBinary(pDstBinary, dstBinarySize, pSrcBinary, srcBinarySize); EXPECT_EQ(0, memcmp(pDstBinary, pSrcBinary, srcBinarySize)); delete[] pDstBinary; } TEST(OfflineCompilerTest, givenErrorStringsWithoutExtraNullCharactersWhenUpdatingBuildLogThenMessageIsCorrect) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); std::string errorString = "Error: undefined variable"; mockOfflineCompiler->updateBuildLog(errorString.c_str(), errorString.length()); EXPECT_EQ(0, errorString.compare(mockOfflineCompiler->getBuildLog())); std::string finalString = "Build failure"; mockOfflineCompiler->updateBuildLog(finalString.c_str(), finalString.length()); EXPECT_EQ(0, (errorString + "\n" + finalString).compare(mockOfflineCompiler->getBuildLog().c_str())); } TEST(OfflineCompilerTest, givenErrorStringsWithExtraNullCharactersWhenUpdatingBuildLogThenMessageIsCorrect) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); std::array errorMessageArray = {"Error: undefined variable\0"}; std::string expectedBuildLogString = "Error: undefined variable"; EXPECT_EQ(errorMessageArray.size(), std::string("Error: undefined variable").length() + 2); mockOfflineCompiler->updateBuildLog(errorMessageArray.data(), errorMessageArray.size()); EXPECT_EQ(mockOfflineCompiler->getBuildLog(), expectedBuildLogString); std::array additionalErrorMessageArray = {"Build failure\0"}; expectedBuildLogString = "Error: undefined variable\n" "Build failure"; EXPECT_EQ(additionalErrorMessageArray.size(), std::string("Build failure").length() + 2); mockOfflineCompiler->updateBuildLog(additionalErrorMessageArray.data(), additionalErrorMessageArray.size()); EXPECT_EQ(mockOfflineCompiler->getBuildLog(), expectedBuildLogString); } TEST(OfflineCompilerTest, givenValidSizeAndInvalidLogPointerWhenUpdatingBuildLogThenNothingIsWritten) { MockOfflineCompiler mockOfflineCompiler{}; const char *const invalidLog{nullptr}; const size_t logSize{7}; mockOfflineCompiler.updateBuildLog(invalidLog, logSize); const auto buildLog = mockOfflineCompiler.getBuildLog(); EXPECT_TRUE(buildLog.empty()) << buildLog; } TEST(OfflineCompilerTest, GivenSourceCodeWhenBuildingThenSuccessIsReturned) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto retVal = mockOfflineCompiler->buildSourceCode(); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(nullptr, mockOfflineCompiler->genBinary); EXPECT_EQ(0u, mockOfflineCompiler->genBinarySize); retVal = mockOfflineCompiler->build(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(nullptr, mockOfflineCompiler->genBinary); EXPECT_NE(0u, mockOfflineCompiler->genBinarySize); } TEST(OfflineCompilerTest, givenSpvOnlyOptionPassedWhenCmdLineParsedThenGenerateOnlySpvFile) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-output", "myOutputFileName", "-spv_only", "-device", gEnvironment->devicePrefix.c_str()}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "bc") || compilerOutputExists("myOutputFileName", "spv")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "bin")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "gen")); retVal = mockOfflineCompiler->build(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(compilerOutputExists("myOutputFileName", "bc") || compilerOutputExists("myOutputFileName", "spv")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "bin")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "gen")); } TEST(OfflineCompilerTest, GivenKernelWhenNoCharAfterKernelSourceThenBuildWithSuccess) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto retVal = mockOfflineCompiler->buildSourceCode(); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); const char kernelWithNoCharAfterKernel[] = "__kernel void empty(){}"; Source source{reinterpret_cast(kernelWithNoCharAfterKernel), sizeof(kernelWithNoCharAfterKernel), "emptykernel.cl"}; static_cast(mockOfflineCompiler->argHelper)->inputs.push_back(source); std::vector argv = { "ocloc", "-file", "emptykernel.cl", "-device", gEnvironment->devicePrefix.c_str()}; retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); retVal = mockOfflineCompiler->build(); EXPECT_EQ(CL_SUCCESS, retVal); } TEST(OfflineCompilerTest, WhenGeneratingElfBinaryThenBinaryIsCreated) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto retVal = mockOfflineCompiler->generateElfBinary(); EXPECT_FALSE(retVal); iOpenCL::SProgramBinaryHeader binHeader; memset(&binHeader, 0, sizeof(binHeader)); binHeader.Magic = iOpenCL::MAGIC_CL; binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION - 3; binHeader.Device = mockOfflineCompiler->hwInfo.platform.eRenderCoreFamily; binHeader.GPUPointerSizeInBytes = 8; binHeader.NumberOfKernels = 0; binHeader.SteppingId = 0; binHeader.PatchListSize = 0; size_t binSize = sizeof(iOpenCL::SProgramBinaryHeader); mockOfflineCompiler->storeGenBinary(&binHeader, binSize); EXPECT_TRUE(mockOfflineCompiler->elfBinary.empty()); retVal = mockOfflineCompiler->generateElfBinary(); EXPECT_TRUE(retVal); EXPECT_FALSE(mockOfflineCompiler->elfBinary.empty()); } TEST(OfflineCompilerTest, givenInvalidGenBinarySizeAndNotNullPointerWhenGeneratingElfBinaryThenNothingHappensAndFalseIsReturned) { MockOfflineCompiler mockOfflineCompiler; // Destructor of OfflineCompiler will deallocate the memory. mockOfflineCompiler.genBinary = new char[0]; mockOfflineCompiler.genBinarySize = 0; EXPECT_FALSE(mockOfflineCompiler.generateElfBinary()); EXPECT_TRUE(mockOfflineCompiler.elfBinary.empty()); } TEST(OfflineCompilerTest, givenNonEmptyOptionsWhenGeneratingElfBinaryThenOptionsSectionIsIncludedInElfAndTrueIsReturned) { MockOfflineCompiler mockOfflineCompiler; mockOfflineCompiler.options = "-some_option"; // Destructor of OfflineCompiler will deallocate the memory. mockOfflineCompiler.genBinary = new char[8]{}; mockOfflineCompiler.genBinarySize = 8; EXPECT_TRUE(mockOfflineCompiler.generateElfBinary()); ASSERT_FALSE(mockOfflineCompiler.elfBinary.empty()); std::string errorReason{}; std::string warning{}; const auto elf{Elf::decodeElf(mockOfflineCompiler.elfBinary, errorReason, warning)}; ASSERT_TRUE(errorReason.empty()); ASSERT_TRUE(warning.empty()); const auto isOptionsSection = [](const auto §ion) { return section.header && section.header->type == Elf::SHT_OPENCL_OPTIONS; }; const auto isAnyOptionsSectionDefined = std::any_of(elf.sectionHeaders.begin(), elf.sectionHeaders.end(), isOptionsSection); EXPECT_TRUE(isAnyOptionsSectionDefined); } TEST(OfflineCompilerTest, givenOutputNoSuffixFlagAndNonEmptyOutputFileNameAndNonEmptyElfContentWhenWritingOutAllFilesThenFileWithCorrectNameIsWritten) { MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.uniqueHelper->interceptOutput = true; mockOfflineCompiler.outputNoSuffix = true; mockOfflineCompiler.outputFile = "some_output_filename"; mockOfflineCompiler.elfBinary = {49, 50, 51, 52, 53, 54, 55, 56}; // ASCII codes of "12345678" mockOfflineCompiler.writeOutAllFiles(); const auto outputFileIt = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("some_output_filename.bin"); ASSERT_NE(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt); EXPECT_EQ("12345678", outputFileIt->second); } TEST(OfflineCompilerTest, givenOutputNoSuffixFlagAndOutputFileNameWithExtensionOutWhenWritingOutAllFilesThenBinaryFileDoesNotHaveExtensionBinAdded) { MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.uniqueHelper->interceptOutput = true; mockOfflineCompiler.outputNoSuffix = true; mockOfflineCompiler.outputFile = "some_output_filename.out"; mockOfflineCompiler.elfBinary = {49, 50, 51, 52, 53, 54, 55, 56}; // ASCII codes of "12345678" mockOfflineCompiler.writeOutAllFiles(); const auto outputFileIt = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("some_output_filename.out"); ASSERT_NE(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt); mockOfflineCompiler.uniqueHelper->interceptedFiles.clear(); mockOfflineCompiler.outputFile = "some_output_filename.out1"; mockOfflineCompiler.writeOutAllFiles(); const auto outputFileIt2 = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("some_output_filename.out1.bin"); ASSERT_NE(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt2); } TEST(OfflineCompilerTest, givenOutputNoSuffixFlagAndOutputFileNameWithExtensionExeWhenWritingOutAllFilesThenBinaryFileDoesNotHaveExtensionBinAdded) { MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.uniqueHelper->interceptOutput = true; mockOfflineCompiler.outputNoSuffix = true; mockOfflineCompiler.outputFile = "some_output_filename.exe"; mockOfflineCompiler.elfBinary = {49, 50, 51, 52, 53, 54, 55, 56}; // ASCII codes of "12345678" mockOfflineCompiler.writeOutAllFiles(); const auto outputFileIt = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("some_output_filename.exe"); ASSERT_NE(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt); mockOfflineCompiler.uniqueHelper->interceptedFiles.clear(); mockOfflineCompiler.outputFile = "some_output_filename.exe1"; mockOfflineCompiler.writeOutAllFiles(); const auto outputFileIt2 = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("some_output_filename.exe1.bin"); ASSERT_NE(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt2); } TEST(OfflineCompilerTest, givenInputFileNameAndOutputNoSuffixFlagAndEmptyOutputFileNameAndNonEmptyElfContentWhenWritingOutAllFilesThenFileWithTruncatedInputNameIsWritten) { MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.uniqueHelper->interceptOutput = true; mockOfflineCompiler.outputNoSuffix = true; mockOfflineCompiler.inputFile = "/home/important_file.spv"; mockOfflineCompiler.elfBinary = {49, 50, 51, 52, 53, 54, 55, 56}; // ASCII codes of "12345678" mockOfflineCompiler.writeOutAllFiles(); const auto outputFileIt = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("important_file.bin"); ASSERT_NE(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt); EXPECT_EQ("12345678", outputFileIt->second); } TEST(OfflineCompilerTest, givenNonEmptyOutputDirectoryWhenWritingOutAllFilesTheDirectoriesAreCreatedAndFileIsWrittenToIt) { MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.interceptCreatedDirs = true; mockOfflineCompiler.uniqueHelper->interceptOutput = true; mockOfflineCompiler.outputDirectory = "/home/important/compilation"; mockOfflineCompiler.outputNoSuffix = true; mockOfflineCompiler.outputFile = "some_output_filename"; mockOfflineCompiler.elfBinary = {49, 50, 51, 52, 53, 54, 55, 56}; // ASCII codes of "12345678" mockOfflineCompiler.writeOutAllFiles(); ASSERT_EQ(3u, mockOfflineCompiler.createdDirs.size()); EXPECT_EQ("/home", mockOfflineCompiler.createdDirs[0]); EXPECT_EQ("/home/important", mockOfflineCompiler.createdDirs[1]); EXPECT_EQ("/home/important/compilation", mockOfflineCompiler.createdDirs[2]); const auto outputFileIt = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("/home/important/compilation/some_output_filename.bin"); ASSERT_NE(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt); EXPECT_EQ("12345678", outputFileIt->second); } TEST(OfflineCompilerTest, givenBinaryOutputFileWhenWritingOutAllFilesThenOnlyBinaryWithCorrectNameIsCreated) { MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.interceptCreatedDirs = true; mockOfflineCompiler.uniqueHelper->interceptOutput = true; mockOfflineCompiler.binaryOutputFile = "some_output_filename.bin"; mockOfflineCompiler.elfBinary = {49, 50, 51, 52, 53, 54, 55, 56}; // ASCII codes of "12345678" mockOfflineCompiler.irBinary = new char[4]; mockOfflineCompiler.irBinarySize = 4; mockOfflineCompiler.writeOutAllFiles(); const auto outputFileIt = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("some_output_filename.bin"); ASSERT_NE(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt); EXPECT_EQ("12345678", outputFileIt->second); const auto outputFileIt2 = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("some_output_filename.spv"); EXPECT_EQ(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt2); } TEST(OfflineCompilerTest, givenBinaryOutputFileWithSpirvOnlyWhenWritingOutAllFilesThenOnlyBinaryWithCorrectNameIsCreated) { MockOfflineCompiler mockOfflineCompiler{}; mockOfflineCompiler.interceptCreatedDirs = true; mockOfflineCompiler.uniqueHelper->interceptOutput = true; mockOfflineCompiler.binaryOutputFile = "some_output_filename.bin"; mockOfflineCompiler.elfBinary = {0, 0, 0, 0, 0, 0}; mockOfflineCompiler.irBinary = new char[4]; mockOfflineCompiler.irBinarySize = 4; uint8_t data[] = {49, 50, 51, 52}; // ASCII codes of "1234" memcpy(mockOfflineCompiler.irBinary, data, sizeof(data)); mockOfflineCompiler.onlySpirV = true; mockOfflineCompiler.writeOutAllFiles(); const auto outputFileIt = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("some_output_filename.bin"); ASSERT_NE(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt); EXPECT_EQ("1234", outputFileIt->second); const auto outputFileIt2 = mockOfflineCompiler.uniqueHelper->interceptedFiles.find("some_output_filename.spv"); EXPECT_EQ(mockOfflineCompiler.uniqueHelper->interceptedFiles.end(), outputFileIt2); } TEST(OfflineCompilerTest, givenLlvmInputOptionPassedWhenCmdLineParsedThenInputFileLlvmIsSetTrue) { std::vector argv = { "ocloc", "-llvm_input"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); testing::internal::CaptureStdout(); mockOfflineCompiler->parseCommandLine(argv.size(), argv); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(0u, output.size()); bool llvmFileOption = mockOfflineCompiler->inputFileLlvm; EXPECT_TRUE(llvmFileOption); } TEST(OfflineCompilerTest, givenDefaultOfflineCompilerObjectWhenNoOptionsAreChangedThenLlvmInputFileIsFalse) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); bool llvmFileOption = mockOfflineCompiler->inputFileLlvm; EXPECT_FALSE(llvmFileOption); } TEST(OfflineCompilerTest, givenSpirvInputOptionPassedWhenCmdLineParsedThenInputFileSpirvIsSetTrue) { std::vector argv = {"ocloc", "-spirv_input"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); testing::internal::CaptureStdout(); mockOfflineCompiler->parseCommandLine(argv.size(), argv); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(0u, output.size()); EXPECT_TRUE(mockOfflineCompiler->inputFileSpirV); } TEST(OfflineCompilerTest, givenDefaultOfflineCompilerObjectWhenNoOptionsAreChangedThenSpirvInputFileIsFalse) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); EXPECT_FALSE(mockOfflineCompiler->inputFileSpirV); } TEST(OfflineCompilerTest, givenSpirvRepresentationInputWhenBuildSourceCodeIsCalledThenProperTranslationContextIsUsed) { MockOfflineCompiler mockOfflineCompiler; Source source{reinterpret_cast(spirvMagic.data()), spirvMagic.size(), "some_file.spv"}; static_cast(mockOfflineCompiler.argHelper)->inputs.push_back(source); std::vector argv = { "ocloc", "-file", "some_file.spv", "-device", gEnvironment->devicePrefix.c_str()}; testing::internal::CaptureStdout(); struct StdoutCaptureRAII { ~StdoutCaptureRAII() { auto output = testing::internal::GetCapturedStdout(); if (HasFatalFailure()) { printf("%s", output.c_str()); } } } stdoutCaptureRAII; auto retVal = mockOfflineCompiler.initialize(argv.size(), argv); auto mockIgcOclDeviceCtx = new NEO::MockIgcOclDeviceCtx(); mockOfflineCompiler.mockIgcFacade->igcDeviceCtx = CIF::RAII::Pack(mockIgcOclDeviceCtx); ASSERT_EQ(CL_SUCCESS, retVal); mockOfflineCompiler.inputFileSpirV = true; retVal = mockOfflineCompiler.build(); EXPECT_EQ(CL_SUCCESS, retVal); ASSERT_EQ(1U, mockIgcOclDeviceCtx->requestedTranslationCtxs.size()); NEO::MockIgcOclDeviceCtx::TranslationOpT expectedTranslation = {IGC::CodeType::spirV, IGC::CodeType::oclGenBin}; ASSERT_EQ(expectedTranslation, mockIgcOclDeviceCtx->requestedTranslationCtxs[0]); } TEST(OfflineCompilerTest, givenLlvmBcRepresentationInputWhenBuildSourceCodeIsCalledThenProperTranslationContextIsUsed) { MockOfflineCompiler mockOfflineCompiler; Source source{reinterpret_cast(llvmBcMagic.data()), llvmBcMagic.size(), "some_file.bc"}; static_cast(mockOfflineCompiler.argHelper)->inputs.push_back(source); std::vector argv = { "ocloc", "-file", "some_file.bc", "-device", gEnvironment->devicePrefix.c_str()}; testing::internal::CaptureStdout(); struct StdoutCaptureRAII { ~StdoutCaptureRAII() { auto output = testing::internal::GetCapturedStdout(); if (HasFatalFailure()) { printf("%s", output.c_str()); } } } stdoutCaptureRAII; auto retVal = mockOfflineCompiler.initialize(argv.size(), argv); auto mockIgcOclDeviceCtx = new NEO::MockIgcOclDeviceCtx(); mockOfflineCompiler.mockIgcFacade->igcDeviceCtx = CIF::RAII::Pack(mockIgcOclDeviceCtx); ASSERT_EQ(CL_SUCCESS, retVal); mockOfflineCompiler.inputFileLlvm = true; mockIgcOclDeviceCtx->requestedTranslationCtxs.clear(); retVal = mockOfflineCompiler.build(); ASSERT_EQ(mockOfflineCompiler.irBinarySize, mockOfflineCompiler.sourceCode.size()); EXPECT_EQ(0, memcmp(mockOfflineCompiler.irBinary, mockOfflineCompiler.sourceCode.data(), mockOfflineCompiler.sourceCode.size())); EXPECT_FALSE(mockOfflineCompiler.isSpirV); EXPECT_EQ(CL_SUCCESS, retVal); ASSERT_EQ(1U, mockIgcOclDeviceCtx->requestedTranslationCtxs.size()); NEO::MockIgcOclDeviceCtx::TranslationOpT expectedTranslation = {IGC::CodeType::llvmBc, IGC::CodeType::oclGenBin}; ASSERT_EQ(expectedTranslation, mockIgcOclDeviceCtx->requestedTranslationCtxs[0]); } TEST(OfflineCompilerTest, givenUseLlvmBcFlagWhenBuildingIrBinaryThenProperTranslationContextIsUsed) { MockOfflineCompiler mockOfflineCompiler; std::vector argv = { "ocloc", "-file", clFiles + "emptykernel.cl", "-device", gEnvironment->devicePrefix.c_str()}; const auto initResult = mockOfflineCompiler.initialize(argv.size(), argv); ASSERT_EQ(CL_SUCCESS, initResult); auto mockFclOclDeviceCtx = new NEO::MockFclOclDeviceCtx(); mockOfflineCompiler.mockFclFacade->fclDeviceCtx = CIF::RAII::Pack(mockFclOclDeviceCtx); mockOfflineCompiler.inputFileLlvm = true; mockOfflineCompiler.useLlvmBc = true; const auto buildResult = mockOfflineCompiler.buildIrBinary(); EXPECT_EQ(CL_SUCCESS, buildResult); ASSERT_EQ(1U, mockFclOclDeviceCtx->requestedTranslationCtxs.size()); NEO::MockIgcOclDeviceCtx::TranslationOpT expectedTranslation = {IGC::CodeType::oclC, IGC::CodeType::llvmBc}; EXPECT_EQ(expectedTranslation, mockFclOclDeviceCtx->requestedTranslationCtxs[0]); } TEST(OfflineCompilerTest, givenBinaryInputThenDontTruncateSourceAtFirstZero) { std::vector argvLlvm = {"ocloc", "-llvm_input", "-file", clFiles + "binary_with_zeroes", "-qq", "-device", gEnvironment->devicePrefix.c_str()}; auto mockOfflineCompiler = std::make_unique(); mockOfflineCompiler->initialize(argvLlvm.size(), argvLlvm); mockOfflineCompiler->build(); EXPECT_LT(0U, mockOfflineCompiler->sourceCode.size()); std::vector argvSpirV = {"ocloc", "-spirv_input", "-file", clFiles + "binary_with_zeroes", "-qq", "-device", gEnvironment->devicePrefix.c_str()}; mockOfflineCompiler = std::make_unique(); mockOfflineCompiler->initialize(argvSpirV.size(), argvSpirV); mockOfflineCompiler->build(); EXPECT_LT(0U, mockOfflineCompiler->sourceCode.size()); } TEST(OfflineCompilerTest, givenSpirvInputFileWhenCmdLineHasOptionsThenCorrectOptionsArePassedToCompiler) { char data[] = {1, 2, 3, 4, 5, 6, 7, 8}; MockCompilerDebugVars igcDebugVars(gEnvironment->igcDebugVars); igcDebugVars.binaryToReturn = data; igcDebugVars.binaryToReturnSize = sizeof(data); NEO::setIgcDebugVars(igcDebugVars); MockOfflineCompiler mockOfflineCompiler; Source source{reinterpret_cast(spirvMagic.data()), spirvMagic.size(), "some_file.spv"}; static_cast(mockOfflineCompiler.argHelper)->inputs.push_back(source); std::vector argv = { "ocloc", "-file", "some_file.spv", "-spirv_input", "-device", gEnvironment->devicePrefix.c_str(), "-options", "test_options_passed", "-qq"}; auto retVal = mockOfflineCompiler.initialize(argv.size(), argv); auto mockIgcOclDeviceCtx = new NEO::MockIgcOclDeviceCtx(); mockOfflineCompiler.mockIgcFacade->igcDeviceCtx = CIF::RAII::Pack(mockIgcOclDeviceCtx); ASSERT_EQ(CL_SUCCESS, retVal); mockOfflineCompiler.inputFileSpirV = true; retVal = mockOfflineCompiler.build(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_STREQ("test_options_passed", mockOfflineCompiler.options.c_str()); NEO::setIgcDebugVars(gEnvironment->igcDebugVars); } TEST(OfflineCompilerTest, givenOutputFileOptionWhenSourceIsCompiledThenOutputFileHasCorrectName) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-output", "myOutputFileName", "-device", gEnvironment->devicePrefix.c_str()}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "bc") || compilerOutputExists("myOutputFileName", "spv")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "bin")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "gen")); retVal = mockOfflineCompiler->build(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(compilerOutputExists("myOutputFileName", "bc") || compilerOutputExists("myOutputFileName", "spv")); EXPECT_TRUE(compilerOutputExists("myOutputFileName", "bin")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "gen")); } TEST(OfflineCompilerTest, givenDebugDataAvailableWhenSourceIsBuiltThenDebugDataFileIsCreated) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-output", "myOutputFileName", "-device", gEnvironment->devicePrefix.c_str()}; char debugData[10]; MockCompilerDebugVars igcDebugVars(gEnvironment->igcDebugVars); igcDebugVars.debugDataToReturn = debugData; igcDebugVars.debugDataToReturnSize = sizeof(debugData); NEO::setIgcDebugVars(igcDebugVars); auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "bc") || compilerOutputExists("myOutputFileName", "spv")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "bin")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "gen")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "dbg")); retVal = mockOfflineCompiler->build(); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(compilerOutputExists("myOutputFileName", "bc") || compilerOutputExists("myOutputFileName", "spv")); EXPECT_TRUE(compilerOutputExists("myOutputFileName", "bin")); EXPECT_FALSE(compilerOutputExists("myOutputFileName", "gen")); EXPECT_TRUE(compilerOutputExists("myOutputFileName", "dbg")); NEO::setIgcDebugVars(gEnvironment->igcDebugVars); } TEST(OfflineCompilerTest, givenInternalOptionsWhenCmdLineParsedThenOptionsAreAppendedToInternalOptionsString) { std::vector argv = { "ocloc", "-internal_options", "myInternalOptions"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); testing::internal::CaptureStdout(); mockOfflineCompiler->parseCommandLine(argv.size(), argv); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(0u, output.size()); std::string internalOptions = mockOfflineCompiler->internalOptions; EXPECT_TRUE(hasSubstr(internalOptions, std::string("myInternalOptions"))); } TEST(OfflineCompilerTest, givenOptionsWhenCmdLineParsedThenOptionsAreAppendedToOptionsString) { std::vector argv = { "ocloc", "-options", "options1", "-options", "options2"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); testing::internal::CaptureStdout(); mockOfflineCompiler->parseCommandLine(argv.size(), argv); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(0u, output.size()); std::string options = mockOfflineCompiler->options; EXPECT_TRUE(hasSubstr(options, std::string("options1"))); EXPECT_TRUE(hasSubstr(options, std::string("options2"))); } TEST(OfflineCompilerTest, givenDeviceOptionsForCompiledDeviceWhenCmdLineParsedThenDeviceOptionsAreAppendedToOptionsString) { std::vector argv = { "ocloc", "-device", gEnvironment->devicePrefix.c_str(), "-options", "options", "-device_options", gEnvironment->devicePrefix.c_str(), "devOptions"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->parseCommandLine(argv.size(), argv); auto perDeviceOptions = mockOfflineCompiler->perDeviceOptions; EXPECT_TRUE(hasSubstr(perDeviceOptions[gEnvironment->devicePrefix.c_str()], std::string("devOptions"))); std::string options = mockOfflineCompiler->options; EXPECT_TRUE(hasSubstr(options, std::string("options"))); EXPECT_TRUE(hasSubstr(options, std::string("devOptions"))); } TEST(OfflineCompilerTest, givenDeviceOptionsWithDeprecatedDeviceAcronymWhenCmdLineParsedThenDeviceNameIsRecognized) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto deprecatedAcronyms = mockOfflineCompiler->argHelper->productConfigHelper->getDeprecatedAcronyms(); if (deprecatedAcronyms.empty()) { GTEST_SKIP(); } const auto deviceName = deprecatedAcronyms[0].str(); std::vector argv = { "ocloc", "compile", "-file", clFiles + "copybuffer.cl", "-device", deviceName.c_str(), "-options", "options", "-device_options", deviceName.c_str(), "devOptions"}; testing::internal::CaptureStdout(); const auto result = mockOfflineCompiler->parseCommandLine(argv.size(), argv); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(0u, output.size()); EXPECT_NE(OCLOC_INVALID_COMMAND_LINE, result); std::stringstream expectedErrorMessage; expectedErrorMessage << "Error: Invalid device acronym passed to -device_options: " << deviceName; EXPECT_FALSE(hasSubstr(output, expectedErrorMessage.str())); } TEST(OfflineCompilerTest, givenUnknownDeviceAcronymInDeviceOptionsWhenParsingCommandLineThenErrorLogIsPrintedAndFailureIsReturned) { std::vector argv = { "ocloc", "compile", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-options", "options", "-device_options", "unknownDeviceName1", "devOptions1", "-device_options", gEnvironment->devicePrefix.c_str(), "devOptions2", "-device_options", "unknownDeviceName2", "devOptions2"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); testing::internal::CaptureStdout(); const auto result = mockOfflineCompiler->parseCommandLine(argv.size(), argv); const std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, result); const std::string expectedErrorMessage1{"Error: Invalid device acronym passed to -device_options: unknownDeviceName1\n"}; const std::string expectedErrorMessage2{"Error: Invalid device acronym passed to -device_options: unknownDeviceName2\n"}; EXPECT_TRUE(hasSubstr(output, expectedErrorMessage1)); EXPECT_TRUE(hasSubstr(output, expectedErrorMessage2)); } TEST(OfflineCompilerTest, givenDeviceOptionsInWrongFormatWhenCmdLineParsedThenDeviceOptionsAreNotAppendedToOptionsString) { std::vector argv = { "ocloc", "-device", gEnvironment->devicePrefix.c_str(), "-options", "options", "-device_options", "devOptions"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); testing::internal::CaptureStdout(); mockOfflineCompiler->parseCommandLine(argv.size(), argv); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(0u, output.size()); auto perDeviceOptions = mockOfflineCompiler->perDeviceOptions; EXPECT_FALSE(hasSubstr(perDeviceOptions[gEnvironment->devicePrefix.c_str()], std::string("devOptions"))); std::string options = mockOfflineCompiler->options; EXPECT_TRUE(hasSubstr(options, std::string("options"))); EXPECT_FALSE(hasSubstr(options, std::string("devOptions"))); } TEST(OfflineCompilerTest, givenMultipleDeviceOptionsWhenCmdLineParsedThenDeviceOptionsAreAppendedToOptionsString) { std::vector argv = { "ocloc", "-device", gEnvironment->devicePrefix.c_str(), "-options", "options", "-device_options", gEnvironment->devicePrefix.c_str(), "devOptions1", "-device_options", gEnvironment->devicePrefix.c_str(), "devOptions2"}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); mockOfflineCompiler->parseCommandLine(argv.size(), argv); auto perDeviceOptions = mockOfflineCompiler->perDeviceOptions; EXPECT_TRUE(hasSubstr(perDeviceOptions[gEnvironment->devicePrefix.c_str()], std::string("devOptions1"))); EXPECT_TRUE(hasSubstr(perDeviceOptions[gEnvironment->devicePrefix.c_str()], std::string("devOptions2"))); std::string options = mockOfflineCompiler->options; EXPECT_TRUE(hasSubstr(options, std::string("options"))); EXPECT_TRUE(hasSubstr(options, std::string("devOptions1"))); EXPECT_TRUE(hasSubstr(options, std::string("devOptions2"))); } TEST(OfflineCompilerTest, givenMultipleDeviceOptionsForCompiledDeviceAndDeviceOptionsNotForCompiledDeviceWhenCmdLineParsedThenDeviceOptionsOnlyForCompiledDeviceAreAppendedToOptionsString) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto allEnabledDeviceAcronyms = mockOfflineCompiler->argHelper->productConfigHelper->getRepresentativeProductAcronyms(); if (allEnabledDeviceAcronyms.empty()) { GTEST_SKIP(); } std::string notCompiledDevice; for (const auto &deviceAcronym : allEnabledDeviceAcronyms) { if (deviceAcronym.str() != gEnvironment->devicePrefix.c_str()) { notCompiledDevice = deviceAcronym.str(); break; } } if (notCompiledDevice == "") { GTEST_SKIP(); } std::vector argv = { "ocloc", "-device", gEnvironment->devicePrefix.c_str(), "-device_options", gEnvironment->devicePrefix.c_str(), "devOptions1", "-device_options", notCompiledDevice, "devOptions2", "-options", "options1", "-device_options", gEnvironment->devicePrefix.c_str(), "devOptions3", "-options", "options2"}; mockOfflineCompiler->parseCommandLine(argv.size(), argv); auto perDeviceOptions = mockOfflineCompiler->perDeviceOptions; EXPECT_TRUE(hasSubstr(perDeviceOptions[notCompiledDevice], std::string("devOptions2"))); EXPECT_TRUE(hasSubstr(perDeviceOptions[gEnvironment->devicePrefix.c_str()], std::string("devOptions1"))); EXPECT_TRUE(hasSubstr(perDeviceOptions[gEnvironment->devicePrefix.c_str()], std::string("devOptions3"))); std::string options = mockOfflineCompiler->options; EXPECT_TRUE(hasSubstr(options, std::string("options1"))); EXPECT_TRUE(hasSubstr(options, std::string("options2"))); EXPECT_TRUE(hasSubstr(options, std::string("devOptions1"))); EXPECT_TRUE(hasSubstr(options, std::string("devOptions3"))); EXPECT_FALSE(hasSubstr(options, std::string("devOptions2"))); } TEST(OfflineCompilerTest, givenDeviceOptionsForMultipleDevicesSeparatedByCommasWhenCmdLineParsedThenDeviceOptionsAreParsedCorrectly) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto allEnabledDeviceAcronyms = mockOfflineCompiler->argHelper->productConfigHelper->getRepresentativeProductAcronyms(); if (allEnabledDeviceAcronyms.size() < 3) { GTEST_SKIP(); } auto product = allEnabledDeviceAcronyms[0].str(); auto productForDeviceOptions0 = allEnabledDeviceAcronyms[0].str(); auto productForDeviceOptions1 = allEnabledDeviceAcronyms[1].str(); std::stringstream productsForDeviceOptions; productsForDeviceOptions << productForDeviceOptions0 << "," << productForDeviceOptions1; std::vector argv = { "ocloc", "-device", product.c_str(), "-device_options", productsForDeviceOptions.str().c_str(), "devOptions1", "-options", "options1", "-device_options", productForDeviceOptions1.c_str(), "devOptions2"}; mockOfflineCompiler->parseCommandLine(argv.size(), argv); auto perDeviceOptions = mockOfflineCompiler->perDeviceOptions; EXPECT_TRUE(hasSubstr(perDeviceOptions[productForDeviceOptions0], std::string("devOptions1"))); EXPECT_FALSE(hasSubstr(perDeviceOptions[productForDeviceOptions0], std::string("devOptions2"))); EXPECT_TRUE(hasSubstr(perDeviceOptions[productForDeviceOptions1], std::string("devOptions1"))); EXPECT_TRUE(hasSubstr(perDeviceOptions[productForDeviceOptions1], std::string("devOptions2"))); std::string options = mockOfflineCompiler->options; EXPECT_TRUE(hasSubstr(options, std::string("options1"))); EXPECT_TRUE(hasSubstr(options, std::string("devOptions1"))); EXPECT_FALSE(hasSubstr(options, std::string("devOptions2"))); } TEST(OfflineCompilerTest, givenDeviceOptionsForMultipleDevicesSeparatedByCommasWithSpacesAfterCommasWhenCmdLineParsedThenErrorLogIsPrintedAndFailureIsReturned) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto allEnabledDeviceAcronyms = mockOfflineCompiler->argHelper->productConfigHelper->getRepresentativeProductAcronyms(); if (allEnabledDeviceAcronyms.size() < 3) { GTEST_SKIP(); } auto product = allEnabledDeviceAcronyms[0].str(); auto productForDeviceOptions0 = allEnabledDeviceAcronyms[0].str(); auto productForDeviceOptions1 = allEnabledDeviceAcronyms[1].str(); std::stringstream productsForDeviceOptions; productsForDeviceOptions << productForDeviceOptions0 << ", " << productForDeviceOptions1; std::vector argv = { "ocloc", "-device", product.c_str(), "-device_options", productsForDeviceOptions.str().c_str(), "devOptions1", "-options", "options1", "-device_options", productForDeviceOptions1.c_str(), "devOptions2"}; testing::internal::CaptureStdout(); const auto result = mockOfflineCompiler->parseCommandLine(argv.size(), argv); const std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, result); EXPECT_NE(0u, output.size()); std::stringstream expectedErrorMessage; expectedErrorMessage << "Error: Invalid device acronym passed to -device_options: " << " " << productForDeviceOptions1 << "\n"; EXPECT_TRUE(hasSubstr(output, expectedErrorMessage.str())); } TEST(OfflineCompilerTest, givenDashOOptionWhenCmdLineParsedThenBinaryOutputNameIsSet) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-o", "nameOfFile.bin", "-device", gEnvironment->devicePrefix.c_str()}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); testing::internal::CaptureStdout(); auto retVal = mockOfflineCompiler->parseCommandLine(argv.size(), argv); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(OCLOC_SUCCESS, retVal); EXPECT_EQ(0u, output.size()); EXPECT_EQ("nameOfFile.bin", mockOfflineCompiler->binaryOutputFile); } TEST(OfflineCompilerTest, givenDashOAndOtherInvalidOptionsWhenCmdLineParsedThenErrorReturned) { std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-o", "nameOfFile.bin", "-device", gEnvironment->devicePrefix.c_str(), "empty"}; std::vector options = { "-gen_file", "-cpp_file", "-output_no_suffix"}; for (const auto &op : options) { argv[argv.size() - 1] = op; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); testing::internal::CaptureStdout(); auto retVal = mockOfflineCompiler->parseCommandLine(argv.size(), argv); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, retVal); EXPECT_NE(0u, output.size()); EXPECT_TRUE(hasSubstr(output, std::string("Error: options: -gen_file/-cpp_file/-output_no_suffix/-output cannot be used with -o\n"))); } std::vector argv2 = { "ocloc", "-file", clFiles + "copybuffer.cl", "-o", "nameOfFile.bin", "-output", "abc", "-device", gEnvironment->devicePrefix.c_str()}; auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); testing::internal::CaptureStdout(); auto retVal = mockOfflineCompiler->parseCommandLine(argv2.size(), argv2); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(OCLOC_INVALID_COMMAND_LINE, retVal); EXPECT_NE(0u, output.size()); EXPECT_TRUE(hasSubstr(output, std::string("Error: options: -gen_file/-cpp_file/-output_no_suffix/-output cannot be used with -o\n"))); } TEST(OfflineCompilerTest, givenInputOptionsAndInternalOptionsFilesWhenOfflineCompilerIsInitializedThenCorrectOptionsAreSetAndRemainAfterBuild) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); ASSERT_TRUE(fileExists(clFiles + "shouldfail_options.txt")); ASSERT_TRUE(fileExists(clFiles + "shouldfail_internal_options.txt")); std::vector argv = { "ocloc", "-q", "-file", clFiles + "shouldfail.cl", "-device", gEnvironment->devicePrefix.c_str()}; int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); auto &options = mockOfflineCompiler->options; auto &internalOptions = mockOfflineCompiler->internalOptions; EXPECT_STREQ(options.c_str(), "-shouldfailOptions"); EXPECT_TRUE(internalOptions.find("-shouldfailInternalOptions") != std::string::npos); EXPECT_TRUE(mockOfflineCompiler->getOptionsReadFromFile().find("-shouldfailOptions") != std::string::npos); EXPECT_TRUE(mockOfflineCompiler->getInternalOptionsReadFromFile().find("-shouldfailInternalOptions") != std::string::npos); mockOfflineCompiler->build(); EXPECT_STREQ(options.c_str(), "-shouldfailOptions"); EXPECT_TRUE(internalOptions.find("-shouldfailInternalOptions") != std::string::npos); EXPECT_TRUE(mockOfflineCompiler->getOptionsReadFromFile().find("-shouldfailOptions") != std::string::npos); EXPECT_TRUE(mockOfflineCompiler->getInternalOptionsReadFromFile().find("-shouldfailInternalOptions") != std::string::npos); } TEST(OfflineCompilerTest, givenInputOptionsFileWithSpecialCharsWhenOfflineCompilerIsInitializedThenCorrectOptionsAreSet) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); ASSERT_TRUE(fileExists(clFiles + "simple_kernels_opts_options.txt")); std::vector argv = { "ocloc", "-q", "-file", clFiles + "simple_kernels_opts.cl", "-device", gEnvironment->devicePrefix.c_str()}; int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); auto &options = mockOfflineCompiler->options; EXPECT_STREQ(options.c_str(), "-cl-opt-disable -DDEF_WAS_SPECIFIED=1 -DARGS=\", const __global int *arg1, float arg2, const __global int *arg3, float arg4\""); } TEST(OfflineCompilerTest, givenInputOptionsAndOclockOptionsFileWithForceStosOptWhenOfflineCompilerIsInitializedThenCompilerOptionGreaterThan4gbBuffersRequiredIsNotApplied) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); ASSERT_TRUE(fileExists(clFiles + "stateful_copy_buffer_ocloc_options.txt")); std::vector argv = { "ocloc", "-q", "-file", clFiles + "stateful_copy_buffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(CL_SUCCESS, retVal); mockOfflineCompiler->build(); auto &internalOptions = mockOfflineCompiler->internalOptions; size_t found = internalOptions.find(NEO::CompilerOptions::greaterThan4gbBuffersRequired.data()); EXPECT_EQ(std::string::npos, found); } struct OfflineCompilerStatelessToStatefulTests : public ::testing::Test { void SetUp() override { mockOfflineCompiler = std::make_unique(); mockOfflineCompiler->deviceName = gEnvironment->devicePrefix; mockOfflineCompiler->initHardwareInfo(mockOfflineCompiler->deviceName); } void runTest() const { std::pair testParams[] = {{true, false}, {false, true}}; for (const auto &[forceStatelessToStatefulOptimization, containsGreaterThan4gbBuffersRequired] : testParams) { auto internalOptions = mockOfflineCompiler->internalOptions; mockOfflineCompiler->forceStatelessToStatefulOptimization = forceStatelessToStatefulOptimization; mockOfflineCompiler->appendExtraInternalOptions(internalOptions); auto found = internalOptions.find(NEO::CompilerOptions::greaterThan4gbBuffersRequired.data()); if (containsGreaterThan4gbBuffersRequired) { EXPECT_NE(std::string::npos, found); } else { EXPECT_EQ(std::string::npos, found); } } } std::unique_ptr mockOfflineCompiler; }; TEST_F(OfflineCompilerStatelessToStatefulTests, whenAppendExtraInternalOptionsThenInternalOptionsAreCorrect) { if (!mockOfflineCompiler->compilerProductHelper->isForceToStatelessRequired()) { GTEST_SKIP(); } runTest(); } template class MockCompilerProductHelperHw : public CompilerProductHelperHw { public: bool isForceToStatelessRequired() const override { return true; } }; HWTEST2_F(OfflineCompilerStatelessToStatefulTests, givenMockWhenAppendExtraInternalOptionsThenInternalOptionsAreCorrect, MatchAny) { auto backup = std::unique_ptr(new MockCompilerProductHelperHw()); this->mockOfflineCompiler->compilerProductHelper.swap(backup); runTest(); this->mockOfflineCompiler->compilerProductHelper.swap(backup); } struct OfflineCompilerBindlessOptionsTests : public ::testing::Test { void SetUp() override { mockOfflineCompiler = std::make_unique(); mockOfflineCompiler->deviceName = gEnvironment->devicePrefix; mockOfflineCompiler->initHardwareInfo(mockOfflineCompiler->deviceName); mockOfflineCompiler->internalOptions.clear(); releaseHelper = std::make_unique(); } std::unique_ptr mockOfflineCompiler; std::unique_ptr releaseHelper; }; TEST_F(OfflineCompilerBindlessOptionsTests, givenBindlessAddressingEnabledWhenAppendExtraInternalOptionsThenBindlessModeOptionsAreAddedToInternalOptions) { releaseHelper->isBindlessAddressingDisabledResult = false; mockOfflineCompiler->releaseHelper = std::move(releaseHelper); auto internalOptions = mockOfflineCompiler->internalOptions; mockOfflineCompiler->appendExtraInternalOptions(internalOptions); EXPECT_NE(std::string::npos, internalOptions.find(NEO::CompilerOptions::bindlessMode.data())); } TEST_F(OfflineCompilerBindlessOptionsTests, givenBindlessNotEnabledAddrModeSetWhenAppendExtraInternalOptionsThenBindlessModeOptionsAreNotAddedToInternalOptions) { releaseHelper->isBindlessAddressingDisabledResult = false; mockOfflineCompiler->releaseHelper = std::move(releaseHelper); mockOfflineCompiler->addressingMode = "bindful"; auto internalOptions = mockOfflineCompiler->internalOptions; mockOfflineCompiler->appendExtraInternalOptions(internalOptions); EXPECT_EQ(std::string::npos, internalOptions.find(NEO::CompilerOptions::bindlessMode.data())); } TEST_F(OfflineCompilerBindlessOptionsTests, givenBindlessAddressingDisabledWhenAppendExtraInternalOptionsThenBindlessModeOptionsAreNotAddedToInternalOptions) { releaseHelper->isBindlessAddressingDisabledResult = true; mockOfflineCompiler->releaseHelper = std::move(releaseHelper); auto internalOptions = mockOfflineCompiler->internalOptions; mockOfflineCompiler->appendExtraInternalOptions(internalOptions); EXPECT_EQ(std::string::npos, internalOptions.find(NEO::CompilerOptions::bindlessMode.data())); } TEST_F(OfflineCompilerBindlessOptionsTests, givenNullReleaseHelperWhenAppendExtraInternalOptionsThenBindlessModeOptionsAreNotAddedToInternalOptions) { mockOfflineCompiler->releaseHelper.reset(); ASSERT_EQ(nullptr, mockOfflineCompiler->releaseHelper); auto internalOptions = mockOfflineCompiler->internalOptions; mockOfflineCompiler->appendExtraInternalOptions(internalOptions); EXPECT_EQ(std::string::npos, internalOptions.find(NEO::CompilerOptions::bindlessMode.data())); } TEST(OfflineCompilerTest, givenNonExistingFilenameWhenUsedToReadOptionsThenReadOptionsFromFileReturnsFalse) { std::string options; std::string file("non_existing_file"); ASSERT_FALSE(fileExists(file.c_str())); auto helper = std::make_unique(); bool result = OfflineCompiler::readOptionsFromFile(options, file, helper.get()); EXPECT_FALSE(result); } class MyOclocArgHelper : public OclocArgHelper { public: std::unique_ptr loadDataFromFile(const std::string &filename, size_t &retSize) override { auto file = std::make_unique(fileContent.size() + 1); strcpy_s(file.get(), fileContent.size() + 1, fileContent.c_str()); retSize = fileContent.size(); return file; } bool fileExists(const std::string &filename) const override { return true; } std::string fileContent; }; TEST(OfflineCompilerTest, givenEmptyFileWhenReadOptionsFromFileThenSuccessIsReturned) { std::string options; std::string filename("non_existing_file"); auto helper = std::make_unique(); helper->fileContent = ""; EXPECT_TRUE(OfflineCompiler::readOptionsFromFile(options, filename, helper.get())); EXPECT_TRUE(options.empty()); } TEST(OfflineCompilerTest, givenNoCopyrightsWhenReadOptionsFromFileThenSuccessIsReturned) { std::string options; std::string filename("non_existing_file"); auto helper = std::make_unique(); helper->fileContent = "-dummy_option"; EXPECT_TRUE(OfflineCompiler::readOptionsFromFile(options, filename, helper.get())); EXPECT_STREQ(helper->fileContent.c_str(), options.c_str()); } TEST(OfflineCompilerTest, givenEmptyDirectoryWhenGenerateFilePathIsCalledThenTrailingSlashIsNotAppended) { std::string path = generateFilePath("", "a", "b"); EXPECT_STREQ("ab", path.c_str()); } TEST(OfflineCompilerTest, givenNonEmptyDirectoryWithTrailingSlashWhenGenerateFilePathIsCalledThenAdditionalTrailingSlashIsNotAppended) { std::string path = generateFilePath("d/", "a", "b"); EXPECT_STREQ("d/ab", path.c_str()); } TEST(OfflineCompilerTest, givenNonEmptyDirectoryWithoutTrailingSlashWhenGenerateFilePathIsCalledThenTrailingSlashIsAppended) { std::string path = generateFilePath("d", "a", "b"); EXPECT_STREQ("d/ab", path.c_str()); } TEST(OfflineCompilerTest, givenSpirvPathWhenGenerateFilePathForIrIsCalledThenProperExtensionIsReturned) { MockOfflineCompiler compiler; compiler.isSpirV = true; compiler.outputDirectory = "d"; std::string path = compiler.generateFilePathForIr("a"); EXPECT_STREQ("d/a.spv", path.c_str()); } TEST(OfflineCompilerTest, givenLlvmBcPathWhenGenerateFilePathForIrIsCalledThenProperExtensionIsReturned) { MockOfflineCompiler compiler; compiler.isSpirV = false; compiler.outputDirectory = "d"; std::string path = compiler.generateFilePathForIr("a"); EXPECT_STREQ("d/a.bc", path.c_str()); } TEST(OfflineCompilerTest, givenLlvmTextPathWhenGenerateFilePathForIrIsCalledThenProperExtensionIsReturned) { MockOfflineCompiler compiler; compiler.isSpirV = false; compiler.useLlvmText = true; compiler.outputDirectory = "d"; std::string path = compiler.generateFilePathForIr("a"); EXPECT_STREQ("d/a.ll", path.c_str()); compiler.isSpirV = true; path = compiler.generateFilePathForIr("a"); EXPECT_STREQ("d/a.ll", path.c_str()); } TEST(OfflineCompilerTest, givenDisabledOptsSuffixWhenGenerateOptsSuffixIsCalledThenEmptyStringIsReturned) { MockOfflineCompiler compiler; compiler.options = "A B C"; compiler.useOptionsSuffix = false; std::string suffix = compiler.generateOptsSuffix(); EXPECT_STREQ("", suffix.c_str()); } TEST(OfflineCompilerTest, givenEnabledOptsSuffixWhenGenerateOptsSuffixIsCalledThenEscapedStringIsReturned) { MockOfflineCompiler compiler; compiler.options = "A B C"; compiler.useOptionsSuffix = true; std::string suffix = compiler.generateOptsSuffix(); EXPECT_STREQ("A_B_C", suffix.c_str()); } TEST(OfflineCompilerTest, givenCompilerWhenBuildSourceCodeFailsThenGenerateElfBinaryAndWriteOutAllFilesAreCalled) { MockOfflineCompiler compiler; compiler.overrideBuildSourceCodeStatus = true; auto expectedError = OCLOC_BUILD_PROGRAM_FAILURE; compiler.buildSourceCodeStatus = expectedError; EXPECT_EQ(0u, compiler.generateElfBinaryCalled); EXPECT_EQ(0u, compiler.writeOutAllFilesCalled); compiler.inputFile = clFiles + "copybuffer.cl"; auto status = compiler.build(); EXPECT_EQ(expectedError, status); EXPECT_EQ(1u, compiler.generateElfBinaryCalled); EXPECT_EQ(1u, compiler.writeOutAllFilesCalled); } TEST(OfflineCompilerTest, givenDeviceSpecificKernelFileWhenCompilerIsInitializedThenOptionsAreReadFromFile) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); auto kernelForSpecificDevice = "__kernel void empty(){}"; Source source{reinterpret_cast(kernelForSpecificDevice), sizeof(kernelForSpecificDevice), "emptykernel.cl"}; static_cast(mockOfflineCompiler->argHelper)->inputs.push_back(source); const char options[] = R"===( /* * Copyright (C) 2024 Intel Corporation * * SPDX-License-Identifier: MIT * */ -cl-opt-disable )==="; Source optionsSource{reinterpret_cast(options), sizeof(options), "emptykernel_options.txt"}; static_cast(mockOfflineCompiler->argHelper)->inputs.push_back(optionsSource); std::vector argv = { "ocloc", "-q", "-file", "emptykernel.cl", "-device", gEnvironment->devicePrefix.c_str()}; int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, retVal); EXPECT_STREQ("-cl-opt-disable", mockOfflineCompiler->options.c_str()); } TEST(OfflineCompilerTest, givenHexadecimalRevisionIdWhenCompilerIsInitializedThenPassItToHwInfo) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); std::vector argv = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-revision_id", "0x11"}; int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, retVal); EXPECT_EQ(mockOfflineCompiler->hwInfo.platform.usRevId, 17); } TEST(OfflineCompilerTest, givenDebugVariableSetWhenInitializingThenOverrideRevision) { DebugManagerStateRestore stateRestore; debugManager.flags.OverrideRevision.set(123); auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); std::vector argv = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-revision_id", "0x11"}; int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, retVal); EXPECT_EQ(mockOfflineCompiler->hwInfo.platform.usRevId, 123); } TEST(OfflineCompilerTest, givenDecimalRevisionIdWhenCompilerIsInitializedThenPassItToHwInfo) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); std::vector argv = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-revision_id", "17"}; int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, retVal); EXPECT_EQ(mockOfflineCompiler->hwInfo.platform.usRevId, 17); } TEST(OfflineCompilerTest, givenNoRevisionIdWhenCompilerIsInitializedThenHwInfoHasDefaultRevId) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); std::vector argv = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; mockOfflineCompiler->initHardwareInfo(gEnvironment->devicePrefix.c_str()); auto revId = mockOfflineCompiler->hwInfo.platform.usRevId; int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, retVal); EXPECT_EQ(mockOfflineCompiler->hwInfo.platform.usRevId, revId); } TEST(OfflineCompilerTest, givenEmptyDeviceNameWhenInitializingHardwareInfoThenInvalidDeviceIsReturned) { MockOfflineCompiler mockOfflineCompiler{}; const std::string emptyDeviceName{}; const auto result = mockOfflineCompiler.initHardwareInfo(emptyDeviceName); EXPECT_EQ(OCLOC_INVALID_DEVICE, result); } TEST(OfflineCompilerTest, whenDeviceIsSpecifiedThenDefaultConfigFromTheDeviceIsUsed) { auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); ASSERT_NE(nullptr, mockOfflineCompiler); std::vector argv = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; int retVal = mockOfflineCompiler->initialize(argv.size(), argv); EXPECT_EQ(OCLOC_SUCCESS, retVal); HardwareInfo hwInfo = mockOfflineCompiler->hwInfo; uint32_t sliceCount = 2; uint32_t subSlicePerSliceCount = 4; uint32_t euPerSubSliceCount = 5; uint64_t hwInfoConfig = euPerSubSliceCount; hwInfoConfig |= (static_cast(subSlicePerSliceCount) << 16); hwInfoConfig |= (static_cast(sliceCount) << 32); setHwInfoValuesFromConfig(hwInfoConfig, hwInfo); EXPECT_EQ(sliceCount, hwInfo.gtSystemInfo.SliceCount); EXPECT_EQ(subSlicePerSliceCount * sliceCount, hwInfo.gtSystemInfo.SubSliceCount); EXPECT_EQ(subSlicePerSliceCount * sliceCount, hwInfo.gtSystemInfo.SubSliceCount); EXPECT_EQ(euPerSubSliceCount * subSlicePerSliceCount * sliceCount, hwInfo.gtSystemInfo.EUCount); } TEST(OclocCompile, whenDetectedPotentialInputTypeMismatchThenEmitsWarning) { std::string sourceOclC = "__kernel void k() { }"; std::string sourceLlvmBc = NEO::llvmBcMagic.str(); std::string sourceSpirv = NEO::spirvMagic.str(); std::string sourceSpirvInv = NEO::spirvMagicInv.str(); std::string notSpirvWarning = "Warning : file does not look like spirv bitcode (wrong magic numbers)"; std::string notLlvmBcWarning = "Warning : file does not look like llvm bitcode (wrong magic numbers)"; std::string isSpirvWarning = "Warning : file looks like spirv bitcode (based on magic numbers) - please make sure proper CLI flags are present"; std::string isLlvmBcWarning = "Warning : file looks like llvm bitcode (based on magic numbers) - please make sure proper CLI flags are present"; std::string allWarnings[] = {notSpirvWarning, notLlvmBcWarning, isLlvmBcWarning, isSpirvWarning}; struct Case { std::string input; bool isSpirv; bool isLlvm; std::string expectedWarning; }; Case cases[] = { {sourceOclC, false, false, ""}, {sourceOclC, true, false, notSpirvWarning}, {sourceOclC, false, true, notLlvmBcWarning}, {sourceLlvmBc, false, false, isLlvmBcWarning}, {sourceLlvmBc, true, false, notSpirvWarning}, {sourceLlvmBc, false, true, ""}, {sourceSpirv, false, false, isSpirvWarning}, {sourceSpirv, true, false, ""}, {sourceSpirv, false, true, notLlvmBcWarning}, {sourceSpirvInv, false, false, isSpirvWarning}, {sourceSpirvInv, true, false, ""}, {sourceSpirvInv, false, true, notLlvmBcWarning}, }; { MockOfflineCompiler ocloc; std::vector argv = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str()}; ocloc.initHardwareInfo(gEnvironment->devicePrefix.c_str()); int retVal = ocloc.initialize(argv.size(), argv); ASSERT_EQ(0, retVal); int caseNum = 0; for (auto &c : cases) { testing::internal::CaptureStdout(); ocloc.inputFileLlvm = c.isLlvm; ocloc.inputFileSpirV = c.isSpirv; ocloc.inputFile = "src"; ocloc.uniqueHelper->filesMap["src"] = c.input; ocloc.uniqueHelper->callBaseFileExists = false; ocloc.uniqueHelper->callBaseLoadDataFromFile = false; ocloc.build(); auto log = ocloc.argHelper->getPrinterRef().getLog().str(); ocloc.clearLog(); std::string output = testing::internal::GetCapturedStdout(); if (c.expectedWarning.empty()) { for (auto &w : allWarnings) { EXPECT_FALSE(hasSubstr(log, w)) << " Case : " << caseNum; } } else { EXPECT_TRUE(hasSubstr(log, c.expectedWarning)) << " Case : " << caseNum << " : " << c.expectedWarning << ". Got : " << log; EXPECT_STREQ(log.c_str(), output.c_str()); } caseNum++; } } } TEST(OclocCompile, givenCommandLineWithoutDeviceWhenCompilingToSpirvThenSucceedsButUsesEmptyExtensionString) { MockOfflineCompiler ocloc; std::vector argv = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-spv_only"}; int retVal = ocloc.initialize(argv.size(), argv); ASSERT_EQ(0, retVal); retVal = ocloc.build(); EXPECT_EQ(0, retVal); EXPECT_TRUE(hasSubstr(ocloc.internalOptions, "-ocl-version=300" " -cl-ext=-all,+cl_khr_3d_image_writes,+__opencl_c_3d_image_writes,+__opencl_c_images")); EXPECT_TRUE(hasSubstr(ocloc.internalOptions, " -D__IMAGE_SUPPORT__=1")); } TEST(OclocCompile, givenDeviceAndInternalOptionsOptionWhenCompilingToSpirvThenInternalOptionsAreSetCorrectly) { MockOfflineCompiler ocloc; std::vector argv = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-internal_options", "-cl-ext=+custom_param", "-device", gEnvironment->devicePrefix.c_str(), "-spv_only"}; int retVal = ocloc.initialize(argv.size(), argv); ASSERT_EQ(0, retVal); retVal = ocloc.build(); EXPECT_EQ(0, retVal); std::string regexToMatch = "\\-ocl\\-version=" + std::to_string(ocloc.hwInfo.capabilityTable.clVersionSupport) + "0 \\-cl\\-ext=\\-all.* \\-cl\\-ext=\\+custom_param"; EXPECT_TRUE(containsRegex(ocloc.internalOptions, regexToMatch)); } TEST(OclocCompile, givenNoDeviceAndInternalOptionsOptionWhenCompilingToSpirvThenInternalOptionsAreSetCorrectly) { MockOfflineCompiler ocloc; std::vector argv = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-internal_options", "-cl-ext=+custom_param", "-spv_only"}; int retVal = ocloc.initialize(argv.size(), argv); ASSERT_EQ(0, retVal); retVal = ocloc.build(); EXPECT_EQ(0, retVal); EXPECT_TRUE(hasSubstr(ocloc.internalOptions, "-ocl-version=300" " -cl-ext=-all,+cl_khr_3d_image_writes,+__opencl_c_3d_image_writes,+__opencl_c_images" " -cl-ext=+custom_param")); } TEST(OclocCompile, givenPackedDeviceBinaryFormatWhenGeneratingElfBinaryThenItIsReturnedAsItIs) { MockOfflineCompiler ocloc; ZebinTestData::ValidEmptyProgram zebin; // genBinary is deleted in ocloc's destructor ocloc.genBinary = new char[zebin.storage.size()]; ocloc.genBinarySize = zebin.storage.size(); memcpy_s(ocloc.genBinary, ocloc.genBinarySize, zebin.storage.data(), zebin.storage.size()); ASSERT_EQ(true, ocloc.generateElfBinary()); EXPECT_EQ(0, memcmp(zebin.storage.data(), ocloc.elfBinary.data(), zebin.storage.size())); } TEST(OclocCompile, givenSpirvInputThenDontGenerateSpirvFile) { MockOfflineCompiler ocloc; std::vector argv = { "ocloc", "-q", "-file", clFiles + "binary_with_zeroes", "-out_dir", "offline_compiler_test", "-device", gEnvironment->devicePrefix.c_str(), "-spirv_input", "-qq"}; int retVal = ocloc.initialize(argv.size(), argv); ASSERT_EQ(0, retVal); retVal = ocloc.build(); EXPECT_EQ(0, retVal); EXPECT_FALSE(compilerOutputExists("offline_compiler_test/binary_with_zeroes", "gen")); EXPECT_TRUE(compilerOutputExists("offline_compiler_test/binary_with_zeroes", "bin")); EXPECT_FALSE(compilerOutputExists("offline_compiler_test/binary_with_zeroes", "spv")); } TEST(OclocCompile, givenFormatFlagWithKnownFormatPassedThenEnforceSpecifiedFormatAccordingly) { MockOfflineCompiler ocloc; std::vector argvEnforcedFormatPatchtokens = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-spv_only", "--format", "patchtokens"}; std::vector argvEnforcedFormatZebin = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-spv_only", "--format", "zebin"}; int retVal = ocloc.initialize(argvEnforcedFormatZebin.size(), argvEnforcedFormatZebin); ASSERT_EQ(0, retVal); EXPECT_FALSE(hasSubstr(ocloc.internalOptions, std::string{CompilerOptions::disableZebin})); ocloc.internalOptions.clear(); retVal = ocloc.initialize(argvEnforcedFormatPatchtokens.size(), argvEnforcedFormatPatchtokens); ASSERT_EQ(0, retVal); EXPECT_TRUE(hasSubstr(ocloc.internalOptions, std::string{CompilerOptions::disableZebin})); } HWTEST2_F(MockOfflineCompilerTests, givenNoFormatFlagSpecifiedWhenOclocInitializeThenZebinFormatIsEnforcedByDefault, HasOclocZebinFormatEnforced) { MockOfflineCompiler ocloc; std::vector argvNoFormatFlag = { "ocloc", "-q", "-file", clFiles + "copybuffer.cl", "-spv_only", "-device", gEnvironment->devicePrefix.c_str()}; int retVal = ocloc.initialize(argvNoFormatFlag.size(), argvNoFormatFlag); ASSERT_EQ(0, retVal); EXPECT_FALSE(hasSubstr(ocloc.internalOptions, std::string{CompilerOptions::disableZebin})); } TEST(OclocCompile, givenFormatFlagWithUnknownFormatPassedThenPrintWarning) { MockOfflineCompiler ocloc; std::vector argvUnknownFormatEnforced = { "ocloc", "-file", clFiles + "copybuffer.cl", "-spv_only", "--format", "banana"}; ::testing::internal::CaptureStdout(); int retVal = ocloc.initialize(argvUnknownFormatEnforced.size(), argvUnknownFormatEnforced); const auto output = testing::internal::GetCapturedStdout(); ASSERT_EQ(0, retVal); const auto expectedOutput{"Invalid format passed: banana. Ignoring.\n"}; EXPECT_EQ(expectedOutput, output); } TEST(OfflineCompilerTest, GivenDebugFlagWhenSetStatelessToStatefulBufferOffsetFlagThenStatelessToStatefullOptimizationIsSetCorrectly) { DebugManagerStateRestore stateRestore; MockOfflineCompiler mockOfflineCompiler; { debugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.set(0); mockOfflineCompiler.initHardwareInfo(gEnvironment->devicePrefix.c_str()); mockOfflineCompiler.setStatelessToStatefulBufferOffsetFlag(); std::string internalOptions = mockOfflineCompiler.internalOptions; size_t found = internalOptions.find(NEO::CompilerOptions::hasBufferOffsetArg.data()); EXPECT_EQ(std::string::npos, found); } { debugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.set(1); mockOfflineCompiler.initHardwareInfo(gEnvironment->devicePrefix.c_str()); mockOfflineCompiler.setStatelessToStatefulBufferOffsetFlag(); std::string internalOptions = mockOfflineCompiler.internalOptions; size_t found = internalOptions.find(NEO::CompilerOptions::hasBufferOffsetArg.data()); EXPECT_NE(std::string::npos, found); } } TEST(OclocCompile, GivenStatefulAddressModeWhenInvalidArgsPAssedThenErrorIsReturned) { MockOfflineCompiler ocloc; std::vector argvA = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-stateful_address_mode", "wrong"}; testing::internal::CaptureStdout(); int retVal = ocloc.initialize(argvA.size(), argvA); ASSERT_EQ(OCLOC_INVALID_COMMAND_LINE, retVal); std::string output = testing::internal::GetCapturedStdout(); EXPECT_STRNE(output.c_str(), ""); std::vector argvB = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-stateful_address_mode", "bindful", "-internal_options", "-cl-intel-use-bindless-mode "}; MockOfflineCompiler ocloc2; testing::internal::CaptureStdout(); retVal = ocloc2.initialize(argvB.size(), argvB); ASSERT_EQ(OCLOC_INVALID_COMMAND_LINE, retVal); output = testing::internal::GetCapturedStdout(); EXPECT_STRNE(output.c_str(), ""); } TEST(OclocCompile, GivenStatefulAddressModeSetToBindlessWhenBuildThenBindlessModeInternalOptionsAreAdded) { MockOfflineCompiler ocloc; std::vector argv = { "ocloc", "-file", clFiles + "copybuffer.cl", "-device", gEnvironment->devicePrefix.c_str(), "-stateful_address_mode", "bindless"}; int retVal = ocloc.initialize(argv.size(), argv); ASSERT_EQ(0, retVal); retVal = ocloc.build(); EXPECT_EQ(0, retVal); EXPECT_NE(std::string::npos, ocloc.internalOptions.find(NEO::CompilerOptions::bindlessMode.data())); } struct WhiteBoxOclocArgHelper : public OclocArgHelper { using OclocArgHelper::messagePrinter; using OclocArgHelper::OclocArgHelper; }; TEST(OclocArgHelperTest, GivenOutputSuppressMessagesAndSaveItToFile) { uint32_t numOutputs = 0U; uint64_t *lenOutputs = nullptr; uint8_t **outputs = nullptr; char **nameOutputs = nullptr; auto helper = std::unique_ptr(new WhiteBoxOclocArgHelper(0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, &numOutputs, &outputs, &lenOutputs, &nameOutputs)); EXPECT_TRUE(helper->messagePrinter.isSuppressed()); ConstStringRef printMsg = "Hello world!"; testing::internal::CaptureStdout(); helper->printf(printMsg.data()); std::string capturedStdout = testing::internal::GetCapturedStdout(); EXPECT_TRUE(capturedStdout.empty()); helper.reset(); // Delete helper. Destructor saves data to output EXPECT_EQ(1U, numOutputs); EXPECT_EQ(printMsg.length() + 1, lenOutputs[0]); EXPECT_STREQ("stdout.log", nameOutputs[0]); std::string stdoutStr = std::string(reinterpret_cast(outputs[0]), static_cast(lenOutputs[0])); EXPECT_STREQ(printMsg.data(), stdoutStr.c_str()); delete[] nameOutputs[0]; delete[] outputs[0]; delete[] nameOutputs; delete[] outputs; delete[] lenOutputs; } TEST(OclocArgHelperTest, GivenValidSourceFileWhenRequestingVectorOfStringsThenLinesAreStored) { const char input[] = "First\nSecond\nThird"; const auto inputLength{sizeof(input)}; const auto filename{"some_file.txt"}; Source source{reinterpret_cast(input), inputLength, filename}; std::vector lines{}; source.toVectorOfStrings(lines); ASSERT_EQ(3u, lines.size()); EXPECT_EQ("First", lines[0]); EXPECT_EQ("Second", lines[1]); EXPECT_EQ("Third", lines[2]); } TEST(OclocArgHelperTest, GivenSourceFileWithTabsWhenRequestingVectorOfStringsWithTabsReplacementThenLinesWithSpacesAreStored) { const char input[] = "First\tWord\nSecond\tWord\nThird\tWord"; const auto inputLength{sizeof(input)}; const auto filename{"some_file.txt"}; Source source{reinterpret_cast(input), inputLength, filename}; constexpr bool replaceTabs{true}; std::vector lines{}; source.toVectorOfStrings(lines, replaceTabs); ASSERT_EQ(3u, lines.size()); EXPECT_EQ("First Word", lines[0]); EXPECT_EQ("Second Word", lines[1]); EXPECT_EQ("Third Word", lines[2]); } TEST(OclocArgHelperTest, GivenSourceFileWithEmptyLinesWhenRequestingVectorOfStringsThenOnlyNonEmptyLinesAreStored) { const char input[] = "First\n\n\nSecond\n"; const auto inputLength{sizeof(input)}; const auto filename{"some_file.txt"}; Source source{reinterpret_cast(input), inputLength, filename}; std::vector lines{}; source.toVectorOfStrings(lines); ASSERT_EQ(2u, lines.size()); EXPECT_EQ("First", lines[0]); EXPECT_EQ("Second", lines[1]); } TEST(OclocArgHelperTest, GivenSourceFileWhenRequestingBinaryVectorThenBinaryIsReturned) { const char input[] = "A file content"; const auto inputLength{sizeof(input)}; const auto filename{"some_file.txt"}; Source source{reinterpret_cast(input), inputLength, filename}; const auto binaryContent = source.toBinaryVector(); ASSERT_EQ(inputLength, binaryContent.size()); ASSERT_TRUE(std::equal(binaryContent.begin(), binaryContent.end(), input)); } TEST(OclocArgHelperTest, GivenNoOutputPrintMessages) { auto helper = WhiteBoxOclocArgHelper(0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); EXPECT_FALSE(helper.messagePrinter.isSuppressed()); ConstStringRef printMsg = "Hello world!"; testing::internal::CaptureStdout(); helper.printf(printMsg.data()); std::string capturedStdout = testing::internal::GetCapturedStdout(); EXPECT_STREQ(printMsg.data(), capturedStdout.c_str()); } TEST(OclocArgHelperTest, GivenValidHeaderFileWhenRequestingHeadersAsVectorOfStringsThenLinesAreStored) { const char input[] = "First\nSecond\nThird"; const auto inputLength{sizeof(input)}; const auto filename{"some_file.txt"}; Source source{reinterpret_cast(input), inputLength, filename}; MockOclocArgHelper::FilesMap mockArgHelperFilesMap{}; MockOclocArgHelper mockOclocArgHelper{mockArgHelperFilesMap}; mockOclocArgHelper.headers.push_back(source); const auto lines = mockOclocArgHelper.headersToVectorOfStrings(); ASSERT_EQ(3u, lines.size()); EXPECT_EQ("First", lines[0]); EXPECT_EQ("Second", lines[1]); EXPECT_EQ("Third", lines[2]); } TEST(OclocArgHelperTest, GivenValidSourceFileWhenLookingForItThenItIsReturned) { const char input[] = "First\nSecond\nThird"; const auto inputLength{sizeof(input)}; const auto filename{"some_file.txt"}; Source source{reinterpret_cast(input), inputLength, filename}; MockOclocArgHelper::FilesMap mockArgHelperFilesMap{}; MockOclocArgHelper mockOclocArgHelper{mockArgHelperFilesMap}; mockOclocArgHelper.inputs.push_back(source); const auto file = mockOclocArgHelper.findSourceFile("some_file.txt"); EXPECT_EQ(&mockOclocArgHelper.inputs[0], file); } TEST(OclocArgHelperTest, GivenValidSourceFileWhenLookingForAnotherOneThenNullptrIsReturned) { const char input[] = "First\nSecond\nThird"; const auto inputLength{sizeof(input)}; const auto filename{"some_file.txt"}; Source source{reinterpret_cast(input), inputLength, filename}; MockOclocArgHelper::FilesMap mockArgHelperFilesMap{}; MockOclocArgHelper mockOclocArgHelper{mockArgHelperFilesMap}; mockOclocArgHelper.inputs.push_back(source); const auto file = mockOclocArgHelper.findSourceFile("another_file.txt"); EXPECT_EQ(nullptr, file); } TEST(OclocArgHelperTest, GivenValidSourceFileWhenReadingItViaHelperAsVectorOfStringsThenLinesAreReturned) { const char input[] = "First\nSecond\nThird"; const auto inputLength{sizeof(input)}; const auto filename{"some_file.txt"}; Source source{reinterpret_cast(input), inputLength, filename}; MockOclocArgHelper::FilesMap mockArgHelperFilesMap{}; MockOclocArgHelper mockOclocArgHelper{mockArgHelperFilesMap}; mockOclocArgHelper.callBaseReadFileToVectorOfStrings = true; mockOclocArgHelper.inputs.push_back(source); std::vector lines{}; mockOclocArgHelper.readFileToVectorOfStrings("some_file.txt", lines); ASSERT_EQ(3u, lines.size()); EXPECT_EQ("First", lines[0]); EXPECT_EQ("Second", lines[1]); EXPECT_EQ("Third", lines[2]); } TEST(OclocArgHelperTest, GivenValidSourceFileWhenReadingItViaHelperAsBinaryThenItIsReturned) { const char input[] = "First\nSecond\nThird"; const auto inputLength{sizeof(input)}; const auto filename{"some_file.txt"}; Source source{reinterpret_cast(input), inputLength, filename}; MockOclocArgHelper::FilesMap mockArgHelperFilesMap{}; MockOclocArgHelper mockOclocArgHelper{mockArgHelperFilesMap}; mockOclocArgHelper.callBaseReadBinaryFile = true; mockOclocArgHelper.inputs.push_back(source); const auto fileContent = mockOclocArgHelper.readBinaryFile("some_file.txt"); ASSERT_EQ(inputLength, fileContent.size()); const auto isContentIdentical = (0 == std::memcmp(input, fileContent.data(), inputLength)); EXPECT_TRUE(isContentIdentical); } TEST(OclocQuery, WhenQueryingDeviceExtensionsThenExtensionsStringIsReturned) { MockOclocArgHelper::FilesMap vfs; MockOclocArgHelper argHelper{vfs}; argHelper.callBaseFileExists = false; argHelper.callBaseLoadDataFromFile = false; argHelper.callBaseReadBinaryFile = false; argHelper.callBaseReadFileToVectorOfStrings = false; argHelper.messagePrinter.setSuppressMessages(true); std::string query = "CL_DEVICE_EXTENSIONS"; std::string commonExt = "cl_khr_icd"; std::vector argv = {"ocloc", "query", query}; int retVal = OfflineCompiler::query(argv.size(), argv, &argHelper); EXPECT_EQ(OCLOC_SUCCESS, retVal); auto log = argHelper.getPrinterRef().getLog().str(); EXPECT_FALSE(log.empty()); EXPECT_TRUE(hasSubstr(log, commonExt)) << commonExt << " e/ " << log; ASSERT_EQ(1U, vfs.count(query)); auto file = vfs[query]; EXPECT_FALSE(file.empty()); EXPECT_TRUE(hasSubstr(file, commonExt)) << commonExt << " e/ " << file; } TEST(OclocQuery, WhenQueryingDeviceExtensionsWithVersionsThenExtensionsStringWithVersionsIsReturned) { MockOclocArgHelper::FilesMap vfs; MockOclocArgHelper argHelper{vfs}; argHelper.callBaseFileExists = false; argHelper.callBaseLoadDataFromFile = false; argHelper.callBaseReadBinaryFile = false; argHelper.callBaseReadFileToVectorOfStrings = false; argHelper.messagePrinter.setSuppressMessages(true); std::string query = "CL_DEVICE_EXTENSIONS_WITH_VERSION"; std::string commonExt = "cl_khr_icd:1.0.0"; ocloc_name_version extWithVersion; strcpy_s(extWithVersion.name, sizeof(extWithVersion.name), "cl_khr_icd"); extWithVersion.version = CL_MAKE_VERSION(1, 0, 0); std::vector argv = {"ocloc", "query", query}; int retVal = OfflineCompiler::query(argv.size(), argv, &argHelper); EXPECT_EQ(OCLOC_SUCCESS, retVal); auto log = argHelper.getPrinterRef().getLog().str(); EXPECT_FALSE(log.empty()); EXPECT_TRUE(hasSubstr(log, commonExt)) << commonExt << " e/ " << log; ASSERT_EQ(1U, vfs.count(query)); auto file = vfs[query]; EXPECT_NE(0U, file.size()); EXPECT_EQ(0U, file.size() % sizeof(ocloc_name_version)); auto it = reinterpret_cast(file.data()); auto end = reinterpret_cast(file.data() + file.size()); decltype(it) found = nullptr; for (; it < end; ++it) { if ((0 == strcmp(extWithVersion.name, it->name)) && (extWithVersion.version == it->version)) { found = it; } } ASSERT_NE(nullptr, found); } TEST(OclocQuery, WhenQueryingDeviceProfileThenFullProfileStringIsReturned) { MockOclocArgHelper::FilesMap vfs; MockOclocArgHelper argHelper{vfs}; argHelper.callBaseFileExists = false; argHelper.callBaseLoadDataFromFile = false; argHelper.callBaseReadBinaryFile = false; argHelper.callBaseReadFileToVectorOfStrings = false; argHelper.messagePrinter.setSuppressMessages(true); std::string query = "CL_DEVICE_PROFILE"; std::string expProfile = "FULL_PROFILE"; std::vector argv = {"ocloc", "query", query}; int retVal = OfflineCompiler::query(argv.size(), argv, &argHelper); EXPECT_EQ(OCLOC_SUCCESS, retVal); auto log = argHelper.getPrinterRef().getLog().str(); EXPECT_FALSE(log.empty()); EXPECT_TRUE(hasSubstr(log, expProfile)) << expProfile << " e/ " << log; ASSERT_EQ(1U, vfs.count(query)); auto file = vfs[query]; EXPECT_FALSE(file.empty()); EXPECT_TRUE(hasSubstr(file, expProfile)) << expProfile << " e/ " << file; } TEST(OclocQuery, WhenQueryingDeviceOpenCLCAllVersionsThenVersionsStringIsReturned) { MockOclocArgHelper::FilesMap vfs; MockOclocArgHelper argHelper{vfs}; argHelper.callBaseFileExists = false; argHelper.callBaseLoadDataFromFile = false; argHelper.callBaseReadBinaryFile = false; argHelper.callBaseReadFileToVectorOfStrings = false; argHelper.messagePrinter.setSuppressMessages(true); std::string query = "CL_DEVICE_OPENCL_C_ALL_VERSIONS"; std::string commonVer = "\"OpenCL C\":1.2"; ocloc_name_version oclcVersion; strcpy_s(oclcVersion.name, sizeof(oclcVersion.name), "OpenCL C"); oclcVersion.version = CL_MAKE_VERSION(1, 2, 0); std::vector argv = {"ocloc", "query", query}; int retVal = OfflineCompiler::query(argv.size(), argv, &argHelper); EXPECT_EQ(OCLOC_SUCCESS, retVal); auto log = argHelper.getPrinterRef().getLog().str(); EXPECT_FALSE(log.empty()); EXPECT_TRUE(hasSubstr(log, commonVer)) << commonVer << " e/ " << log; ASSERT_EQ(1U, vfs.count(query)); auto file = vfs[query]; EXPECT_NE(0U, file.size()); EXPECT_EQ(0U, file.size() % sizeof(ocloc_name_version)); auto it = reinterpret_cast(file.data()); auto end = reinterpret_cast(file.data() + file.size()); decltype(it) found = nullptr; for (; it < end; ++it) { if ((0 == strcmp(oclcVersion.name, it->name)) && (oclcVersion.version == it->version)) { found = it; } } EXPECT_NE(nullptr, found); } TEST(OclocQuery, WhenQueryingDeviceOpenCFeaturesThenFeaturesStringWithVersionsIsReturned) { MockOclocArgHelper::FilesMap vfs; MockOclocArgHelper argHelper{vfs}; argHelper.callBaseFileExists = false; argHelper.callBaseLoadDataFromFile = false; argHelper.callBaseReadBinaryFile = false; argHelper.callBaseReadFileToVectorOfStrings = false; argHelper.messagePrinter.setSuppressMessages(true); std::string query = "CL_DEVICE_OPENCL_C_FEATURES"; std::string commonFeature = "__opencl_c_int64:3.0.0"; ocloc_name_version featureWithVersion; strcpy_s(featureWithVersion.name, sizeof(featureWithVersion.name), "__opencl_c_int64"); featureWithVersion.version = CL_MAKE_VERSION(3, 0, 0); std::vector argv = {"ocloc", "query", query}; int retVal = OfflineCompiler::query(argv.size(), argv, &argHelper); EXPECT_EQ(OCLOC_SUCCESS, retVal); auto log = argHelper.getPrinterRef().getLog().str(); EXPECT_FALSE(log.empty()); EXPECT_TRUE(hasSubstr(log, commonFeature)) << commonFeature << " e/ " << log; ASSERT_EQ(1U, vfs.count(query)); auto file = vfs[query]; EXPECT_NE(0U, file.size()); EXPECT_EQ(0U, file.size() % sizeof(ocloc_name_version)); auto it = reinterpret_cast(file.data()); auto end = reinterpret_cast(file.data() + file.size()); decltype(it) found = nullptr; for (; it < end; ++it) { if ((0 == strcmp(featureWithVersion.name, it->name)) && (featureWithVersion.version == it->version)) { found = it; } } ASSERT_NE(nullptr, found); } } // namespace NEO