From f5d00b26165d7e3f6294408d3c1498d010c72094 Mon Sep 17 00:00:00 2001 From: Jack Myers Date: Fri, 19 Jul 2024 21:32:41 +0000 Subject: [PATCH] feature: 2d-block-load-transpose query Implemented device property query API for determining support capabilities regarding 2d-block-load-tranpose features for which not all Intel devices support. Related-To: NEO-11592 Signed-off-by: Jack Myers --- level_zero/core/source/device/device_imp.cpp | 6 ++ .../sources/device/test_l0_device.cpp | 86 +++++++++++++++++++ .../2D_BLOCK_TRANSPOSE.md | 79 +++++++++++++++++ level_zero/include/ze_intel_gpu.h | 32 +++++++ shared/source/os_interface/product_helper.h | 2 + shared/source/os_interface/product_helper.inl | 10 +++ .../source/os_interface/product_helper_hw.h | 2 + .../os_interface/product_helper_tests.cpp | 10 +++ 8 files changed, 227 insertions(+) create mode 100644 level_zero/doc/experimental_extensions/2D_BLOCK_TRANSPOSE.md diff --git a/level_zero/core/source/device/device_imp.cpp b/level_zero/core/source/device/device_imp.cpp index 7b6100b929..5afa26405f 100644 --- a/level_zero/core/source/device/device_imp.cpp +++ b/level_zero/core/source/device/device_imp.cpp @@ -1060,6 +1060,12 @@ ze_result_t DeviceImp::getProperties(ze_device_properties_t *pDeviceProperties) auto deviceMediaProperties = reinterpret_cast(extendedProperties); deviceMediaProperties->numDecoderCores = 0; deviceMediaProperties->numEncoderCores = 0; + } else if (extendedProperties->stype == ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES) { + ze_intel_device_block_array_exp_flags_t supportMatrix{0}; + supportMatrix |= getProductHelper().supports2DBlockStore() ? ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_STORE : 0; + supportMatrix |= getProductHelper().supports2DBlockLoad() ? ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_LOAD : 0; + auto blockTransposeProps = reinterpret_cast(extendedProperties); + blockTransposeProps->flags = supportMatrix; } getAdditionalExtProperties(extendedProperties); extendedProperties = static_cast(extendedProperties->pNext); diff --git a/level_zero/core/test/unit_tests/sources/device/test_l0_device.cpp b/level_zero/core/test/unit_tests/sources/device/test_l0_device.cpp index defe840ec6..7a9f0c48ec 100644 --- a/level_zero/core/test/unit_tests/sources/device/test_l0_device.cpp +++ b/level_zero/core/test/unit_tests/sources/device/test_l0_device.cpp @@ -6117,5 +6117,91 @@ TEST(ExtensionLookupTest, givenLookupMapWhenAskingForZeIntelGetDriverVersionStri EXPECT_NE(nullptr, ExtensionFunctionAddressHelper::getExtensionFunctionAddress("zeIntelGetDriverVersionString")); } +template +class Mock2DTransposeProductHelper : public MockProductHelperHw { + public: + bool supports2DBlockLoad() const override { + return BlockLoad; + } + bool supports2DBlockStore() const override { + return BlockStore; + } +}; + +template +class Mock2DTransposeDevice : public MockDeviceImp { + public: + using mockProductHelperType = Mock2DTransposeProductHelper; + + using MockDeviceImp::MockDeviceImp; + + const ProductHelper &getProductHelper() override { + return *mockProductHelper; + } + + private: + std::unique_ptr mockProductHelper = std::make_unique(); +}; + +TEST(ExtensionLookupTest, given2DBlockLoadFalseAnd2DBlockStoreFalseThenFlagsIndicateSupportsNeither) { + auto *neoMockDevice = NEO::MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get(), 0); + Mock2DTransposeDevice deviceImp(neoMockDevice, neoMockDevice->getExecutionEnvironment()); + + ze_device_properties_t deviceProps = {ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES}; + ze_intel_device_block_array_exp_properties_t blockArrayProps = {ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES}; + deviceProps.pNext = &blockArrayProps; + + auto success = L0::Device::fromHandle(static_cast(&deviceImp))->getProperties(&deviceProps); + ASSERT_EQ(success, ZE_RESULT_SUCCESS); + + ASSERT_FALSE(static_cast(blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_LOAD)); + ASSERT_FALSE(static_cast(blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_STORE)); +} + +TEST(ExtensionLookupTest, given2DBlockLoadTrueAnd2DBlockStoreFalseThenFlagsIndicateSupportLoad) { + auto *neoMockDevice = NEO::MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get(), 0); + Mock2DTransposeDevice deviceImp(neoMockDevice, neoMockDevice->getExecutionEnvironment()); + + ze_device_properties_t deviceProps = {ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES}; + ze_intel_device_block_array_exp_properties_t blockArrayProps = {ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES}; + deviceProps.pNext = &blockArrayProps; + + auto success = L0::Device::fromHandle(static_cast(&deviceImp))->getProperties(&deviceProps); + ASSERT_EQ(success, ZE_RESULT_SUCCESS); + + ASSERT_TRUE(static_cast(blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_LOAD)); + ASSERT_FALSE(static_cast(blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_STORE)); +} + +TEST(ExtensionLookupTest, given2DBlockLoadFalseAnd2DBlockStoreTrueThenFlagsIndicateSupportStore) { + auto *neoMockDevice = NEO::MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get(), 0); + Mock2DTransposeDevice deviceImp(neoMockDevice, neoMockDevice->getExecutionEnvironment()); + + ze_device_properties_t deviceProps = {ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES}; + ze_intel_device_block_array_exp_properties_t blockArrayProps = {ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES}; + deviceProps.pNext = &blockArrayProps; + + auto success = L0::Device::fromHandle(static_cast(&deviceImp))->getProperties(&deviceProps); + ASSERT_EQ(success, ZE_RESULT_SUCCESS); + + ASSERT_FALSE(static_cast(blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_LOAD)); + ASSERT_TRUE(static_cast(blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_STORE)); +} + +TEST(ExtensionLookupTest, given2DBlockLoadTrueAnd2DBlockStoreTrueThenFlagsIndicateSupportBoth) { + auto *neoMockDevice = NEO::MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get(), 0); + Mock2DTransposeDevice deviceImp(neoMockDevice, neoMockDevice->getExecutionEnvironment()); + + ze_device_properties_t deviceProps = {ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES}; + ze_intel_device_block_array_exp_properties_t blockArrayProps = {ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES}; + deviceProps.pNext = &blockArrayProps; + + auto success = L0::Device::fromHandle(static_cast(&deviceImp))->getProperties(&deviceProps); + ASSERT_EQ(success, ZE_RESULT_SUCCESS); + + ASSERT_TRUE(static_cast(blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_LOAD)); + ASSERT_TRUE(static_cast(blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_STORE)); +} + } // namespace ult } // namespace L0 diff --git a/level_zero/doc/experimental_extensions/2D_BLOCK_TRANSPOSE.md b/level_zero/doc/experimental_extensions/2D_BLOCK_TRANSPOSE.md new file mode 100644 index 0000000000..f602ce4b20 --- /dev/null +++ b/level_zero/doc/experimental_extensions/2D_BLOCK_TRANSPOSE.md @@ -0,0 +1,79 @@ + + +# 2D Block Array Transpose Properties Extension + +* [Overview](#Overview) +* [Definitions](#Definitions) +* [Known Issues and Limitations](#Known-Issues-and-Limitations) + +# Overview + +Some key framework optimization replies on 2D-block-load transpose feature of GPU product, but this feature is absent in some Intel GPU products. +This extension allows for users to query the 2D-block-load transpose capabilities of a device. + +# Definitions + +## Interfaces + +```cpp +/////////////////////////////////////////////////////////////////////////////// +/// @brief Supported 2D Block Array flags +typedef uint32_t ze_intel_device_block_array_exp_flags_t; +typedef enum _ze_intel_device_block_array_exp_flag_t { + ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_STORE = ZE_BIT(0), ///< Supports store operation + ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_LOAD = ZE_BIT(1), ///< Supports load operation + ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_FORCE_UINT32 = 0x7fffffff + +} ze_intel_device_block_array_exp_flag_t; + +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_NAME +/// @brief Device 2D block array properties driver extension name +#define ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_NAME "ZE_intel_experimental_device_block_array_properties" +#endif // ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_NAME + +/// @brief Device 2D block array properties queried using +/// ::zeDeviceGetProperties +/// +/// @details +/// - This structure may be passed to ::zeDeviceGetProperties, via +/// `pNext` member of ::ze_device_properties_t. +/// @brief Device 2D block array properties +#define ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES (ze_structure_type_t)0x00030007 + +typedef struct _ze_intel_device_block_array_exp_properties_t { + ze_structure_type_t stype = ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES; ///< [in] type of this structure + void *pNext; ///< [in,out][optional] must be null or a pointer to an extension-specific + ///< structure (i.e. contains sType and pNext). + ze_intel_device_block_array_exp_flags_t flags; ///< [out] 0 (none) or a valid combination of ::ze_intel_device_block_array_exp_flag_t +} ze_intel_device_block_array_exp_properties_t; +``` + +## Programming example + +```cpp + + ze_device_roperties_t deviceProps = {ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES}; + ze_intel_device_block_array_exp_properties_t blockArrayProps = {ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES}; + deviceProps.pNext = &blockArrayProps; + + SUCCESS_OR_TERMINATE(zeDeviceGetProperties(device, &deviceProps)); + + if (blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_STORE) { + printf("2D block store supported\n"); + } + + if (blockArrayProps.flags & ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_LOAD) { + printf("2D block load supported\n"); + } + +``` + +# Known Issues and Limitations + diff --git a/level_zero/include/ze_intel_gpu.h b/level_zero/include/ze_intel_gpu.h index 07c1de741a..94fb91e7b5 100644 --- a/level_zero/include/ze_intel_gpu.h +++ b/level_zero/include/ze_intel_gpu.h @@ -187,6 +187,38 @@ typedef enum _ze_intel_get_driver_version_string_exp_version_t { ZE_INTEL_GET_DRIVER_VERSION_STRING_EXP_VERSION_FORCE_UINT32 = 0x7fffffff } ze_intel_get_driver_version_string_exp_version_t; +/////////////////////////////////////////////////////////////////////////////// +/// @brief Supported 2D Block Array flags +typedef uint32_t ze_intel_device_block_array_exp_flags_t; +typedef enum _ze_intel_device_block_array_exp_flag_t { + ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_STORE = ZE_BIT(0), ///< Supports store operation + ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_LOAD = ZE_BIT(1), ///< Supports load operation + ZE_INTEL_DEVICE_EXP_FLAG_2D_BLOCK_FORCE_UINT32 = 0x7fffffff + +} ze_intel_device_block_array_exp_flag_t; + +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_NAME +/// @brief Device 2D block array properties driver extension name +#define ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_NAME "ZE_intel_experimental_device_block_array_properties" +#endif // ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_NAME + +/// @brief Device 2D block array properties queried using +/// ::zeDeviceGetProperties +/// +/// @details +/// - This structure may be passed to ::zeDeviceGetProperties, via +/// `pNext` member of ::ze_device_properties_t. +/// @brief Device 2D block array properties +#define ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES (ze_structure_type_t)0x00030007 + +typedef struct _ze_intel_device_block_array_exp_properties_t { + ze_structure_type_t stype = ZE_INTEL_DEVICE_BLOCK_ARRAY_EXP_PROPERTIES; ///< [in] type of this structure + void *pNext; ///< [in,out][optional] must be null or a pointer to an extension-specific + ///< structure (i.e. contains sType and pNext). + ze_intel_device_block_array_exp_flags_t flags; ///< [out] 0 (none) or a valid combination of ::ze_intel_device_block_array_exp_flag_t +} ze_intel_device_block_array_exp_properties_t; + /// @brief Query to read the Intel Level Zero Driver Version String /// /// @details diff --git a/shared/source/os_interface/product_helper.h b/shared/source/os_interface/product_helper.h index 4cef2552de..4bc3b65ee2 100644 --- a/shared/source/os_interface/product_helper.h +++ b/shared/source/os_interface/product_helper.h @@ -241,6 +241,8 @@ class ProductHelper { virtual std::optional isCoherentAllocation(uint64_t patIndex) const = 0; virtual bool isStagingBuffersEnabled() const = 0; virtual uint32_t getCacheLineSize() const = 0; + virtual bool supports2DBlockStore() const = 0; + virtual bool supports2DBlockLoad() const = 0; virtual ~ProductHelper() = default; diff --git a/shared/source/os_interface/product_helper.inl b/shared/source/os_interface/product_helper.inl index 710d6744c9..0aa96e6586 100644 --- a/shared/source/os_interface/product_helper.inl +++ b/shared/source/os_interface/product_helper.inl @@ -909,4 +909,14 @@ uint32_t ProductHelperHw::getCacheLineSize() const { return GfxProduct::cacheLineSize; } +template +bool ProductHelperHw::supports2DBlockLoad() const { + return false; +} + +template +bool ProductHelperHw::supports2DBlockStore() const { + return false; +} + } // namespace NEO diff --git a/shared/source/os_interface/product_helper_hw.h b/shared/source/os_interface/product_helper_hw.h index 2030f67a82..64b1e2d410 100644 --- a/shared/source/os_interface/product_helper_hw.h +++ b/shared/source/os_interface/product_helper_hw.h @@ -185,6 +185,8 @@ class ProductHelperHw : public ProductHelper { std::optional isCoherentAllocation(uint64_t patIndex) const override; bool isStagingBuffersEnabled() const override; uint32_t getCacheLineSize() const override; + bool supports2DBlockStore() const override; + bool supports2DBlockLoad() const override; ~ProductHelperHw() override = default; diff --git a/shared/test/unit_test/os_interface/product_helper_tests.cpp b/shared/test/unit_test/os_interface/product_helper_tests.cpp index 694214c8d5..c19f2ee494 100644 --- a/shared/test/unit_test/os_interface/product_helper_tests.cpp +++ b/shared/test/unit_test/os_interface/product_helper_tests.cpp @@ -1011,3 +1011,13 @@ TEST_F(ProductHelperTest, whenGettingMaxSubSliceSpaceThenValueIsNotSmallerThanMa } EXPECT_EQ(maxSupportedSubSlices, productHelper->computeMaxNeededSubSliceSpace(hwInfo)); } + +HWTEST_F(ProductHelperTest, givenDefaultProductHelperWhenQuery2DBlockLoadThenReturnFalse) { + + EXPECT_FALSE(productHelper->supports2DBlockLoad()); +} + +HWTEST_F(ProductHelperTest, givenDefaultProductHelperWhenQuery2DBlockStoreThenReturnFalse) { + + EXPECT_FALSE(productHelper->supports2DBlockStore()); +}