From 359f4d5b566dd3c78b886acd572d5d57437e860b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Zwoli=C5=84ski?= Date: Wed, 10 Jul 2024 16:54:24 +0000 Subject: [PATCH] feature: add SUPPORTED_DEVICES query to ocloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New query option ocloc query SUPPORTED_DEVICE allows to generate a YAML file containing information about supported devices for: - the current version of ocloc on Windows - the current and previous versions of ocloc on Linux Each version of ocloc build needs to set NEO_OCLOC_CURRENT_LIB_NAME NEO_OCLOC_FORMER_LIB_NAME cmake defines for the ocloc to be able to find a previous lib and query its supported devices. Example of correct format: NEO_OCLOC_FORMER_LIB_NAME=libocloc-1.0.so NEO_OCLOC_CURRENT_LIB_NAME=libocloc-2.0.so Related-To: NEO-9630 Signed-off-by: Fabian ZwoliƄski --- .../unit_test/offline_compiler/CMakeLists.txt | 15 + ...c_supported_devices_helper_linux_tests.cpp | 52 ++ .../offline_compiler/mock/CMakeLists.txt | 3 +- .../mock_ocloc_supported_devices_helper.h | 86 ++ .../ocloc_supported_devices_helper_tests.cpp | 777 ++++++++++++++++++ .../offline_compiler_tests.cpp | 26 + ...supported_devices_helper_windows_tests.cpp | 58 ++ shared/offline_compiler/source/CMakeLists.txt | 7 + .../ocloc_supported_devices_helper_linux.cpp | 119 +++ shared/offline_compiler/source/ocloc_api.h | 8 +- .../source/ocloc_supported_devices_helper.cpp | 299 +++++++ .../source/ocloc_supported_devices_helper.h | 104 +++ .../source/offline_compiler.cpp | 34 + .../source/offline_compiler.h | 22 + shared/offline_compiler/source/queries.h | 6 +- ...ocloc_supported_devices_helper_windows.cpp | 47 ++ 16 files changed, 1659 insertions(+), 4 deletions(-) create mode 100644 opencl/test/unit_test/offline_compiler/linux/ocloc_supported_devices_helper_linux_tests.cpp create mode 100644 opencl/test/unit_test/offline_compiler/mock/mock_ocloc_supported_devices_helper.h create mode 100644 opencl/test/unit_test/offline_compiler/ocloc_supported_devices_helper_tests.cpp create mode 100644 opencl/test/unit_test/offline_compiler/windows/ocloc_supported_devices_helper_windows_tests.cpp create mode 100644 shared/offline_compiler/source/linux/ocloc_supported_devices_helper_linux.cpp create mode 100644 shared/offline_compiler/source/ocloc_supported_devices_helper.cpp create mode 100644 shared/offline_compiler/source/ocloc_supported_devices_helper.h create mode 100644 shared/offline_compiler/source/windows/ocloc_supported_devices_helper_windows.cpp diff --git a/opencl/test/unit_test/offline_compiler/CMakeLists.txt b/opencl/test/unit_test/offline_compiler/CMakeLists.txt index bca3ea896c..a629ec0943 100644 --- a/opencl/test/unit_test/offline_compiler/CMakeLists.txt +++ b/opencl/test/unit_test/offline_compiler/CMakeLists.txt @@ -13,8 +13,20 @@ set(IGDRCL_SRCS_cloc ${OCLOC_DIRECTORY}/source/offline_linker.cpp ${OCLOC_DIRECTORY}/source/ocloc_concat.cpp ${OCLOC_DIRECTORY}/source/ocloc_fatbinary.cpp + ${OCLOC_DIRECTORY}/source/ocloc_supported_devices_helper.h + ${OCLOC_DIRECTORY}/source/ocloc_supported_devices_helper.cpp ) +if(WIN32) + list(APPEND IGDRCL_SRCS_cloc + ${OCLOC_DIRECTORY}/source/windows/ocloc_supported_devices_helper_windows.cpp + ) +else() + list(APPEND IGDRCL_SRCS_cloc + ${OCLOC_DIRECTORY}/source/linux/ocloc_supported_devices_helper_linux.cpp + ) +endif() + set(IGDRCL_SRCS_offline_compiler_mock ${CMAKE_CURRENT_SOURCE_DIR}/decoder/mock/mock_decoder.h ${CMAKE_CURRENT_SOURCE_DIR}/decoder/mock/mock_encoder.h @@ -66,6 +78,7 @@ set(IGDRCL_SRCS_offline_compiler_tests ${CMAKE_CURRENT_SOURCE_DIR}/ocloc_igc_facade_tests.h ${CMAKE_CURRENT_SOURCE_DIR}/ocloc_product_config_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ocloc_product_config_tests.h + ${CMAKE_CURRENT_SOURCE_DIR}/ocloc_supported_devices_helper_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ocloc_tests_configuration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ocloc_validator_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/offline_compiler_tests.cpp @@ -103,6 +116,7 @@ if(WIN32) list(APPEND IGDRCL_SRCS_offline_compiler_tests ${NEO_SHARED_DIRECTORY}/os_interface/windows/os_thread_win.cpp ${NEO_SHARED_TEST_DIRECTORY}/common/os_interface/windows/signal_utils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/windows/ocloc_supported_devices_helper_windows_tests.cpp ) list(REMOVE_ITEM IGDRCL_SRCS_offline_compiler_tests ${NEO_SHARED_DIRECTORY}/utilities/windows/directory.cpp @@ -113,6 +127,7 @@ else() ${NEO_SHARED_DIRECTORY}/os_interface/linux/sys_calls_linux.cpp ${NEO_SHARED_TEST_DIRECTORY}/common/os_interface/linux/signal_utils.cpp ${OCLOC_DIRECTORY}/source/linux/os_library_ocloc_helper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/ocloc_supported_devices_helper_linux_tests.cpp ) list(REMOVE_ITEM IGDRCL_SRCS_offline_compiler_tests ${NEO_SHARED_DIRECTORY}/utilities/linux/directory.cpp diff --git a/opencl/test/unit_test/offline_compiler/linux/ocloc_supported_devices_helper_linux_tests.cpp b/opencl/test/unit_test/offline_compiler/linux/ocloc_supported_devices_helper_linux_tests.cpp new file mode 100644 index 0000000000..e96bdd7b50 --- /dev/null +++ b/opencl/test/unit_test/offline_compiler/linux/ocloc_supported_devices_helper_linux_tests.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/offline_compiler/source/ocloc_supported_devices_helper.h" + +#include "opencl/test/unit_test/offline_compiler/mock/mock_ocloc_supported_devices_helper.h" + +#include "gtest/gtest.h" + +namespace NEO { +using namespace Ocloc; + +struct SupportedDevicesHelperLinuxTest : public ::testing::Test { + void SetUp() override { + mockHelper.getOclocCurrentVersionMockResult = ""; + } + + void TearDown() override { + } + + MockSupportedDevicesHelper mockHelper = MockSupportedDevicesHelper(SupportedDevicesMode::concat, nullptr); +}; + +TEST_F(SupportedDevicesHelperLinuxTest, GivenVariousOclocLibraryNamesWhenExtractingOclocVersionThenEmptyStringIsReturned) { + { + // Valid Ocloc lib names + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc-2.0.1.so"), "ocloc-2.0.1"); + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc-2.0.so"), "ocloc-2.0"); + } + + { + // Invalid Ocloc lib names + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc2.0.so"), "ocloc"); + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc-2.0"), "ocloc"); + EXPECT_EQ(mockHelper.extractOclocVersion(""), "ocloc"); + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc.so"), "ocloc"); + } +} + +TEST_F(SupportedDevicesHelperLinuxTest, GivenSupportedDevicesHelperWhenGetOclocCurrentVersionThenReturnCorrectValue) { + EXPECT_EQ("ocloc-current", mockHelper.getOclocCurrentVersion()); +} + +TEST_F(SupportedDevicesHelperLinuxTest, GivenSupportedDevicesHelperWhenGetOclocFormerVersionThenReturnCorrectValue) { + EXPECT_EQ("ocloc-former", mockHelper.getOclocFormerVersion()); +} + +} // namespace NEO diff --git a/opencl/test/unit_test/offline_compiler/mock/CMakeLists.txt b/opencl/test/unit_test/offline_compiler/mock/CMakeLists.txt index e7f9f403dc..f54b506a99 100644 --- a/opencl/test/unit_test/offline_compiler/mock/CMakeLists.txt +++ b/opencl/test/unit_test/offline_compiler/mock/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2023 Intel Corporation +# Copyright (C) 2023-2024 Intel Corporation # # SPDX-License-Identifier: MIT # @@ -13,6 +13,7 @@ target_sources(ocloc_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/mock_ocloc_fcl_facade.h ${CMAKE_CURRENT_SOURCE_DIR}/mock_ocloc_igc_facade.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mock_ocloc_igc_facade.h + ${CMAKE_CURRENT_SOURCE_DIR}/mock_ocloc_supported_devices_helper.h ${CMAKE_CURRENT_SOURCE_DIR}/mock_offline_compiler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mock_offline_compiler.h ${CMAKE_CURRENT_SOURCE_DIR}/mock_offline_linker.h diff --git a/opencl/test/unit_test/offline_compiler/mock/mock_ocloc_supported_devices_helper.h b/opencl/test/unit_test/offline_compiler/mock/mock_ocloc_supported_devices_helper.h new file mode 100644 index 0000000000..3acc1a79c1 --- /dev/null +++ b/opencl/test/unit_test/offline_compiler/mock/mock_ocloc_supported_devices_helper.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "shared/offline_compiler/source/ocloc_supported_devices_helper.h" + +#include "gtest/gtest.h" + +#include + +namespace NEO { +using namespace Ocloc; + +class MockSupportedDevicesHelper : public SupportedDevicesHelper { + public: + using SupportedDevicesHelper::extractOclocVersion; + using SupportedDevicesHelper::getOclocCurrentLibName; + using SupportedDevicesHelper::getOclocCurrentVersion; + using SupportedDevicesHelper::getOclocFormerLibName; + using SupportedDevicesHelper::getOclocFormerVersion; + using SupportedDevicesHelper::mergeOclocVersionData; + + public: + MockSupportedDevicesHelper(SupportedDevicesMode mode, ProductConfigHelper *productConfigHelper) + : SupportedDevicesHelper(mode, productConfigHelper) {} + + std::string getOclocCurrentLibName() const override { + if (!getOclocCurrentLibNameMockResult.empty()) { + return getOclocCurrentLibNameMockResult; + } + return SupportedDevicesHelper::getOclocCurrentLibName(); + } + + std::string getOclocFormerLibName() const override { + if (!getOclocFormerLibNameMockResult.empty()) { + return getOclocFormerLibNameMockResult; + } + return SupportedDevicesHelper::getOclocFormerLibName(); + } + + std::string getDataFromFormerOclocVersion() const override { + if (getDataFromFormerOclocVersionEmptyResult) { + return ""; + } + + return R"(ocloc-former: + device_ip_versions: + - 0x3000001 + - 0x3000002 + ip_to_dev_rev_id: + - ip: 0x3000001 + revision_id: 1 + device_id: 0x3333 + - ip: 0x3000002 + revision_id: 2 + device_id: 0x4444 + acronym: + eee: 0x3000001 + fff: 0x3000002 + family_groups: + FAMILY_FORMER: [0x3000001, 0x3000002] + release_groups: + RELEASE_FORMER: [0x3000001, 0x3000002] +)"; + } + + std::string getOclocCurrentVersion() const override { + if (!getOclocCurrentVersionMockResult.empty()) { + return getOclocCurrentVersionMockResult; + } + return SupportedDevicesHelper::getOclocCurrentVersion(); + } + + public: + std::string getOclocCurrentLibNameMockResult = "libocloc-current.so"; + std::string getOclocFormerLibNameMockResult = "libocloc-former.so"; + bool getDataFromFormerOclocVersionEmptyResult = false; + std::string getOclocCurrentVersionMockResult = "ocloc-current"; +}; + +} // namespace NEO diff --git a/opencl/test/unit_test/offline_compiler/ocloc_supported_devices_helper_tests.cpp b/opencl/test/unit_test/offline_compiler/ocloc_supported_devices_helper_tests.cpp new file mode 100644 index 0000000000..81e3b2a2de --- /dev/null +++ b/opencl/test/unit_test/offline_compiler/ocloc_supported_devices_helper_tests.cpp @@ -0,0 +1,777 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/offline_compiler/source/ocloc_arg_helper.h" +#include "shared/offline_compiler/source/ocloc_supported_devices_helper.h" +#include "shared/source/device_binary_format/yaml/yaml_parser.h" +#include "shared/test/common/helpers/debug_manager_state_restore.h" + +#include "opencl/test/unit_test/offline_compiler/mock/mock_ocloc_supported_devices_helper.h" + +#include "gtest/gtest.h" +#include "mock/mock_argument_helper.h" + +#include +#include +#include + +namespace NEO { + +struct SupportedDevicesHelperTest : public ::testing::Test { + struct MockDeviceData { + uint32_t ipVersion; + uint32_t revision; + std::vector deviceIds; + std::vector acronyms; + AOT::FAMILY family; + AOT::RELEASE release; + }; + + void initMockDevices() { + auto deviceAotInfo = argHelper->productConfigHelper->getDeviceAotInfo(); + + if (deviceAotInfo.size() < 2) { + GTEST_SKIP(); + } + + std::set families; + std::set releases; + + for (const auto &device : deviceAotInfo) { + families.insert(device.family); + releases.insert(device.release); + } + + if (families.size() < 2 || releases.size() < 2) { + GTEST_SKIP(); + } + + auto familyIt = families.begin(); + family1 = *familyIt; + family2 = *(++familyIt); + + auto releaseIt = releases.begin(); + release1 = *releaseIt; + release2 = *(++releaseIt); + + if (argHelper->productConfigHelper->getAcronymFromAFamily(family1).empty() || + argHelper->productConfigHelper->getAcronymFromAFamily(family2).empty() || + argHelper->productConfigHelper->getAcronymFromARelease(release1).empty() || + argHelper->productConfigHelper->getAcronymFromARelease(release2).empty()) { + GTEST_SKIP(); + } + + const auto revisionBits = 0x3F; + + mockDevices = { + {0x1000001, 0x1000001 & revisionBits, {0x1111, 0x1100}, {"aaa", "bbb"}, family1, release1}, + {0x2000002, 0x2000002 & revisionBits, {0x2222, 0x2200}, {"ccc", "ddd"}, family2, release2}}; + } + + void prepareMockDeviceAotInfo(std::vector &dest) { + for (const auto &mockDevice : mockDevices) { + DeviceAotInfo enabledDevice; + enabledDevice.aotConfig.value = mockDevice.ipVersion; + enabledDevice.aotConfig.revision = mockDevice.revision; + enabledDevice.deviceIds = new std::vector(mockDevice.deviceIds); + enabledDevice.deviceAcronyms = mockDevice.acronyms; + enabledDevice.family = mockDevice.family; + enabledDevice.release = mockDevice.release; + dest.push_back(enabledDevice); + } + } + void SetUp() override { + initMockDevices(); + prepareMockDeviceAotInfo(enabledDevices); + } + + void TearDown() override { + for (auto &device : enabledDevices) { + delete device.deviceIds; + } + } + + std::map filesMap; + std::unique_ptr argHelper = std::make_unique(filesMap); + std::vector mockDevices; + std::vector enabledDevices; + + AOT::FAMILY family1; + AOT::FAMILY family2; + + AOT::RELEASE release1; + AOT::RELEASE release2; +}; + +TEST_F(SupportedDevicesHelperTest, WhenCollectingSupportedDevicesDataThenAllFieldsAreCorrectlyPopulated) { + SupportedDevicesMode mode = SupportedDevicesMode::concat; + SupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + + auto supportedDevicesData = supportedDevicesHelper.collectSupportedDevicesData(enabledDevices); + + // Verify deviceIpVersions + EXPECT_EQ(supportedDevicesData.deviceIpVersions.size(), mockDevices.size()); + for (size_t i = 0; i < mockDevices.size(); ++i) { + EXPECT_EQ(supportedDevicesData.deviceIpVersions[i], mockDevices[i].ipVersion); + } + + // Verify deviceInfos + size_t expectedDeviceInfosSize = 0; + for (const auto &mockDevice : mockDevices) { + expectedDeviceInfosSize += mockDevice.deviceIds.size(); + } + EXPECT_EQ(supportedDevicesData.deviceInfos.size(), expectedDeviceInfosSize); + + size_t deviceInfoIndex = 0; + for (const auto &mockDevice : mockDevices) { + for (const auto &deviceId : mockDevice.deviceIds) { + EXPECT_EQ(supportedDevicesData.deviceInfos[deviceInfoIndex].deviceId, deviceId); + EXPECT_EQ(supportedDevicesData.deviceInfos[deviceInfoIndex].revisionId, mockDevice.revision); + EXPECT_EQ(supportedDevicesData.deviceInfos[deviceInfoIndex].ipVersion, mockDevice.ipVersion); + ++deviceInfoIndex; + } + } + + // Verify acronyms + size_t expectedAcronymsSize = 0; + for (const auto &mockDevice : mockDevices) { + expectedAcronymsSize += mockDevice.acronyms.size(); + } + EXPECT_EQ(supportedDevicesData.acronyms.size(), expectedAcronymsSize); + + size_t acronymIndex = 0; + for (const auto &mockDevice : mockDevices) { + for (const auto &acronym : mockDevice.acronyms) { + EXPECT_EQ(supportedDevicesData.acronyms[acronymIndex].first, acronym.data()); + EXPECT_EQ(supportedDevicesData.acronyms[acronymIndex].second, mockDevice.ipVersion); + ++acronymIndex; + } + } + + // Verify familyGroups + EXPECT_EQ(supportedDevicesData.familyGroups.size(), mockDevices.size()); + for (const auto &mockDevice : mockDevices) { + auto findFamily = [&](const std::string &name) { + return std::find_if(supportedDevicesData.familyGroups.begin(), supportedDevicesData.familyGroups.end(), + [&](const auto &group) { return group.first == name; }); + }; + auto familyName = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevice.family); + auto familyIt = findFamily(familyName.data()); + ASSERT_NE(familyIt, supportedDevicesData.familyGroups.end()); + EXPECT_TRUE(std::find(familyIt->second.begin(), familyIt->second.end(), mockDevice.ipVersion) != familyIt->second.end()); + } + + // Verify releaseGroups + EXPECT_EQ(supportedDevicesData.releaseGroups.size(), mockDevices.size()); + for (const auto &mockDevice : mockDevices) { + auto findRelease = [&](const std::string &name) { + return std::find_if(supportedDevicesData.releaseGroups.begin(), supportedDevicesData.releaseGroups.end(), + [&](const auto &group) { return group.first == name; }); + }; + auto releaseName = argHelper->productConfigHelper->getAcronymFromARelease(mockDevice.release); + auto releaseIt = findRelease(releaseName.data()); + ASSERT_NE(releaseIt, supportedDevicesData.releaseGroups.end()); + EXPECT_TRUE(std::find(releaseIt->second.begin(), releaseIt->second.end(), mockDevice.ipVersion) != releaseIt->second.end()); + } +} + +TEST_F(SupportedDevicesHelperTest, WhenSerializingSupportedDevicesDataThenCorrectYamlIsGenerated) { + SupportedDevicesMode mode = SupportedDevicesMode::concat; + SupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + + auto supportedDevicesData = supportedDevicesHelper.collectSupportedDevicesData(enabledDevices); + + std::string serializedData = supportedDevicesHelper.serialize("ocloc-test", supportedDevicesData); + + auto family1 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[0].family); + auto family2 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[1].family); + auto release1 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[0].release); + auto release2 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[1].release); + + char expectedYaml[1024]; + snprintf(expectedYaml, sizeof(expectedYaml), + R"(ocloc-test: + device_ip_versions: + - 0x1000001 + - 0x2000002 + ip_to_dev_rev_id: + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1111 + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1100 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2222 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2200 + acronym: + aaa: 0x1000001 + bbb: 0x1000001 + ccc: 0x2000002 + ddd: 0x2000002 + family_groups: + %s: [0x1000001] + %s: [0x2000002] + release_groups: + %s: [0x1000001] + %s: [0x2000002] +)", + family1.data(), family2.data(), release1.data(), release2.data()); + + EXPECT_EQ(serializedData, expectedYaml); + + NEO::Yaml::YamlParser parser; + std::string errReason, warning; + EXPECT_TRUE(parser.parse(serializedData, errReason, warning)); + EXPECT_TRUE(errReason.empty()); +} + +TEST_F(SupportedDevicesHelperTest, WhenDeserializingSupportedDevicesDataThenAllFieldsAreCorrectlyPopulated) { + SupportedDevicesMode mode = SupportedDevicesMode::concat; + SupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + + std::string yamlData = R"(ocloc-test: + device_ip_versions: + - 0x1000001 + - 0x2000002 + ip_to_dev_rev_id: + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1111 + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1100 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2222 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2200 + acronym: + aaa: 0x1000001 + bbb: 0x1000001 + ccc: 0x2000002 + ddd: 0x2000002 + family_groups: + FAMILY1: [0x1000001, 0x1000002, 0x1000003] + FAMILY2: [0x2000002, 0x2000003] + release_groups: + RELEASE1: [0x1000001, 0x1000002] + RELEASE2: [0x2000002] +)"; + + auto deserializedData = supportedDevicesHelper.deserialize(yamlData); + + ASSERT_EQ(deserializedData.size(), 1u); + ASSERT_TRUE(deserializedData.find("ocloc-test") != deserializedData.end()); + + auto &data = deserializedData["ocloc-test"]; + + // Verify device_ip_versions + ASSERT_EQ(data.deviceIpVersions.size(), 2u); + EXPECT_EQ(data.deviceIpVersions[0], 0x1000001u); + EXPECT_EQ(data.deviceIpVersions[1], 0x2000002u); + + // Verify ip_to_dev_rev_id + ASSERT_EQ(data.deviceInfos.size(), 4u); + EXPECT_EQ(data.deviceInfos[0].ipVersion, 0x1000001u); + EXPECT_EQ(data.deviceInfos[0].revisionId, 1u); + EXPECT_EQ(data.deviceInfos[0].deviceId, 0x1111u); + EXPECT_EQ(data.deviceInfos[3].ipVersion, 0x2000002u); + EXPECT_EQ(data.deviceInfos[3].revisionId, 2u); + EXPECT_EQ(data.deviceInfos[3].deviceId, 0x2200u); + + // Verify acronyms + ASSERT_EQ(data.acronyms.size(), 4u); + EXPECT_EQ(data.acronyms[0].first, "aaa"); + EXPECT_EQ(data.acronyms[0].second, 0x1000001u); + EXPECT_EQ(data.acronyms[3].first, "ddd"); + EXPECT_EQ(data.acronyms[3].second, 0x2000002u); + + // Verify familyGroups + ASSERT_EQ(data.familyGroups.size(), 2u); + EXPECT_EQ(data.familyGroups[0].first, "FAMILY1"); + EXPECT_EQ(data.familyGroups[0].second.size(), 3u); + EXPECT_EQ(data.familyGroups[0].second[0], 0x1000001u); + EXPECT_EQ(data.familyGroups[0].second[1], 0x1000002u); + EXPECT_EQ(data.familyGroups[0].second[2], 0x1000003u); + + EXPECT_EQ(data.familyGroups[1].first, "FAMILY2"); + EXPECT_EQ(data.familyGroups[1].second.size(), 2u); + EXPECT_EQ(data.familyGroups[1].second[0], 0x2000002u); + EXPECT_EQ(data.familyGroups[1].second[1], 0x2000003u); + + // Verify releaseGroups + ASSERT_EQ(data.releaseGroups.size(), 2u); + EXPECT_EQ(data.releaseGroups[0].first, "RELEASE1"); + EXPECT_EQ(data.releaseGroups[0].second.size(), 2u); + EXPECT_EQ(data.releaseGroups[0].second[0], 0x1000001u); + EXPECT_EQ(data.releaseGroups[0].second[1], 0x1000002u); + + EXPECT_EQ(data.releaseGroups[1].first, "RELEASE2"); + EXPECT_EQ(data.releaseGroups[1].second.size(), 1u); + EXPECT_EQ(data.releaseGroups[1].second[0], 0x2000002u); +} + +TEST_F(SupportedDevicesHelperTest, WhenSerializingDeserializingAndSerializingAgainThenResultsAreIdentical) { + SupportedDevicesMode mode = SupportedDevicesMode::concat; + SupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + + auto initialData = supportedDevicesHelper.collectSupportedDevicesData(enabledDevices); + + std::string firstSerialization = supportedDevicesHelper.serialize("ocloc-test", initialData); + + auto deserializedData = supportedDevicesHelper.deserialize(firstSerialization); + ASSERT_EQ(deserializedData.size(), 1u); + ASSERT_TRUE(deserializedData.find("ocloc-test") != deserializedData.end()); + + std::string secondSerialization = supportedDevicesHelper.serialize("ocloc-test", deserializedData["ocloc-test"]); + + EXPECT_EQ(firstSerialization, secondSerialization); + + auto secondDeserializationData = supportedDevicesHelper.deserialize(secondSerialization); + ASSERT_EQ(secondDeserializationData.size(), 1u); + ASSERT_TRUE(secondDeserializationData.find("ocloc-test") != secondDeserializationData.end()); + + const auto &finalData = secondDeserializationData["ocloc-test"]; + + EXPECT_EQ(initialData.deviceIpVersions, finalData.deviceIpVersions); + + ASSERT_EQ(initialData.deviceInfos.size(), finalData.deviceInfos.size()); + for (size_t i = 0; i < initialData.deviceInfos.size(); ++i) { + EXPECT_EQ(initialData.deviceInfos[i].deviceId, finalData.deviceInfos[i].deviceId); + EXPECT_EQ(initialData.deviceInfos[i].revisionId, finalData.deviceInfos[i].revisionId); + EXPECT_EQ(initialData.deviceInfos[i].ipVersion, finalData.deviceInfos[i].ipVersion); + } + + ASSERT_EQ(initialData.acronyms.size(), finalData.acronyms.size()); + for (size_t i = 0; i < initialData.acronyms.size(); ++i) { + EXPECT_EQ(initialData.acronyms[i].first, finalData.acronyms[i].first); + EXPECT_EQ(initialData.acronyms[i].second, finalData.acronyms[i].second); + } + + ASSERT_EQ(initialData.familyGroups.size(), finalData.familyGroups.size()); + for (size_t i = 0; i < initialData.familyGroups.size(); ++i) { + EXPECT_EQ(initialData.familyGroups[i].first, finalData.familyGroups[i].first); + EXPECT_EQ(initialData.familyGroups[i].second, finalData.familyGroups[i].second); + } + + ASSERT_EQ(initialData.releaseGroups.size(), finalData.releaseGroups.size()); + for (size_t i = 0; i < initialData.releaseGroups.size(); ++i) { + EXPECT_EQ(initialData.releaseGroups[i].first, finalData.releaseGroups[i].first); + EXPECT_EQ(initialData.releaseGroups[i].second, finalData.releaseGroups[i].second); + } +} + +TEST_F(SupportedDevicesHelperTest, WhenMergingOclocVersionDataThenAllDataIsCombinedCorrectly) { + SupportedDevicesMode mode = SupportedDevicesMode::merge; + MockSupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + + std::map versionDataMap; + + SupportedDevicesHelper::SupportedDevicesData data1; + SupportedDevicesHelper::SupportedDevicesData data2; + + data1.deviceIpVersions = {0x1000001, 0x1000002}; + data2.deviceIpVersions = {0x1000001, 0x2000001}; + + data1.deviceInfos = {{0x1111, 1, 0x1000001}, {0x2222, 2, 0x1000002}}; + data2.deviceInfos = {{0x1111, 1, 0x1000001}, {0x3333, 3, 0x2000001}}; + + data1.acronyms = {{"aaa", 0x1000001}, {"bbb", 0x1000002}}; + data2.acronyms = {{"aaa", 0x1000001}, {"ccc", 0x2000001}}; + + data1.familyGroups = {{"FAMILY1", {0x1000001}}, {"FAMILY2", {0x1000002}}}; + data2.familyGroups = {{"FAMILY1", {0x1000001, 0x2000001}}, {"FAMILY3", {0x2000001}}}; + + data1.releaseGroups = {{"RELEASE1", {0x1000001}}, {"RELEASE2", {0x1000002}}}; + data2.releaseGroups = {{"RELEASE3", {0x1000001}}, {"RELEASE4", {0x2000001}}}; + + versionDataMap["ocloc-1.0"] = data1; + versionDataMap["ocloc-2.0"] = data2; + + auto mergedData = supportedDevicesHelper.mergeOclocVersionData(versionDataMap); + + ASSERT_EQ(mergedData.deviceIpVersions.size(), 3u); + EXPECT_TRUE(std::is_sorted(mergedData.deviceIpVersions.begin(), mergedData.deviceIpVersions.end())); + EXPECT_EQ(mergedData.deviceIpVersions, std::vector({0x1000001, 0x1000002, 0x2000001})); + + ASSERT_EQ(mergedData.deviceInfos.size(), 3u); + EXPECT_TRUE(std::is_sorted(mergedData.deviceInfos.begin(), mergedData.deviceInfos.end(), + [](const auto &a, const auto &b) { return a.ipVersion < b.ipVersion; })); + EXPECT_EQ(mergedData.deviceInfos[0].deviceId, 0x1111u); + EXPECT_EQ(mergedData.deviceInfos[0].revisionId, 1u); + EXPECT_EQ(mergedData.deviceInfos[0].ipVersion, 0x1000001u); + + EXPECT_EQ(mergedData.deviceInfos[1].deviceId, 0x2222u); + EXPECT_EQ(mergedData.deviceInfos[1].revisionId, 2u); + EXPECT_EQ(mergedData.deviceInfos[1].ipVersion, 0x1000002u); + + EXPECT_EQ(mergedData.deviceInfos[2].deviceId, 0x3333u); + EXPECT_EQ(mergedData.deviceInfos[2].revisionId, 3u); + EXPECT_EQ(mergedData.deviceInfos[2].ipVersion, 0x2000001u); + + ASSERT_EQ(mergedData.acronyms.size(), 3u); + EXPECT_TRUE(std::is_sorted(mergedData.acronyms.begin(), mergedData.acronyms.end(), + [](const auto &a, const auto &b) { return a.second < b.second; })); + EXPECT_EQ(mergedData.acronyms[0], (std::pair{"aaa", 0x1000001})); + EXPECT_EQ(mergedData.acronyms[1], (std::pair{"bbb", 0x1000002})); + EXPECT_EQ(mergedData.acronyms[2], (std::pair{"ccc", 0x2000001})); + + ASSERT_EQ(mergedData.familyGroups.size(), 3u); + EXPECT_TRUE(std::is_sorted(mergedData.familyGroups.begin(), mergedData.familyGroups.end(), + [](const auto &a, const auto &b) { return a.first < b.first; })); + EXPECT_EQ(mergedData.familyGroups[0].first, "FAMILY1"); + EXPECT_EQ(mergedData.familyGroups[0].second, std::vector({0x1000001, 0x2000001})); + EXPECT_EQ(mergedData.familyGroups[1].first, "FAMILY2"); + EXPECT_EQ(mergedData.familyGroups[1].second, std::vector({0x1000002})); + EXPECT_EQ(mergedData.familyGroups[2].first, "FAMILY3"); + EXPECT_EQ(mergedData.familyGroups[2].second, std::vector({0x2000001})); + + ASSERT_EQ(mergedData.releaseGroups.size(), 4u); + EXPECT_TRUE(std::is_sorted(mergedData.releaseGroups.begin(), mergedData.releaseGroups.end(), + [](const auto &a, const auto &b) { return a.first < b.first; })); + EXPECT_EQ(mergedData.releaseGroups[0].first, "RELEASE1"); + EXPECT_EQ(mergedData.releaseGroups[0].second, std::vector({0x1000001})); + EXPECT_EQ(mergedData.releaseGroups[1].first, "RELEASE2"); + EXPECT_EQ(mergedData.releaseGroups[1].second, std::vector({0x1000002})); + EXPECT_EQ(mergedData.releaseGroups[2].first, "RELEASE3"); + EXPECT_EQ(mergedData.releaseGroups[2].second, std::vector({0x1000001})); + EXPECT_EQ(mergedData.releaseGroups[3].first, "RELEASE4"); + EXPECT_EQ(mergedData.releaseGroups[3].second, std::vector({0x2000001})); +} + +TEST_F(SupportedDevicesHelperTest, WhenConcatAndSerializeWithFormerVersionDataThenResultIsCorrect) { + SupportedDevicesMode mode = SupportedDevicesMode::concat; + MockSupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + + auto currentVersionData = supportedDevicesHelper.collectSupportedDevicesData(enabledDevices); + + std::string concatResult = supportedDevicesHelper.concatAndSerializeWithFormerVersionData(currentVersionData); + + auto family1 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[0].family); + auto family2 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[1].family); + auto release1 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[0].release); + auto release2 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[1].release); + + char expectedYaml[2048]; + snprintf(expectedYaml, sizeof(expectedYaml), + R"(ocloc-current: + device_ip_versions: + - 0x1000001 + - 0x2000002 + ip_to_dev_rev_id: + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1111 + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1100 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2222 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2200 + acronym: + aaa: 0x1000001 + bbb: 0x1000001 + ccc: 0x2000002 + ddd: 0x2000002 + family_groups: + %s: [0x1000001] + %s: [0x2000002] + release_groups: + %s: [0x1000001] + %s: [0x2000002] + +ocloc-former: + device_ip_versions: + - 0x3000001 + - 0x3000002 + ip_to_dev_rev_id: + - ip: 0x3000001 + revision_id: 1 + device_id: 0x3333 + - ip: 0x3000002 + revision_id: 2 + device_id: 0x4444 + acronym: + eee: 0x3000001 + fff: 0x3000002 + family_groups: + FAMILY_FORMER: [0x3000001, 0x3000002] + release_groups: + RELEASE_FORMER: [0x3000001, 0x3000002] +)", + family1.data(), family2.data(), release1.data(), release2.data()); + + EXPECT_EQ(concatResult, expectedYaml); +} + +TEST_F(SupportedDevicesHelperTest, GivenEmptyFormerVersionDataWhenConcatAndSerializeWithFormerVersionDataThenResultIsCorrect) { + SupportedDevicesMode mode = SupportedDevicesMode::concat; + MockSupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + supportedDevicesHelper.getDataFromFormerOclocVersionEmptyResult = true; + + auto currentVersionData = supportedDevicesHelper.collectSupportedDevicesData(enabledDevices); + + std::string concatResult = supportedDevicesHelper.concatAndSerializeWithFormerVersionData(currentVersionData); + + auto family1 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[0].family); + auto family2 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[1].family); + auto release1 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[0].release); + auto release2 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[1].release); + + char expectedYaml[2048]; + snprintf(expectedYaml, sizeof(expectedYaml), + R"(ocloc-current: + device_ip_versions: + - 0x1000001 + - 0x2000002 + ip_to_dev_rev_id: + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1111 + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1100 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2222 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2200 + acronym: + aaa: 0x1000001 + bbb: 0x1000001 + ccc: 0x2000002 + ddd: 0x2000002 + family_groups: + %s: [0x1000001] + %s: [0x2000002] + release_groups: + %s: [0x1000001] + %s: [0x2000002] +)", + family1.data(), family2.data(), release1.data(), release2.data()); + + EXPECT_EQ(concatResult, expectedYaml); +} + +TEST_F(SupportedDevicesHelperTest, WhenMergeAndSerializeWithFormerVersionDataThenBothVersionsAreCorrectlyMerged) { + SupportedDevicesMode mode = SupportedDevicesMode::merge; + MockSupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + supportedDevicesHelper.getDataFromFormerOclocVersionEmptyResult = false; + + auto currentVersionData = supportedDevicesHelper.collectSupportedDevicesData(enabledDevices); + std::string mergeResult = supportedDevicesHelper.mergeAndSerializeWithFormerVersionData(currentVersionData); + + auto deserializedResult = supportedDevicesHelper.deserialize(mergeResult); + ASSERT_EQ(deserializedResult.size(), 1u); + ASSERT_TRUE(deserializedResult.find("ocloc") != deserializedResult.end()); + const auto &mergedData = deserializedResult["ocloc"]; + + std::vector expectedIpVersions = {0x1000001, 0x2000002, 0x3000001, 0x3000002}; + EXPECT_EQ(mergedData.deviceIpVersions.size(), expectedIpVersions.size()); + for (const auto &ipVersion : expectedIpVersions) { + EXPECT_NE(std::find(mergedData.deviceIpVersions.begin(), mergedData.deviceIpVersions.end(), ipVersion), + mergedData.deviceIpVersions.end()); + } + + std::vector expectedDeviceInfos = { + {0x1111, 1, 0x1000001}, + {0x1100, 1, 0x1000001}, + {0x2222, 2, 0x2000002}, + {0x2200, 2, 0x2000002}, + {0x3333, 1, 0x3000001}, + {0x4444, 2, 0x3000002}}; + EXPECT_EQ(mergedData.deviceInfos.size(), expectedDeviceInfos.size()); + for (const auto &info : expectedDeviceInfos) { + auto it = std::find_if(mergedData.deviceInfos.begin(), mergedData.deviceInfos.end(), + [&](const SupportedDevicesHelper::DeviceInfo &di) { + return di.deviceId == info.deviceId && di.revisionId == info.revisionId && di.ipVersion == info.ipVersion; + }); + EXPECT_NE(it, mergedData.deviceInfos.end()); + } + + std::vector> expectedAcronyms = { + {"aaa", 0x1000001}, {"bbb", 0x1000001}, {"ccc", 0x2000002}, {"ddd", 0x2000002}, {"eee", 0x3000001}, {"fff", 0x3000002}}; + EXPECT_EQ(mergedData.acronyms.size(), expectedAcronyms.size()); + for (const auto &acronym : expectedAcronyms) { + auto it = std::find(mergedData.acronyms.begin(), mergedData.acronyms.end(), acronym); + EXPECT_NE(it, mergedData.acronyms.end()); + } + + auto family1 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[0].family); + auto family2 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[1].family); + std::vector>> expectedFamilyGroups = { + {family1.data(), {0x1000001}}, + {family2.data(), {0x2000002}}, + {"FAMILY_FORMER", {0x3000001, 0x3000002}}}; + EXPECT_EQ(mergedData.familyGroups.size(), expectedFamilyGroups.size()); + for (const auto &group : expectedFamilyGroups) { + auto it = std::find_if(mergedData.familyGroups.begin(), mergedData.familyGroups.end(), + [&](const auto &fg) { return fg.first == group.first; }); + EXPECT_NE(it, mergedData.familyGroups.end()); + if (it != mergedData.familyGroups.end()) { + EXPECT_EQ(it->second, group.second); + } + } + + auto release1 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[0].release); + auto release2 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[1].release); + std::vector>> expectedReleaseGroups = { + {release1.data(), {0x1000001}}, + {release2.data(), {0x2000002}}, + {"RELEASE_FORMER", {0x3000001, 0x3000002}}}; + EXPECT_EQ(mergedData.releaseGroups.size(), expectedReleaseGroups.size()); + for (const auto &group : expectedReleaseGroups) { + auto it = std::find_if(mergedData.releaseGroups.begin(), mergedData.releaseGroups.end(), + [&](const auto &rg) { return rg.first == group.first; }); + EXPECT_NE(it, mergedData.releaseGroups.end()); + if (it != mergedData.releaseGroups.end()) { + EXPECT_EQ(it->second, group.second); + } + } +} + +TEST_F(SupportedDevicesHelperTest, GivenEmptyFormerVersionDataWhenMergeAndSerializeWithFormerVersionDataThenOnlyCurrentVersionIsPresent) { + SupportedDevicesMode mode = SupportedDevicesMode::merge; + MockSupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + supportedDevicesHelper.getDataFromFormerOclocVersionEmptyResult = true; + + auto currentVersionData = supportedDevicesHelper.collectSupportedDevicesData(enabledDevices); + std::string mergeResult = supportedDevicesHelper.mergeAndSerializeWithFormerVersionData(currentVersionData); + + auto family1 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[0].family); + auto family2 = argHelper->productConfigHelper->getAcronymFromAFamily(mockDevices[1].family); + auto release1 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[0].release); + auto release2 = argHelper->productConfigHelper->getAcronymFromARelease(mockDevices[1].release); + + char expectedYaml[2048]; + snprintf(expectedYaml, sizeof(expectedYaml), + R"(ocloc-current: + device_ip_versions: + - 0x1000001 + - 0x2000002 + ip_to_dev_rev_id: + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1111 + - ip: 0x1000001 + revision_id: 1 + device_id: 0x1100 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2222 + - ip: 0x2000002 + revision_id: 2 + device_id: 0x2200 + acronym: + aaa: 0x1000001 + bbb: 0x1000001 + ccc: 0x2000002 + ddd: 0x2000002 + family_groups: + %s: [0x1000001] + %s: [0x2000002] + release_groups: + %s: [0x1000001] + %s: [0x2000002] +)", + family1.data(), family2.data(), release1.data(), release2.data()); + + EXPECT_EQ(mergeResult, expectedYaml); +} + +TEST_F(SupportedDevicesHelperTest, GivenSupportedDevicesModeWhenCallingToStrThenCorrectStringIsReturned) { + EXPECT_EQ("merge", toStr(SupportedDevicesMode::merge)); + EXPECT_EQ("concat", toStr(SupportedDevicesMode::concat)); + EXPECT_EQ("unknown", toStr(SupportedDevicesMode::unknown)); +} + +TEST_F(SupportedDevicesHelperTest, GivenInvalidYamlInputWhenDeserializeThenReturnEmptyData) { + DebugManagerStateRestore dbgRestore; + debugManager.flags.EnableDebugBreak.set(0); + + SupportedDevicesMode mode = SupportedDevicesMode::merge; + SupportedDevicesHelper supportedDevicesHelper(mode, argHelper->productConfigHelper.get()); + + ConstStringRef yaml = + R"===( + device_ip_versions: + - 0x1000001 + - 0x2000002 + - 0x2000002 +)==="; + + auto ret = supportedDevicesHelper.deserialize(yaml.str()); + EXPECT_TRUE(ret.empty()); +} + +TEST_F(SupportedDevicesHelperTest, GivenYamlWithInvalidValuesThenReturnDataWithEmptySections) { + SupportedDevicesHelper helper(SupportedDevicesMode::concat, nullptr); + + std::string incompleteYaml = R"( +ocloc-test: + device_ip_versions: + - not_a_number + ip_to_dev_rev_id: + - ip: 0x1000001 + revision_id: 1 + - ip: 0x1000001 + device_id: 0x1111 + - deviceId: 0x2222 + revisionId: 2 + acronym: + aaa: not_a_number + family_groups: + FAMILY1: + - not_a_number + release_groups: + RELEASE1: + - not_a_number +)"; + + auto result = helper.deserialize(incompleteYaml); + + ASSERT_EQ(result.size(), 1u); + ASSERT_TRUE(result.find("ocloc-test") != result.end()); + const auto &data = result["ocloc-test"]; + + EXPECT_TRUE(data.deviceIpVersions.empty()); + EXPECT_TRUE(data.deviceInfos.empty()); + EXPECT_TRUE(data.acronyms.empty()); + EXPECT_TRUE(data.familyGroups.empty()); + EXPECT_TRUE(data.releaseGroups.empty()); +} + +TEST_F(SupportedDevicesHelperTest, GivenYamlWithMissingSectionsWhenDeserializeThenReturnDataWithEmptySections) { + SupportedDevicesHelper helper(SupportedDevicesMode::concat, nullptr); + + std::string missingYaml = R"( +ocloc-test: +)"; + + auto result = helper.deserialize(missingYaml); + + ASSERT_EQ(result.size(), 1u); + ASSERT_TRUE(result.find("ocloc-test") != result.end()); + const auto &data = result["ocloc-test"]; + + EXPECT_TRUE(data.deviceIpVersions.empty()); + EXPECT_TRUE(data.deviceInfos.empty()); + EXPECT_TRUE(data.acronyms.empty()); + EXPECT_TRUE(data.familyGroups.empty()); + EXPECT_TRUE(data.releaseGroups.empty()); +} + +} // namespace NEO 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 97aabb70ae..19d719e036 100644 --- a/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp +++ b/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp @@ -9,6 +9,7 @@ #include "shared/offline_compiler/source/ocloc_api.h" #include "shared/offline_compiler/source/ocloc_fatbinary.h" +#include "shared/offline_compiler/source/ocloc_supported_devices_helper.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" @@ -1027,6 +1028,31 @@ TEST_F(OfflineCompilerTests, givenProductAcronymWhenIdsCommandIsInvokeThenSucces } } +TEST_F(OfflineCompilerTests, WhenQueryingSupportedDevicesThenNonEmptyOutputFileIsGenerated) { + std::vector modes = {Ocloc::SupportedDevicesMode::concat, Ocloc::SupportedDevicesMode::merge}; + + for (const auto &mode : modes) { + std::vector argv = { + "ocloc", + "query", + "SUPPORTED_DEVICES", + "-" + toStr(mode)}; + + int retVal = OfflineCompiler::query(argv.size(), argv, oclocArgHelperWithoutInput.get()); + EXPECT_EQ(OCLOC_SUCCESS, retVal); + + Ocloc::SupportedDevicesHelper supportedDevicesHelper(mode, oclocArgHelperWithoutInput->productConfigHelper.get()); + std::string expectedFileName = supportedDevicesHelper.getOclocCurrentVersionOutputFilename(); + + EXPECT_NE(oclocArgHelperWithoutInput->filesMap.find(expectedFileName), oclocArgHelperWithoutInput->filesMap.end()); + + std::string generatedContent = oclocArgHelperWithoutInput->filesMap[expectedFileName]; + EXPECT_FALSE(generatedContent.empty()); + + 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"}; diff --git a/opencl/test/unit_test/offline_compiler/windows/ocloc_supported_devices_helper_windows_tests.cpp b/opencl/test/unit_test/offline_compiler/windows/ocloc_supported_devices_helper_windows_tests.cpp new file mode 100644 index 0000000000..c84090940c --- /dev/null +++ b/opencl/test/unit_test/offline_compiler/windows/ocloc_supported_devices_helper_windows_tests.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/offline_compiler/source/ocloc_supported_devices_helper.h" + +#include "opencl/test/unit_test/offline_compiler/mock/mock_ocloc_supported_devices_helper.h" + +#include "gtest/gtest.h" + +namespace NEO { + +struct SupportedDevicesHelperWindowsTest : public ::testing::Test { + void SetUp() override { + mockHelper.getOclocCurrentLibNameMockResult = ""; + mockHelper.getOclocFormerLibNameMockResult = ""; + mockHelper.getOclocCurrentVersionMockResult = ""; + } + + void TearDown() override { + } + + MockSupportedDevicesHelper mockHelper = MockSupportedDevicesHelper(SupportedDevicesMode::concat, nullptr); +}; + +TEST_F(SupportedDevicesHelperWindowsTest, GivenVariousOclocLibraryNamesWhenExtractingOclocVersionThenEmptyStringIsReturned) { + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc-2.0.1.so"), ""); + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc-2.0.so"), ""); + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc2.0.so"), ""); + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc-2.0"), ""); + EXPECT_EQ(mockHelper.extractOclocVersion("libocloc.so"), ""); +} + +TEST_F(SupportedDevicesHelperWindowsTest, GivenSupportedDevicesHelperWhenGetOclocCurrentLibNameThenReturnEmptyString) { + EXPECT_EQ("", mockHelper.getOclocCurrentLibName()); +} + +TEST_F(SupportedDevicesHelperWindowsTest, GivenSupportedDevicesHelperWhenGetOclocFormerLibNameThenReturnEmptyString) { + EXPECT_EQ("", mockHelper.getOclocFormerLibName()); +} + +TEST_F(SupportedDevicesHelperWindowsTest, GivenSupportedDevicesHelperWhenGetOclocCurrentVersionThenReturnCorrectValue) { + EXPECT_EQ("ocloc", mockHelper.getOclocCurrentVersion()); +} + +TEST_F(SupportedDevicesHelperWindowsTest, GivenSupportedDevicesHelperWhenGetOclocFormerVersionThenReturnCorrectValue) { + EXPECT_EQ("", mockHelper.getOclocFormerVersion()); +} + +TEST_F(SupportedDevicesHelperWindowsTest, GivenSupportedDevicesHelperWhenGetDataFromFormerOclocVersionThenReturnEmptyData) { + SupportedDevicesHelper helper(SupportedDevicesMode::concat, nullptr); + EXPECT_EQ("", helper.getDataFromFormerOclocVersion()); +} + +} // namespace NEO diff --git a/shared/offline_compiler/source/CMakeLists.txt b/shared/offline_compiler/source/CMakeLists.txt index 0a66110bcc..39af3af46c 100644 --- a/shared/offline_compiler/source/CMakeLists.txt +++ b/shared/offline_compiler/source/CMakeLists.txt @@ -111,6 +111,8 @@ set(CLOC_LIB_SRCS_LIB ${OCLOC_DIRECTORY}/source/ocloc_igc_facade.h ${OCLOC_DIRECTORY}/source/ocloc_interface.cpp ${OCLOC_DIRECTORY}/source/ocloc_interface.h + ${OCLOC_DIRECTORY}/source/ocloc_supported_devices_helper.cpp + ${OCLOC_DIRECTORY}/source/ocloc_supported_devices_helper.h ${OCLOC_DIRECTORY}/source/ocloc_validator.cpp ${OCLOC_DIRECTORY}/source/ocloc_validator.h ${OCLOC_DIRECTORY}/source/offline_compiler.cpp @@ -147,6 +149,7 @@ if(WIN32) ${NEO_SHARED_DIRECTORY}/os_interface/windows/os_library_win.h ${NEO_SHARED_DIRECTORY}/os_interface/windows/sys_calls.cpp ${NEO_SHARED_DIRECTORY}/utilities/windows/directory.cpp + ${OCLOC_DIRECTORY}/source/windows/ocloc_supported_devices_helper_windows.cpp ) else() list(APPEND CLOC_LIB_SRCS_LIB @@ -160,6 +163,7 @@ else() ${NEO_SHARED_DIRECTORY}/os_interface/linux/sys_calls_linux.cpp ${NEO_SHARED_DIRECTORY}/utilities/linux/directory.cpp ${OCLOC_DIRECTORY}/source/linux/os_library_ocloc_helper.cpp + ${OCLOC_DIRECTORY}/source/linux/ocloc_supported_devices_helper_linux.cpp ) endif() @@ -454,6 +458,9 @@ endif() set_target_properties(${OCLOC_NAME} PROPERTIES OUTPUT_NAME ${OCLOC_NAME}${OCLOC_OUTPUT_NAME_SUFFIX}) set_target_properties(${OCLOC_NAME}_lib PROPERTIES OUTPUT_NAME ${OCLOC_NAME}${LIBOCLOC_OUTPUT_NAME_SUFFIX}) +add_definitions(-DNEO_OCLOC_CURRENT_LIB_NAME="${NEO_OCLOC_CURRENT_LIB_NAME}") +add_definitions(-DNEO_OCLOC_FORMER_LIB_NAME="${NEO_OCLOC_FORMER_LIB_NAME}") + add_custom_target(copy_compiler_files DEPENDS ${NEO__IGC_TARGETS}) set_target_properties(copy_compiler_files PROPERTIES FOLDER ${OCLOC_FOLDER_NAME}) diff --git a/shared/offline_compiler/source/linux/ocloc_supported_devices_helper_linux.cpp b/shared/offline_compiler/source/linux/ocloc_supported_devices_helper_linux.cpp new file mode 100644 index 0000000000..c5ca814385 --- /dev/null +++ b/shared/offline_compiler/source/linux/ocloc_supported_devices_helper_linux.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/offline_compiler/source/ocloc_api.h" +#include "shared/offline_compiler/source/ocloc_supported_devices_helper.h" +#include "shared/source/os_interface/os_library.h" + +#include +#include + +namespace Ocloc { +using namespace NEO; + +std::string SupportedDevicesHelper::getOutputFilenameSuffix(SupportedDevicesMode mode) const { + return "_supported_devices_" + toStr(mode) + fileExtension.data(); +} + +std::string SupportedDevicesHelper::getOclocCurrentVersionOutputFilename() const { + return getOclocCurrentVersion() + getOutputFilenameSuffix(mode); +} + +std::string SupportedDevicesHelper::getOclocCurrentLibName() const { +#ifdef NEO_OCLOC_CURRENT_LIB_NAME + return std::string(NEO_OCLOC_CURRENT_LIB_NAME); +#else + return ""; +#endif +} + +std::string SupportedDevicesHelper::getOclocFormerLibName() const { +#ifdef NEO_OCLOC_FORMER_LIB_NAME + return std::string(NEO_OCLOC_FORMER_LIB_NAME); +#else + return ""; +#endif +} + +std::string SupportedDevicesHelper::getOclocCurrentVersion() const { + return extractOclocVersion(getOclocCurrentLibName()); +} + +std::string SupportedDevicesHelper::getOclocFormerVersion() const { + return extractOclocVersion(getOclocFormerLibName()); +} + +std::string SupportedDevicesHelper::extractOclocVersion(std::string_view oclocLibNameWithVersion) const { + // libocloc-2.0.so -> ocloc-2.0 + std::string_view view(oclocLibNameWithVersion); + auto start = view.find("ocloc-"); + if (start == std::string_view::npos) { + return "ocloc"; + } + + auto end = view.find(".so", start); + if (end == std::string_view::npos) { + return "ocloc"; + } + + return std::string(view.substr(start, end - start)); +} + +std::string SupportedDevicesHelper::getDataFromFormerOclocVersion() const { + if (getOclocFormerLibName().empty() || + getOclocFormerLibName() == getOclocCurrentLibName()) { + return ""; + } + + std::unique_ptr oclocLib(OsLibrary::load(getOclocFormerLibName())); + + if (!oclocLib || + !oclocLib->isLoaded()) { + return ""; + } + + std::string retData; + + auto oclocInvokeFunc = reinterpret_cast(oclocLib->getProcAddress("oclocInvoke")); + + const char *argv[] = {"ocloc", "query", "SUPPORTED_DEVICES", "-concat"}; + + unsigned int numArgs = sizeof(argv) / sizeof(argv[0]); + uint32_t numOutputs = 0u; + unsigned char **dataOutputs = nullptr; + size_t *ouputLengths = nullptr; + char **outputNames = nullptr; + + oclocInvokeFunc(numArgs, argv, + 0, + nullptr, + nullptr, + nullptr, + 0, + nullptr, + nullptr, + nullptr, + &numOutputs, + &dataOutputs, + &ouputLengths, + &outputNames); + + const std::string expectedSubstr = getOutputFilenameSuffix(SupportedDevicesMode::concat); + + for (unsigned int i = 0; i < numOutputs; ++i) { + if (std::strstr(outputNames[i], expectedSubstr.c_str()) == nullptr) { + continue; + } + retData = std::string(reinterpret_cast(dataOutputs[i]), ouputLengths[i]); + break; + } + + oclocFreeOutput(&numOutputs, &dataOutputs, &ouputLengths, &outputNames); + return retData; +} + +} // namespace Ocloc \ No newline at end of file diff --git a/shared/offline_compiler/source/ocloc_api.h b/shared/offline_compiler/source/ocloc_api.h index c77e173380..f440ece08f 100644 --- a/shared/offline_compiler/source/ocloc_api.h +++ b/shared/offline_compiler/source/ocloc_api.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2023 Intel Corporation + * Copyright (C) 2020-2024 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -13,6 +13,12 @@ #include +typedef int (*pOclocInvoke)( + unsigned int numArgs, const char *argv[], + const uint32_t numSources, const uint8_t **dataSources, const uint64_t *lenSources, const char **nameSources, + const uint32_t numInputHeaders, const uint8_t **dataInputHeaders, const uint64_t *lenInputHeaders, const char **nameInputHeaders, + uint32_t *numOutputs, uint8_t ***dataOutputs, uint64_t **lenOutputs, char ***nameOutputs); + #ifndef OCLOC_MAKE_VERSION /// Generates ocloc API versions #define OCLOC_MAKE_VERSION(_major, _minor) ((_major << 16) | (_minor & 0x0000ffff)) diff --git a/shared/offline_compiler/source/ocloc_supported_devices_helper.cpp b/shared/offline_compiler/source/ocloc_supported_devices_helper.cpp new file mode 100644 index 0000000000..d5536f2f61 --- /dev/null +++ b/shared/offline_compiler/source/ocloc_supported_devices_helper.cpp @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/offline_compiler/source/ocloc_supported_devices_helper.h" + +#include "shared/offline_compiler/source/ocloc_api.h" +#include "shared/source/device_binary_format/yaml/yaml_parser.h" +#include "shared/source/helpers/product_config_helper.h" +#include "shared/source/os_interface/os_library.h" + +#include +#include +#include +#include +#include + +namespace Ocloc { +using namespace NEO; + +SupportedDevicesHelper::SupportedDevicesData SupportedDevicesHelper::collectSupportedDevicesData( + const std::vector &enabledDevices) const { + + SupportedDevicesData data; + + // Populate IP Versions, Device Infos, Acronyms + for (const auto &device : enabledDevices) { + data.deviceIpVersions.push_back(device.aotConfig.value); + + for (const auto &deviceId : *device.deviceIds) { + data.deviceInfos.push_back({deviceId, device.aotConfig.revision, device.aotConfig.value}); + } + + for (const auto &acronym : device.deviceAcronyms) { + data.acronyms.push_back({acronym.data(), device.aotConfig.value}); + } + } + + // Populate Family groups + std::map> groupedDevices; + for (const auto &device : enabledDevices) { + groupedDevices[device.family].push_back(device.aotConfig.value); + } + for (const auto &entry : groupedDevices) { + data.familyGroups.push_back({productConfigHelper->getAcronymFromAFamily(entry.first).data(), entry.second}); + } + + // Populate Release groups + std::map> groupedReleases; + for (const auto &device : enabledDevices) { + groupedReleases[device.release].push_back(device.aotConfig.value); + } + for (const auto &entry : groupedReleases) { + auto name = productConfigHelper->getAcronymFromARelease(entry.first); + if (!name.empty()) { + data.releaseGroups.push_back({name.data(), entry.second}); + } + } + + return data; +} + +std::string SupportedDevicesHelper::serialize(std::string_view oclocVersion, const SupportedDevicesData &data) const { + std::ostringstream oss; + oss << oclocVersion << ":\n"; + + // DeviceIpVersions + oss << " " << SupportedDevicesYamlConstants::deviceIpVersions << ":\n"; + for (const auto &ipVersion : data.deviceIpVersions) { + oss << " - 0x" << std::hex << ipVersion << "\n"; + } + + // IpToDevRevId + oss << " " << SupportedDevicesYamlConstants::ipToDevRevId << ":\n"; + for (const auto &device : data.deviceInfos) { + oss << " - " << SupportedDevicesYamlConstants::ip << ": 0x" << std::hex << device.ipVersion << "\n"; + oss << " " << SupportedDevicesYamlConstants::revisionId << ": " << std::dec << device.revisionId << "\n"; + oss << " " << SupportedDevicesYamlConstants::deviceId << ": 0x" << std::hex << device.deviceId << "\n"; + } + + // Acronym + oss << " " << SupportedDevicesYamlConstants::acronym << ":\n"; + for (const auto &[acronym, ipVersion] : data.acronyms) { + oss << " " << acronym << ": 0x" << std::hex << ipVersion << "\n"; + } + + // FamilyGroups + oss << " " << SupportedDevicesYamlConstants::familyGroups << ":\n"; + for (const auto &[family, ipVersions] : data.familyGroups) { + oss << " " << family << ": ["; + for (size_t i = 0; i < ipVersions.size(); ++i) { + oss << "0x" << std::hex << ipVersions[i]; + if (i < ipVersions.size() - 1) + oss << ", "; + } + oss << "]\n"; + } + + // ReleaseGroups + oss << " " << SupportedDevicesYamlConstants::releaseGroups << ":\n"; + for (const auto &[release, ipVersions] : data.releaseGroups) { + oss << " " << release << ": ["; + for (size_t i = 0; i < ipVersions.size(); ++i) { + oss << "0x" << std::hex << ipVersions[i]; + if (i < ipVersions.size() - 1) + oss << ", "; + } + oss << "]\n"; + } + + return oss.str(); +} + +std::map SupportedDevicesHelper::deserialize(std::string_view yamlString) const { + std::map result; + NEO::Yaml::YamlParser parser; + std::string errReason, warning; + + if (!parser.parse(yamlString.data(), errReason, warning)) { + DEBUG_BREAK_IF(true); + return result; + } + + const auto *root = parser.getRoot(); + for (const auto &oclocVersionNode : parser.createChildrenRange(*root)) { + std::string oclocVersion = parser.readKey(oclocVersionNode).str(); + SupportedDevicesData data; + + const auto *ipVersionsNode = parser.getChild(oclocVersionNode, SupportedDevicesYamlConstants::deviceIpVersions.data()); + if (ipVersionsNode) { + for (const auto &ipNode : parser.createChildrenRange(*ipVersionsNode)) { + uint32_t ipVersion; + if (parser.readValueChecked(ipNode, ipVersion)) { + data.deviceIpVersions.push_back(ipVersion); + } + } + } + + const auto *deviceIdsNode = parser.getChild(oclocVersionNode, SupportedDevicesYamlConstants::ipToDevRevId.data()); + if (deviceIdsNode) { + for (const auto &deviceNode : parser.createChildrenRange(*deviceIdsNode)) { + DeviceInfo info; + const auto *deviceIdNode = parser.getChild(deviceNode, SupportedDevicesYamlConstants::deviceId.data()); + const auto *revisionIdNode = parser.getChild(deviceNode, SupportedDevicesYamlConstants::revisionId.data()); + const auto *ipNode = parser.getChild(deviceNode, SupportedDevicesYamlConstants::ip.data()); + if (deviceIdNode && revisionIdNode && ipNode) { + parser.readValueChecked(*deviceIdNode, info.deviceId); + parser.readValueChecked(*revisionIdNode, info.revisionId); + parser.readValueChecked(*ipNode, info.ipVersion); + data.deviceInfos.push_back(info); + } + } + } + + const auto *acronymNode = parser.getChild(oclocVersionNode, SupportedDevicesYamlConstants::acronym.data()); + if (acronymNode) { + for (const auto &acrNode : parser.createChildrenRange(*acronymNode)) { + std::string acronym = parser.readKey(acrNode).str(); + uint32_t ipVersion; + if (parser.readValueChecked(acrNode, ipVersion)) { + data.acronyms.push_back({acronym, ipVersion}); + } + } + } + + const auto *familyGroupsNode = parser.getChild(oclocVersionNode, SupportedDevicesYamlConstants::familyGroups.data()); + if (familyGroupsNode) { + for (const auto &familyNode : parser.createChildrenRange(*familyGroupsNode)) { + std::string family = parser.readKey(familyNode).str(); + std::vector ipVersions; + for (const auto &ipVersionNode : parser.createChildrenRange(familyNode)) { + uint32_t ipVersion; + if (parser.readValueChecked(ipVersionNode, ipVersion)) { + ipVersions.push_back(ipVersion); + } + } + if (!ipVersions.empty()) { + data.familyGroups.push_back({family, ipVersions}); + } + } + } + + const auto *releaseGroupsNode = parser.getChild(oclocVersionNode, SupportedDevicesYamlConstants::releaseGroups.data()); + if (releaseGroupsNode) { + for (const auto &releaseNode : parser.createChildrenRange(*releaseGroupsNode)) { + std::string release = parser.readKey(releaseNode).str(); + std::vector ipVersions; + for (const auto &ipVersionNode : parser.createChildrenRange(releaseNode)) { + uint32_t ipVersion; + if (parser.readValueChecked(ipVersionNode, ipVersion)) { + ipVersions.push_back(ipVersion); + } + } + if (!ipVersions.empty()) { + data.releaseGroups.push_back({release, ipVersions}); + } + } + } + + result[oclocVersion] = data; + } + + return result; +} + +std::string SupportedDevicesHelper::mergeAndSerializeWithFormerVersionData(const SupportedDevicesData ¤tVersionData) const { + std::string formerVersionSupportedDevices = getDataFromFormerOclocVersion(); + + if (formerVersionSupportedDevices.empty()) { + return serialize(getOclocCurrentVersion(), currentVersionData); + } + + auto formerVerDeserialized = deserialize(formerVersionSupportedDevices); + formerVerDeserialized[getOclocCurrentVersion()] = currentVersionData; + + auto mergedData = mergeOclocVersionData(formerVerDeserialized); + return serialize("ocloc", mergedData); +} + +std::string SupportedDevicesHelper::concatAndSerializeWithFormerVersionData(const SupportedDevicesData ¤tVersionData) const { + std::string output = serialize(getOclocCurrentVersion(), currentVersionData); + std::string formerVersionSupportedDevices = getDataFromFormerOclocVersion(); + if (!formerVersionSupportedDevices.empty()) { + output += "\n" + formerVersionSupportedDevices; + } + return output; +} + +SupportedDevicesHelper::SupportedDevicesData SupportedDevicesHelper::mergeOclocVersionData(const std::map &versionDataMap) const { + struct DeviceInfoComparator { + bool operator()(const DeviceInfo &lhs, const DeviceInfo &rhs) const { + return std::tie(lhs.deviceId, lhs.revisionId, lhs.ipVersion) < + std::tie(rhs.deviceId, rhs.revisionId, rhs.ipVersion); + } + }; + + SupportedDevicesData mergedData; + std::set uniqueIpVersions; + std::set uniqueDeviceInfos; + std::set> uniqueAcronyms; + std::map> uniqueFamilyGroups; + std::map> uniqueReleaseGroups; + + for (const auto &[version, data] : versionDataMap) { + uniqueIpVersions.insert(data.deviceIpVersions.begin(), data.deviceIpVersions.end()); + for (const auto &deviceInfo : data.deviceInfos) { + uniqueDeviceInfos.insert(deviceInfo); + } + uniqueAcronyms.insert(data.acronyms.begin(), data.acronyms.end()); + for (const auto &[family, ipVersions] : data.familyGroups) { + uniqueFamilyGroups[family].insert(ipVersions.begin(), ipVersions.end()); + } + for (const auto &[release, ipVersions] : data.releaseGroups) { + uniqueReleaseGroups[release].insert(ipVersions.begin(), ipVersions.end()); + } + } + + // Sort DeviceIpVersions (ascending) + mergedData.deviceIpVersions = std::vector(uniqueIpVersions.begin(), uniqueIpVersions.end()); + std::sort(mergedData.deviceIpVersions.begin(), mergedData.deviceIpVersions.end()); + + // Sort IpToDevRevId (ascending by ipVersion) + mergedData.deviceInfos = std::vector(uniqueDeviceInfos.begin(), uniqueDeviceInfos.end()); + std::sort(mergedData.deviceInfos.begin(), mergedData.deviceInfos.end(), + [](const DeviceInfo &a, const DeviceInfo &b) { return a.ipVersion < b.ipVersion; }); + + // Sort Acronyms (ascending by ipVersion) + mergedData.acronyms = std::vector>(uniqueAcronyms.begin(), uniqueAcronyms.end()); + std::sort(mergedData.acronyms.begin(), mergedData.acronyms.end(), + [](const auto &a, const auto &b) { return a.second < b.second; }); + + // Sort FamilyGroups (alphabetically by group name) + for (const auto &[family, ipVersions] : uniqueFamilyGroups) { + mergedData.familyGroups.push_back({family, std::vector(ipVersions.begin(), ipVersions.end())}); + } + std::sort(mergedData.familyGroups.begin(), mergedData.familyGroups.end(), + [](const auto &a, const auto &b) { return a.first < b.first; }); + + // Sort ReleaseGroups (alphabetically by group name) + for (const auto &[release, ipVersions] : uniqueReleaseGroups) { + mergedData.releaseGroups.push_back({release, std::vector(ipVersions.begin(), ipVersions.end())}); + } + std::sort(mergedData.releaseGroups.begin(), mergedData.releaseGroups.end(), + [](const auto &a, const auto &b) { return a.first < b.first; }); + + // Sort IP versions within each FAMILY and RELEASE group + for (auto &[_, ipVersions] : mergedData.familyGroups) { + std::sort(ipVersions.begin(), ipVersions.end()); + } + for (auto &[_, ipVersions] : mergedData.releaseGroups) { + std::sort(ipVersions.begin(), ipVersions.end()); + } + + return mergedData; +} +} // namespace Ocloc \ No newline at end of file diff --git a/shared/offline_compiler/source/ocloc_supported_devices_helper.h b/shared/offline_compiler/source/ocloc_supported_devices_helper.h new file mode 100644 index 0000000000..aed8ce9584 --- /dev/null +++ b/shared/offline_compiler/source/ocloc_supported_devices_helper.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "shared/offline_compiler/source/ocloc_arg_helper.h" +#include "shared/source/helpers/product_config_helper.h" + +#include +#include +#include + +namespace Ocloc { + +namespace SupportedDevicesYamlConstants { +constexpr std::string_view deviceIpVersions = "device_ip_versions"; +constexpr std::string_view ipToDevRevId = "ip_to_dev_rev_id"; +constexpr std::string_view acronym = "acronym"; +constexpr std::string_view familyGroups = "family_groups"; +constexpr std::string_view releaseGroups = "release_groups"; + +// Fields in IpToDevRevId section +constexpr std::string_view ip = "ip"; +constexpr std::string_view revisionId = "revision_id"; +constexpr std::string_view deviceId = "device_id"; +} // namespace SupportedDevicesYamlConstants + +enum class SupportedDevicesMode { + merge, + concat, + unknown +}; + +class SupportedDevicesHelper { + public: + struct DeviceInfo { + uint32_t deviceId; + uint32_t revisionId; + uint32_t ipVersion; + }; + + struct SupportedDevicesData { + std::vector deviceIpVersions; + std::vector deviceInfos; + std::vector> acronyms; + std::vector>> familyGroups; + std::vector>> releaseGroups; + }; + + public: + SupportedDevicesHelper(SupportedDevicesMode mode, ProductConfigHelper *productConfigHelper) + : mode(mode), productConfigHelper(productConfigHelper) {} + + std::string getOclocCurrentVersionOutputFilename() const; + SupportedDevicesData collectSupportedDevicesData(const std::vector &enabledDevices) const; + + std::string serialize(std::string_view oclocVersion, const SupportedDevicesData &data) const; + std::map deserialize(std::string_view yamlString) const; + + std::string mergeAndSerializeWithFormerVersionData(const SupportedDevicesData ¤tVersionData) const; + std::string concatAndSerializeWithFormerVersionData(const SupportedDevicesData ¤tVersionData) const; + + MOCKABLE_VIRTUAL std::string getDataFromFormerOclocVersion() const; + + protected: + MOCKABLE_VIRTUAL std::string getOclocCurrentLibName() const; + MOCKABLE_VIRTUAL std::string getOclocFormerLibName() const; + MOCKABLE_VIRTUAL std::string getOclocCurrentVersion() const; + std::string getOclocFormerVersion() const; + std::string extractOclocVersion(std::string_view oclocLibNameWithVersion) const; + SupportedDevicesData mergeOclocVersionData(const std::map &versionDataMap) const; + std::string getOutputFilenameSuffix([[maybe_unused]] SupportedDevicesMode mode) const; + + private: + SupportedDevicesMode mode; + ProductConfigHelper *productConfigHelper; + static constexpr std::string_view fileExtension = ".yaml"; +}; + +inline SupportedDevicesMode parseSupportedDevicesMode(std::string_view modeStr) { + if (modeStr == "-merge") { + return SupportedDevicesMode::merge; + } else if (modeStr == "-concat") { + return SupportedDevicesMode::concat; + } else { + return SupportedDevicesMode::unknown; + } +} + +inline std::string toStr(SupportedDevicesMode mode) { + switch (mode) { + case SupportedDevicesMode::concat: + return "concat"; + case SupportedDevicesMode::merge: + return "merge"; + default: + return "unknown"; + } +} +} // namespace Ocloc \ No newline at end of file diff --git a/shared/offline_compiler/source/offline_compiler.cpp b/shared/offline_compiler/source/offline_compiler.cpp index 98e0f6c982..2a74759556 100644 --- a/shared/offline_compiler/source/offline_compiler.cpp +++ b/shared/offline_compiler/source/offline_compiler.cpp @@ -12,6 +12,7 @@ #include "shared/offline_compiler/source/ocloc_fatbinary.h" #include "shared/offline_compiler/source/ocloc_fcl_facade.h" #include "shared/offline_compiler/source/ocloc_igc_facade.h" +#include "shared/offline_compiler/source/ocloc_supported_devices_helper.h" #include "shared/offline_compiler/source/queries.h" #include "shared/offline_compiler/source/utilities/get_git_version_info.h" #include "shared/source/compiler_interface/compiler_options.h" @@ -273,6 +274,8 @@ int OfflineCompiler::query(size_t numArgs, const std::vector &allAr return OCLOC_INVALID_COMMAND_LINE; } + Ocloc::SupportedDevicesMode supportedDevicesMode = Ocloc::SupportedDevicesMode::concat; + std::vector targetProducts; std::vector queries; auto argIt = allArgs.begin() + 2; @@ -300,6 +303,15 @@ int OfflineCompiler::query(size_t numArgs, const std::vector &allAr queries.push_back(Queries::QueryType::oclDeviceOpenCLCAllVersions); } else if (Queries::queryOCLDeviceOpenCLCFeatures == *argIt) { queries.push_back(Queries::QueryType::oclDeviceOpenCLCFeatures); + } else if (Queries::querySupportedDevices == *argIt) { + queries.push_back(Queries::QueryType::supportedDevices); + if (argIt + 1 != allArgs.end()) { + auto newMode = Ocloc::parseSupportedDevicesMode(*(argIt + 1)); + if (newMode != Ocloc::SupportedDevicesMode::unknown) { + supportedDevicesMode = newMode; + ++argIt; + } + } } else if ("--help" == *argIt) { printQueryHelp(helper); return 0; @@ -371,6 +383,9 @@ int OfflineCompiler::query(size_t numArgs, const std::vector &allAr helper->saveOutput(Queries::queryOCLDeviceOpenCLCFeatures.str(), commonFeaturesVec.data(), commonFeaturesVec.size() * sizeof(NameVersionPair)); helper->printf("%s\n", commonFeaturesString.c_str()); } break; + case Queries::QueryType::supportedDevices: { + querySupportedDevices(supportedDevicesMode, helper); + } break; } } @@ -448,6 +463,25 @@ int OfflineCompiler::queryAcronymIds(size_t numArgs, const std::vectorproductConfigHelper->getDeviceAotInfo(); + + Ocloc::SupportedDevicesHelper supportedDevicesHelper(mode, helper->productConfigHelper.get()); + auto supportedDevicesData = supportedDevicesHelper.collectSupportedDevicesData(enabledDevices); + + std::string output; + + if (mode == Ocloc::SupportedDevicesMode::merge) { + output = supportedDevicesHelper.mergeAndSerializeWithFormerVersionData(supportedDevicesData); + } else { + output = supportedDevicesHelper.concatAndSerializeWithFormerVersionData(supportedDevicesData); + } + + helper->saveOutput(supportedDevicesHelper.getOclocCurrentVersionOutputFilename(), output.data(), output.size()); + + return 0; +} + struct OfflineCompiler::buildInfo { std::unique_ptr> fclOptions; std::unique_ptr> fclInternalOptions; diff --git a/shared/offline_compiler/source/offline_compiler.h b/shared/offline_compiler/source/offline_compiler.h index 0dee59d954..7ddbe148ac 100644 --- a/shared/offline_compiler/source/offline_compiler.h +++ b/shared/offline_compiler/source/offline_compiler.h @@ -21,6 +21,10 @@ class OclocArgHelper; +namespace Ocloc { +enum class SupportedDevicesMode; +}; + namespace NEO { class CompilerCache; @@ -47,6 +51,7 @@ class OfflineCompiler { static std::vector getOpenCLCFeatures(ConstStringRef product, OclocArgHelper *helper); static int query(size_t numArgs, const std::vector &allArgs, OclocArgHelper *helper); static int queryAcronymIds(size_t numArgs, const std::vector &allArgs, OclocArgHelper *helper); + static int querySupportedDevices(Ocloc::SupportedDevicesMode mode, OclocArgHelper *helper); static OfflineCompiler *create(size_t numArgs, const std::vector &allArgs, bool dumpFiles, int &retVal, OclocArgHelper *helper); @@ -74,6 +79,23 @@ Supported query options: CL_DEVICE_PROFILE ; OpenCL device profile supported by device_filter CL_DEVICE_OPENCL_C_ALL_VERSIONS ; OpenCL C versions supported by device_filter CL_DEVICE_OPENCL_C_FEATURES ; OpenCL C features supported by device_filter + SUPPORTED_DEVICES ; Generates a YAML file with information about supported devices + +SUPPORTED_DEVICES option: + Linux: + Description: Generates a YAML file containing information about supported devices + for the current and previous versions of ocloc. + Usage: ocloc query SUPPORTED_DEVICES [] + Supported Modes: + -merge - Combines supported devices from all ocloc versions into a single list (default if not specified) + -concat - Lists supported devices for each ocloc version separately + Output file: _supported_devices_.yaml + + Windows: + Description: Generates a YAML file containing information about supported devices + for the current version of ocloc. + Usage: ocloc query SUPPORTED_DEVICES + Output file: _supported_devices.yaml Examples: ocloc query OCL_DRIVER_VERSION diff --git a/shared/offline_compiler/source/queries.h b/shared/offline_compiler/source/queries.h index c5222097c8..b1ccab3d8c 100644 --- a/shared/offline_compiler/source/queries.h +++ b/shared/offline_compiler/source/queries.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 Intel Corporation + * Copyright (C) 2021-2024 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -21,7 +21,8 @@ enum class QueryType { oclDeviceExtensionsWithVersion, oclDeviceProfile, oclDeviceOpenCLCAllVersions, - oclDeviceOpenCLCFeatures + oclDeviceOpenCLCFeatures, + supportedDevices }; inline constexpr ConstStringRef queryNeoRevision = "NEO_REVISION"; @@ -32,5 +33,6 @@ inline constexpr ConstStringRef queryOCLDeviceExtensionsWithVersion = "CL_DEVICE inline constexpr ConstStringRef queryOCLDeviceProfile = "CL_DEVICE_PROFILE"; inline constexpr ConstStringRef queryOCLDeviceOpenCLCAllVersions = "CL_DEVICE_OPENCL_C_ALL_VERSIONS"; inline constexpr ConstStringRef queryOCLDeviceOpenCLCFeatures = "CL_DEVICE_OPENCL_C_FEATURES"; +inline constexpr ConstStringRef querySupportedDevices = "SUPPORTED_DEVICES"; }; // namespace Queries } // namespace NEO diff --git a/shared/offline_compiler/source/windows/ocloc_supported_devices_helper_windows.cpp b/shared/offline_compiler/source/windows/ocloc_supported_devices_helper_windows.cpp new file mode 100644 index 0000000000..f555ceb3cc --- /dev/null +++ b/shared/offline_compiler/source/windows/ocloc_supported_devices_helper_windows.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/offline_compiler/source/ocloc_supported_devices_helper.h" +#include "shared/source/helpers/product_config_helper.h" + +#include + +namespace Ocloc { +using namespace NEO; + +std::string SupportedDevicesHelper::getOutputFilenameSuffix(SupportedDevicesMode mode) const { + return std::string("_supported_devices") + fileExtension.data(); +} + +std::string SupportedDevicesHelper::getOclocCurrentVersionOutputFilename() const { + return getOclocCurrentVersion() + getOutputFilenameSuffix(SupportedDevicesMode::unknown); +} + +std::string SupportedDevicesHelper::getOclocCurrentLibName() const { + return ""; +} + +std::string SupportedDevicesHelper::getOclocFormerLibName() const { + return ""; +} + +std::string SupportedDevicesHelper::getOclocCurrentVersion() const { + return "ocloc"; +} + +std::string SupportedDevicesHelper::getOclocFormerVersion() const { + return ""; +} + +std::string SupportedDevicesHelper::extractOclocVersion(std::string_view oclocLibNameWithVersion) const { + return ""; +} + +std::string SupportedDevicesHelper::getDataFromFormerOclocVersion() const { + return ""; +} +} // namespace Ocloc \ No newline at end of file