From bb16789fcd331105cd3f1ac92c085f63df1094b2 Mon Sep 17 00:00:00 2001 From: Fabian Zwolinski Date: Tue, 13 Jun 2023 09:56:51 +0000 Subject: [PATCH] feature: Allow to pass multiple devices separated by commas in -device-options Related-To: NEO-8037 Signed-off-by: Fabian Zwolinski --- .../ocloc_fatbinary_tests.cpp | 34 +++++ .../offline_compiler_tests.cpp | 128 ++++++++++++++++++ .../source/ocloc_fatbinary.cpp | 6 +- .../source/offline_compiler.cpp | 34 +++-- 4 files changed, 192 insertions(+), 10 deletions(-) diff --git a/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp b/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp index 89183e26a2..c7f3ec15b1 100644 --- a/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp +++ b/opencl/test/unit_test/offline_compiler/ocloc_fatbinary_tests.cpp @@ -1136,6 +1136,40 @@ TEST_F(OclocFatBinaryProductAcronymsTests, givenDeviceOptionsForCompiledDeviceAn EXPECT_FALSE(hasSubstr(output, errorMessage2.str())); } +TEST_F(OclocFatBinaryProductAcronymsTests, givenDeviceOptionsForMultipleDevicesSeparatedByCommasWhenFatBinaryBuildIsInvokedThenWarningIsNotPrinted) { + if (enabledProductsAcronyms.size() < 3) { + GTEST_SKIP(); + } + + std::stringstream products, productsForDeviceOptions; + products << enabledProductsAcronyms[0].str() << "," + << enabledProductsAcronyms[1].str() << "," + << enabledProductsAcronyms[2].str(); + + productsForDeviceOptions << enabledProductsAcronyms[0].str() << "," + << enabledProductsAcronyms[1].str(); + + oclocArgHelperWithoutInput->getPrinterRef().setSuppressMessages(false); + std::stringstream resString; + std::vector argv = { + "ocloc", + "-file", + clFiles + "copybuffer.cl", + "-device", + products.str().c_str(), + "-device-options", + productsForDeviceOptions.str().c_str(), + "deviceOptions"}; + + testing::internal::CaptureStdout(); + [[maybe_unused]] int retVal = buildFatBinary(argv, oclocArgHelperWithoutInput.get()); + auto output = testing::internal::GetCapturedStdout(); + + std::stringstream expectedErrorMessage; + expectedErrorMessage << "Warning! -device-options set for non-compiled device"; + EXPECT_FALSE(hasSubstr(output, expectedErrorMessage.str())); +} + TEST_F(OclocFatBinaryProductAcronymsTests, givenOpenRangeToReleaseWhenFatBinaryBuildIsInvokedThenSuccessIsReturned) { if (enabledReleasesAcronyms.size() < 3) { GTEST_SKIP(); diff --git a/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp b/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp index 7b7390f1bd..4d5e9e6713 100644 --- a/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp +++ b/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp @@ -3286,6 +3286,42 @@ TEST(OfflineCompilerTest, givenDeviceOptionsForCompiledDeviceWhenCmdLineParsedTh 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(OclocErrorCode::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", @@ -3440,6 +3476,98 @@ TEST(OfflineCompilerTest, givenMultipleDeviceOptionsForCompiledDeviceAndDeviceOp 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"}; + + testing::internal::CaptureStdout(); + mockOfflineCompiler->parseCommandLine(argv.size(), argv); + std::string output = testing::internal::GetCapturedStdout(); + + EXPECT_NE(0u, output.size()); + + 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(OclocErrorCode::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", diff --git a/shared/offline_compiler/source/ocloc_fatbinary.cpp b/shared/offline_compiler/source/ocloc_fatbinary.cpp index 21a208c02e..dd42745477 100644 --- a/shared/offline_compiler/source/ocloc_fatbinary.cpp +++ b/shared/offline_compiler/source/ocloc_fatbinary.cpp @@ -326,8 +326,10 @@ int buildFatBinary(const std::vector &args, OclocArgHelper *argHelp } else if (ConstStringRef("-spirv_input") == currArg) { spirvInput = true; } else if (("-device-options" == currArg) && hasAtLeast2MoreArgs) { - const auto &deviceName = args[argIndex + 1]; - deviceAcronymsFromDeviceOptions.insert(deviceName); + const auto deviceAcronyms = CompilerOptions::tokenize(args[argIndex + 1], ','); + for (const auto &deviceAcronym : deviceAcronyms) { + deviceAcronymsFromDeviceOptions.insert(deviceAcronym.str()); + } argIndex += 2; } } diff --git a/shared/offline_compiler/source/offline_compiler.cpp b/shared/offline_compiler/source/offline_compiler.cpp index 9354da45c6..59c2753453 100644 --- a/shared/offline_compiler/source/offline_compiler.cpp +++ b/shared/offline_compiler/source/offline_compiler.cpp @@ -13,6 +13,7 @@ #include "shared/source/compiler_interface/compiler_options.h" #include "shared/source/compiler_interface/default_cache_config.h" #include "shared/source/compiler_interface/intermediate_representations.h" +#include "shared/source/compiler_interface/tokenized_string.h" #include "shared/source/debug_settings/debug_settings_manager.h" #include "shared/source/device_binary_format/device_binary_formats.h" #include "shared/source/device_binary_format/elf/elf_encoder.h" @@ -30,6 +31,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -672,6 +674,7 @@ int OfflineCompiler::parseCommandLine(size_t numArgs, const std::vector deviceAcronymsFromDeviceOptions; for (uint32_t argIndex = 1; argIndex < argv.size(); argIndex++) { const auto &currArg = argv[argIndex]; @@ -715,9 +718,12 @@ int OfflineCompiler::parseCommandLine(size_t numArgs, const std::vectorproductConfigHelper->getProductConfigFromAcronym(deviceName); + for (const auto &device : deviceAcronymsFromDeviceOptions) { + auto productConfig = argHelper->productConfigHelper->getProductConfigFromDeviceName(device); if (productConfig == AOT::UNKNOWN_ISA) { - argHelper->printf("Error: Invalid device acronym passed to -device-options: %s\n", deviceName.c_str()); - retVal = INVALID_COMMAND_LINE; + auto productName = device; + std::transform(productName.begin(), productName.end(), productName.begin(), ::tolower); + std::vector allSupportedProduct{ALL_SUPPORTED_PRODUCT_FAMILIES}; + auto isDeprecatedName = false; + for (const auto &product : allSupportedProduct) { + if (0 == strcmp(productName.c_str(), hardwarePrefix[product])) { + isDeprecatedName = true; + break; + } + } + if (!isDeprecatedName) { + argHelper->printf("Error: Invalid device acronym passed to -device-options: %s\n", device.c_str()); + retVal = INVALID_COMMAND_LINE; + } } } @@ -985,7 +1002,8 @@ Usage: ocloc [compile] -file -device [-output Optional OpenCL C compilation options as defined by OpenCL specification - specific to a single target device. - can be product acronym i.e. dg1 + Multiple product acronyms may be provided - separated by commas. + can be product acronym or version passed in -device i.e. dg1 or 12.10.0 -32 Forces target architecture to 32-bit pointers. Default pointer size is inherited from