From ebfdb5a1ea73c2269eec5af492970c2174ab7d0f Mon Sep 17 00:00:00 2001 From: Gian Marco Iodice Date: Fri, 7 Jul 2023 11:25:57 +0100 Subject: Integrate CLTensorArgument - Add CLTensorArgument to query the components and storages as OpenCL variables (or by values when possible) - Add caching mechanism in CLTensorArgument to keep track of the components and storages used - Add unit tests Resolves COMPMID-5787 Signed-off-by: Gian Marco Iodice Signed-off-by: Viet-Hoa Do Change-Id: Ib39e1f77b097e5b907a296fe6b0d41bb4bcd4ffc Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/9908 Comments-Addressed: Arm Jenkins Benchmark: Arm Jenkins Tested-by: Arm Jenkins Reviewed-by: Gunes Bayir Reviewed-by: Jakub Sujak --- compute_kernel_writer/CMakeLists.txt | 6 +- compute_kernel_writer/include/ckw/Error.h | 21 +- compute_kernel_writer/include/ckw/TensorInfo.h | 72 +-- .../include/ckw/types/TensorComponentType.h | 61 +++ .../include/ckw/types/TensorDataLayout.h | 52 ++ .../include/ckw/types/TensorStorageType.h | 46 ++ compute_kernel_writer/src/ITensorArgument.h | 121 +++++ compute_kernel_writer/src/TensorUtils.cpp | 56 +-- compute_kernel_writer/src/TensorUtils.h | 13 +- compute_kernel_writer/src/cl/CLHelpers.cpp | 26 +- compute_kernel_writer/src/cl/CLHelpers.h | 10 +- compute_kernel_writer/src/cl/CLTensorArgument.cpp | 247 ++++++++++ compute_kernel_writer/src/cl/CLTensorArgument.h | 70 +++ .../src/types/TensorComponentType.h | 78 +++ compute_kernel_writer/validation/Validation.cpp | 21 +- .../validation/tests/CLTensorArgumentTest.h | 533 +++++++++++++++++++++ .../validation/tests/TensorBitMaskTest.h | 221 +++++++++ .../validation/tests/TensorBitMaskTest.hpp | 219 --------- compute_kernel_writer/validation/tests/UtilsTest.h | 104 ++++ .../validation/tests/UtilsTest.hpp | 103 ---- 20 files changed, 1640 insertions(+), 440 deletions(-) create mode 100644 compute_kernel_writer/include/ckw/types/TensorComponentType.h create mode 100644 compute_kernel_writer/include/ckw/types/TensorDataLayout.h create mode 100644 compute_kernel_writer/include/ckw/types/TensorStorageType.h create mode 100644 compute_kernel_writer/src/ITensorArgument.h create mode 100644 compute_kernel_writer/src/cl/CLTensorArgument.cpp create mode 100644 compute_kernel_writer/src/cl/CLTensorArgument.h create mode 100644 compute_kernel_writer/src/types/TensorComponentType.h create mode 100644 compute_kernel_writer/validation/tests/CLTensorArgumentTest.h create mode 100644 compute_kernel_writer/validation/tests/TensorBitMaskTest.h delete mode 100644 compute_kernel_writer/validation/tests/TensorBitMaskTest.hpp create mode 100644 compute_kernel_writer/validation/tests/UtilsTest.h delete mode 100644 compute_kernel_writer/validation/tests/UtilsTest.hpp diff --git a/compute_kernel_writer/CMakeLists.txt b/compute_kernel_writer/CMakeLists.txt index 9f372df585..674bc53309 100644 --- a/compute_kernel_writer/CMakeLists.txt +++ b/compute_kernel_writer/CMakeLists.txt @@ -131,6 +131,7 @@ target_sources(ckw PRIVATE if(CKW_ENABLE_OPENCL) target_sources(ckw PRIVATE src/cl/CLConstantTile.cpp + src/cl/CLTensorArgument.cpp src/cl/CLHelpers.cpp src/cl/CLTile.cpp src/cl/ICLTile.cpp @@ -150,11 +151,6 @@ if(CKW_BUILD_TESTING) add_executable(ckw_validation validation/Validation.cpp ) - if(CKW_ENABLE_OPENCL) - target_sources(ckw_validation PRIVATE - validation/tests/CLConstantTileTest.hpp - validation/tests/CLTileTest.hpp) - endif() target_link_libraries(ckw_validation PRIVATE ckw) target_include_directories(ckw_validation diff --git a/compute_kernel_writer/include/ckw/Error.h b/compute_kernel_writer/include/ckw/Error.h index 100bdc48fe..eaf3f10c05 100644 --- a/compute_kernel_writer/include/ckw/Error.h +++ b/compute_kernel_writer/include/ckw/Error.h @@ -87,7 +87,7 @@ inline void ignore_unused(T &&...) #ifdef COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED -/** If the condition is not met, throw an std::runtime_error with the specified message. +/** If the condition is not met, throw an std::runtime_error with the specified message if assertion is enabled. * * @param[in] cond The condition that is expected to be true. * @param[in] msg The error message when the condition is not met. @@ -101,19 +101,24 @@ inline void ignore_unused(T &&...) } \ } while(false) -/** If the condition is not met, throw an std::runtime_error. - * - * @param[in] cond The condition that is expected to be true. - */ -#define CKW_ASSERT(cond) CKW_ASSERT_MSG(cond, #cond) - #else // COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED #define CKW_ASSERT_MSG(cond, msg) -#define CKW_ASSERT(cond) #endif // COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED +/** If the condition is not met, throw an std::runtime_error if assertion is enabled. + * + * @param[in] cond The condition that is expected to be true. + */ +#define CKW_ASSERT(cond) CKW_ASSERT_MSG(cond, #cond) + +/** Throw an std::runtime_error with the specified message if assertion is enabled. + * + * @param[in] msg The error message when the condition is not met. + */ +#define CKW_ASSERT_FAILED_MSG(msg) CKW_ASSERT_MSG(false, msg) + } // namespace ckw #endif // CKW_INCLUDE_CKW_ERROR_H diff --git a/compute_kernel_writer/include/ckw/TensorInfo.h b/compute_kernel_writer/include/ckw/TensorInfo.h index 63d9f412b6..87cf7c1426 100644 --- a/compute_kernel_writer/include/ckw/TensorInfo.h +++ b/compute_kernel_writer/include/ckw/TensorInfo.h @@ -26,85 +26,27 @@ #define COMPUTE_KERNEL_WRITER_INCLUDE_CKW_TENSORINFO_H #include "ckw/types/DataType.h" - +#include "ckw/types/TensorDataLayout.h" #include #include namespace ckw { -/** Compute Kernel Writer tensor data layout (or memory format) */ -enum class TensorDataLayout -{ - Unknown, - Nhwc, - Ndhwc -}; - -/** Compute Kernel Writer tensor data layout component */ -enum class TensorDataLayoutComponent -{ - Unknown, - N, - D, - H, - W, - C, -}; - -/** Compute Kernel Writer tensor component bitmask. The bitmask can be used to retrieve - * the info from @ref TensorComponent. - */ -enum class TensorComponentBitmask : uint32_t -{ - OffsetFirstElement = 0x01000000, // For example, OffsetFirstElement in @ref TensorComponent - Stride = 0x02000000, // For example, stride0 in @ref TensorComponent - Dimension = 0x04000000, // For example, Dim0 in @ref TensorComponent - FoldedDimensions = 0x08000000, // For example, Dim0xDim1 in @ref TensorComponent -}; - -/** Compute Kernel Writer tensor component. The tensor components are used to access specific backend-agnostic tensor arguments, - * such as the tensor dimensions and tensor strides. - * The data type is represented as an integer. The value of the integer value - * is assigned to retrieve the information through the @ref TensorComponentBitmask. - */ -enum class TensorComponent : uint32_t -{ - Unknown = 0x00000000, - OffsetFirstElement = 0x01000000, - Stride0 = 0x02000001, - Stride1 = 0x02000010, - Stride2 = 0x02000100, - Stride3 = 0x02001000, - Stride4 = 0x02010000, - Dim0 = 0x04000001, - Dim1 = 0x04000010, - Dim2 = 0x04000100, - Dim3 = 0x04001000, - Dim4 = 0x04010000, - Dim1xDim2 = 0x08000110, - Dim2xDim3 = 0x08001100, - Dim1xDim2xDim3 = 0x08001110 -}; - -/** Compute Kernel Writer tensor storage. The tensor storage represents the type of tensor memory object. - */ -enum class TensorStorage : uint32_t -{ - Unknown = 0x00000000, - BufferUint8Ptr = 0x01000000, - Texture2dReadOnly = 0x02000001, - Texture2dWriteOnly = 0x02000010, -}; /** Compute Kernel Writer tensor shape - * Negative dimensions can be interpreted as dynamic dimensions by the Compute Kernel Writer + * The value -1 for the tensor dimension is reserved to dynamic dimensions. */ using TensorShape = std::array; +/** Tensor dimension value reserved to dynamic dimensions */ +constexpr int32_t kDynamicTensorDimensionValue = -1; + /** Compute Kernel Writer tensor info */ class TensorInfo { public: + /** Default constructor */ + TensorInfo() = default; /** Constructor * * @param[in] dt Tensor data type diff --git a/compute_kernel_writer/include/ckw/types/TensorComponentType.h b/compute_kernel_writer/include/ckw/types/TensorComponentType.h new file mode 100644 index 0000000000..7a5031d8c0 --- /dev/null +++ b/compute_kernel_writer/include/ckw/types/TensorComponentType.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef CKW_INCLUDE_CKW_TYPES_TENSORCOMPONENTTYPE_H +#define CKW_INCLUDE_CKW_TYPES_TENSORCOMPONENTTYPE_H + +#include + +namespace ckw +{ + +/** Compute Kernel Writer tensor component. + * + * The tensor components are used to access specific backend-agnostic tensor arguments, + * such as the tensor dimensions and tensor strides. + * The tensor component is represented as an unsigned integer. The value of the integer value + * is assigned to retrieve the information through the @ref TensorComponentBitmask. + */ +enum class TensorComponentType : uint32_t +{ + Unknown = 0x00000000, + OffsetFirstElement = 0x01000000, + Stride0 = 0x02000001, + Stride1 = 0x02000002, + Stride2 = 0x02000003, + Stride3 = 0x02000004, + Stride4 = 0x02000005, + Dim0 = 0x04000001, + Dim1 = 0x04000002, + Dim2 = 0x04000003, + Dim3 = 0x04000004, + Dim4 = 0x04000005, + Dim1xDim2 = 0x08000032, + Dim2xDim3 = 0x08000043, + Dim1xDim2xDim3 = 0x08000432 +}; + +} // namespace ckw + +#endif // CKW_INCLUDE_CKW_TYPES_TENSORCOMPONENTTYPE_H diff --git a/compute_kernel_writer/include/ckw/types/TensorDataLayout.h b/compute_kernel_writer/include/ckw/types/TensorDataLayout.h new file mode 100644 index 0000000000..532b299910 --- /dev/null +++ b/compute_kernel_writer/include/ckw/types/TensorDataLayout.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef CKW_INCLUDE_CKW_TYPES_TENSORDATALAYOUT_H +#define CKW_INCLUDE_CKW_TYPES_TENSORDATALAYOUT_H + +namespace ckw +{ + +/** Compute Kernel Writer tensor data layout (or memory format) */ +enum class TensorDataLayout +{ + Unknown, + Nhwc, + Ndhwc +}; + +/** Compute Kernel Writer tensor data layout component */ +enum class TensorDataLayoutComponent +{ + Unknown, + N, + D, + H, + W, + C, +}; + +} // namespace ckw + +#endif // CKW_INCLUDE_CKW_TYPES_TENSORDATALAYOUT_H diff --git a/compute_kernel_writer/include/ckw/types/TensorStorageType.h b/compute_kernel_writer/include/ckw/types/TensorStorageType.h new file mode 100644 index 0000000000..5a2f17d520 --- /dev/null +++ b/compute_kernel_writer/include/ckw/types/TensorStorageType.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef CKW_INCLUDE_CKW_TYPES_TENSORSTORAGETYPE_H +#define CKW_INCLUDE_CKW_TYPES_TENSORSTORAGETYPE_H + +#include + +namespace ckw +{ + +/** Compute Kernel Writer tensor storage. + * The tensor storage represents the type of tensor memory object. + */ +enum class TensorStorageType : uint32_t +{ + Unknown = 0x00000000, + BufferUint8Ptr = 0x01000000, + Texture2dReadOnly = 0x02000001, + Texture2dWriteOnly = 0x02000010, +}; + +} // namespace ckw + +#endif // CKW_INCLUDE_CKW_TYPES_TENSORSTORAGETYPE_H diff --git a/compute_kernel_writer/src/ITensorArgument.h b/compute_kernel_writer/src/ITensorArgument.h new file mode 100644 index 0000000000..40ad69fdc0 --- /dev/null +++ b/compute_kernel_writer/src/ITensorArgument.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef CKW_SRC_ITENSORARGUMENT_H +#define CKW_SRC_ITENSORARGUMENT_H + +#include "ckw/TensorInfo.h" +#include "ckw/types/TensorComponentType.h" +#include "ckw/types/TensorStorageType.h" +#include "src/ITile.h" + +#include +#include + +namespace ckw +{ +/** Tensor storage variable */ +struct TensorStorageVariable +{ + std::string val{ "" }; /** Tensor storage as a string */ + std::string type{ "" }; /** Tensor storage type as a string */ +}; + +/** Tensor argument base class. + * A tensor is a multidimensional array used to store data. To access an element (or multiple elements) from a tensor, + * the following information are required: + * -# The data memory object. For example, the pointer to the array + * -# The tensor components, such as the size of each tensor dimension, or the number of elements in bytes contained in each dimension (also known as the "stride") + */ +class ITensorArgument +{ +public: + virtual ~ITensorArgument() = default; + /** Method to get the name of the tensor argument. + * + * @return the name of the tensor argument + */ + std::string name() const + { + return _basename; + } + /** Method to get the tensor info + * + * @return the @ref TensorInfo + */ + TensorInfo info() const + { + return _info; + } + +protected: + TensorInfo _info{}; // Tensor info + std::string _basename{ "" }; // Tensor name +}; + +/** Tensor component argument base class */ +class ITensorComponentArgument +{ +public: + virtual ~ITensorComponentArgument() = default; + /** Method to get the tensor component variable as a string + * + * @param[in] x The tensor component to query + * + * @return the tensor component variable as a @ref TileVariable + */ + virtual TileVariable component(TensorComponentType x) = 0; + /** Method to get all tensor components needed to access the data in the tensor + * + * The tensor components returned by this method must be all passed as kernel argument + * + * @return a vector containing all the tensor components as @ref TileVariable objects + */ + virtual std::vector components() const = 0; +}; + +/** Tensor storage argument base class */ +class ITensorStorageArgument +{ +public: + virtual ~ITensorStorageArgument() = default; + /** Method to get the tensor storage as a string + * + * @param[in] x The tensor storage to query + * + * @return the tensor storage as a @ref TensorStorageVariable + */ + virtual TensorStorageVariable storage(TensorStorageType x) = 0; + /** Method to get all tensor storages needed to access the data in the tensor + * + * The tensor storages returned by this method must be all passed as kernel argument + * + * @return a vector containing all the tensor storages as @ref TensorStorageVariable objects + */ + virtual std::vector storages() const = 0; +}; + +} // namespace ckw + +#endif // CKW_SRC_ITENSORARGUMENT_H diff --git a/compute_kernel_writer/src/TensorUtils.cpp b/compute_kernel_writer/src/TensorUtils.cpp index 4970de75a6..24836092d4 100644 --- a/compute_kernel_writer/src/TensorUtils.cpp +++ b/compute_kernel_writer/src/TensorUtils.cpp @@ -22,14 +22,14 @@ * SOFTWARE. */ +#include "src/TensorUtils.h" #include "ckw/Error.h" #include "ckw/TensorInfo.h" - -#include "src/TensorUtils.h" +#include "ckw/types/TensorComponentType.h" namespace ckw { -TensorComponent get_tensor_dimension(TensorDataLayout layout, TensorDataLayoutComponent component) +TensorComponentType get_tensor_dimension(TensorDataLayout layout, TensorDataLayoutComponent component) { switch(layout) { @@ -37,41 +37,41 @@ TensorComponent get_tensor_dimension(TensorDataLayout layout, TensorDataLayoutCo switch(component) { case TensorDataLayoutComponent::C: - return TensorComponent::Dim0; + return TensorComponentType::Dim0; case TensorDataLayoutComponent::W: - return TensorComponent::Dim1; + return TensorComponentType::Dim1; case TensorDataLayoutComponent::H: - return TensorComponent::Dim2; + return TensorComponentType::Dim2; case TensorDataLayoutComponent::N: - return TensorComponent::Dim3; + return TensorComponentType::Dim3; default: COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor component for NHWC"); - return TensorComponent::Unknown; + return TensorComponentType::Unknown; } case TensorDataLayout::Ndhwc: switch(component) { case TensorDataLayoutComponent::C: - return TensorComponent::Dim0; + return TensorComponentType::Dim0; case TensorDataLayoutComponent::W: - return TensorComponent::Dim1; + return TensorComponentType::Dim1; case TensorDataLayoutComponent::H: - return TensorComponent::Dim2; + return TensorComponentType::Dim2; case TensorDataLayoutComponent::D: - return TensorComponent::Dim3; + return TensorComponentType::Dim3; case TensorDataLayoutComponent::N: - return TensorComponent::Dim4; + return TensorComponentType::Dim4; default: COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor component for NDHWC"); - return TensorComponent::Unknown; + return TensorComponentType::Unknown; } default: COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor data layout"); - return TensorComponent::Unknown; + return TensorComponentType::Unknown; } } -TensorComponent get_tensor_stride(TensorDataLayout layout, TensorDataLayoutComponent component) +TensorComponentType get_tensor_stride(TensorDataLayout layout, TensorDataLayoutComponent component) { switch(layout) { @@ -79,37 +79,37 @@ TensorComponent get_tensor_stride(TensorDataLayout layout, TensorDataLayoutCompo switch(component) { case TensorDataLayoutComponent::C: - return TensorComponent::Stride0; + return TensorComponentType::Stride0; case TensorDataLayoutComponent::W: - return TensorComponent::Stride1; + return TensorComponentType::Stride1; case TensorDataLayoutComponent::H: - return TensorComponent::Stride2; + return TensorComponentType::Stride2; case TensorDataLayoutComponent::N: - return TensorComponent::Stride3; + return TensorComponentType::Stride3; default: COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor component for NHWC"); - return TensorComponent::Unknown; + return TensorComponentType::Unknown; } case TensorDataLayout::Ndhwc: switch(component) { case TensorDataLayoutComponent::C: - return TensorComponent::Stride0; + return TensorComponentType::Stride0; case TensorDataLayoutComponent::W: - return TensorComponent::Stride1; + return TensorComponentType::Stride1; case TensorDataLayoutComponent::H: - return TensorComponent::Stride2; + return TensorComponentType::Stride2; case TensorDataLayoutComponent::D: - return TensorComponent::Stride3; + return TensorComponentType::Stride3; case TensorDataLayoutComponent::N: - return TensorComponent::Stride4; + return TensorComponentType::Stride4; default: COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor component for NDHWC"); - return TensorComponent::Unknown; + return TensorComponentType::Unknown; } default: COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor data layout"); - return TensorComponent::Unknown; + return TensorComponentType::Unknown; } } } // namespace ckw diff --git a/compute_kernel_writer/src/TensorUtils.h b/compute_kernel_writer/src/TensorUtils.h index 84eca084bb..bb0af5c0b9 100644 --- a/compute_kernel_writer/src/TensorUtils.h +++ b/compute_kernel_writer/src/TensorUtils.h @@ -22,8 +22,8 @@ * SOFTWARE. */ -#ifndef COMPUTE_KERNEL_WRITER_SRC_TENSORUTILS_H -#define COMPUTE_KERNEL_WRITER_SRC_TENSORUTILS_H +#ifndef CKW_SRC_TENSORUTILS_H +#define CKW_SRC_TENSORUTILS_H #include @@ -33,7 +33,7 @@ namespace ckw // Forward declarations enum class TensorDataLayout; enum class TensorDataLayoutComponent; -enum class TensorComponent : uint32_t; +enum class TensorComponentType : uint32_t; /** Get tensor dimension from a given data layout and data layout component * @@ -42,7 +42,7 @@ enum class TensorComponent : uint32_t; * * @return the @ref TensorComponent */ -TensorComponent get_tensor_dimension(TensorDataLayout layout, TensorDataLayoutComponent component); +TensorComponentType get_tensor_dimension(TensorDataLayout layout, TensorDataLayoutComponent component); /** Get tensor stride from a given data layout and data layout component * @@ -51,6 +51,7 @@ TensorComponent get_tensor_dimension(TensorDataLayout layout, TensorDataLayoutCo * * @return the @ref TensorComponent */ -TensorComponent get_tensor_stride(TensorDataLayout layout, TensorDataLayoutComponent component); +TensorComponentType get_tensor_stride(TensorDataLayout layout, TensorDataLayoutComponent component); } // namespace ckw -#endif /* COMPUTE_KERNEL_WRITER_SRC_TENSORUTILS_H */ + +#endif // CKW_SRC_TENSORUTILS_H diff --git a/compute_kernel_writer/src/cl/CLHelpers.cpp b/compute_kernel_writer/src/cl/CLHelpers.cpp index 5a3d0fab81..af8a8a07ac 100644 --- a/compute_kernel_writer/src/cl/CLHelpers.cpp +++ b/compute_kernel_writer/src/cl/CLHelpers.cpp @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include "src/cl/CLHelpers.h" #include "ckw/Error.h" #include "ckw/types/DataType.h" - -#include "src/cl/CLHelpers.h" +#include "ckw/types/TensorStorageType.h" namespace ckw { @@ -120,4 +120,26 @@ int32_t width_to_cl_vector_size(int32_t width) return 0; } } + +std::string cl_get_variable_storagetype_as_string(TensorStorageType storage) +{ + std::string res; + switch(storage) + { + case TensorStorageType::BufferUint8Ptr: + res += "__global uchar*"; + break; + case TensorStorageType::Texture2dReadOnly: + res += "__read_only image2d_t"; + break; + case TensorStorageType::Texture2dWriteOnly: + res += "__write_only image2d_t"; + break; + default: + COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported storage type"); + } + + return res; +} + } // namespace ckw diff --git a/compute_kernel_writer/src/cl/CLHelpers.h b/compute_kernel_writer/src/cl/CLHelpers.h index a9a84e2187..d0ca488617 100644 --- a/compute_kernel_writer/src/cl/CLHelpers.h +++ b/compute_kernel_writer/src/cl/CLHelpers.h @@ -24,14 +24,15 @@ #ifndef CKW_SRC_CL_CLHELPERS_H #define CKW_SRC_CL_CLHELPERS_H -#include #include +#include /** OpenCL specific helper functions */ namespace ckw { // Forward declarations enum class DataType; +enum class TensorStorageType : uint32_t; /** Helper function to validate the vector length of OpenCL vector data types * @@ -58,6 +59,13 @@ std::string cl_get_variable_datatype_as_string(DataType dt, int32_t len); */ int32_t width_to_cl_vector_size(int32_t width); +/** Helper function to return the OpenCL storage type as a string from a @ref TensorStorage + * + * @param[in] storage Storage type + * + * @return the OpenCL storage type as a string + */ +std::string cl_get_variable_storagetype_as_string(TensorStorageType storage); } // namespace ckw #endif /* COMPUTE_KERNEL_WRITER_SRC_CL_CLHELPERS_H */ diff --git a/compute_kernel_writer/src/cl/CLTensorArgument.cpp b/compute_kernel_writer/src/cl/CLTensorArgument.cpp new file mode 100644 index 0000000000..ed1c5bd687 --- /dev/null +++ b/compute_kernel_writer/src/cl/CLTensorArgument.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "src/cl/CLTensorArgument.h" +#include "ckw/Error.h" +#include "src/cl/CLHelpers.h" +#include "src/types/TensorComponentType.h" + +#include +#include + +namespace ckw +{ +CLTensorArgument::CLTensorArgument(const std::string &name, const TensorInfo &info, bool return_dims_by_value) +{ + _return_dims_by_value = return_dims_by_value; + _basename = name; + _info = info; +} + +TileVariable CLTensorArgument::component(TensorComponentType x) +{ + if(_return_dims_by_value) + { + uint32_t component_type = static_cast(x); + + const bool is_dimension = (component_type & static_cast(TensorComponentBitmask::Dimension)) != 0; + const bool is_folded_dimensions = (component_type & static_cast(TensorComponentBitmask::FoldedDimensions)) != 0; + + constexpr auto bitmask_all = static_cast(TensorComponentIndexBitmask::All); + constexpr auto bitmask_index_0 = static_cast(TensorComponentIndexBitmask::Index0); +#ifdef COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED + constexpr auto bitmask_index_1 = static_cast(TensorComponentIndexBitmask::Index1); + constexpr auto bitmask_index_2 = static_cast(TensorComponentIndexBitmask::Index2); + constexpr auto bitmask_index_3 = static_cast(TensorComponentIndexBitmask::Index3); +#endif // COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED + + // Make sure that the encoding of component type hasn't changed and each nibble is 4 bits apart. + CKW_ASSERT(bitmask_all == (bitmask_index_0 | bitmask_index_1 | bitmask_index_2 | bitmask_index_3)); + CKW_ASSERT(bitmask_index_0 == bitmask_index_1 >> 4); + CKW_ASSERT(bitmask_index_1 == bitmask_index_2 >> 4); + CKW_ASSERT(bitmask_index_2 == bitmask_index_3 >> 4); + + // If we have a dimension or folded dimensions, we can return the corresponding value if it is not dynamic (not equal to -1) + if(is_dimension == true || is_folded_dimensions == true) + { + component_type = component_type & bitmask_all; + + int32_t idx = 1; + for(int32_t i = 0; i < tensor_component_index_max_count; ++i) + { + uint32_t dim_idx = component_type & bitmask_index_0; + + if(dim_idx == 0) + { + // Stop at the first nibble containing 0 + break; + } + + // Subtract - 1. Please refer to the TensorComponentIndexBitmask documentation + dim_idx -= 1; + + // Get the dimension value + const int32_t dim_val = _info.shape()[dim_idx]; + + if(dim_val == kDynamicTensorDimensionValue) + { + // We cannot return the dimension by value if it is dynamic. + // Therefore, force the idx variable to kDynamicTensorDimensionValue and break the loop. + idx = kDynamicTensorDimensionValue; + break; + } + + idx *= dim_val; + + // Go to the next nibble + component_type >>= 4; + } + + if(idx != kDynamicTensorDimensionValue) + { + TileVariable t; + t.str = std::to_string(idx); + t.desc.dt = DataType::Uint32; + t.desc.len = 1; + return t; + } + } + } + + auto it = std::find(_components_used.begin(), _components_used.end(), x); + + // Add to the list of used components if not present yet + if(it == _components_used.end()) + { + _components_used.push_back(x); + } + + TileVariable t; + t.str = create_component_name(x); + t.desc.dt = DataType::Int32; + t.desc.len = 1; + return t; +} + +TensorStorageVariable CLTensorArgument::storage(TensorStorageType x) +{ + if(std::find(_storages_used.begin(), _storages_used.end(), x) == _storages_used.end()) + { + _storages_used.push_back(x); + } + + TensorStorageVariable t; + t.val = create_storage_name(x); + t.type = cl_get_variable_storagetype_as_string(x); + + return t; +} + +std::string CLTensorArgument::create_storage_name(TensorStorageType x) const +{ + std::string var_name = _basename; + + switch(x) + { + case TensorStorageType::BufferUint8Ptr: + var_name += "_ptr"; + break; + case TensorStorageType::Texture2dReadOnly: + case TensorStorageType::Texture2dWriteOnly: + var_name += "_img2d"; + break; + default: + CKW_ASSERT_FAILED_MSG("Unsupported tensor storage"); + return ""; + } + + return var_name; +} + +std::string CLTensorArgument::create_component_name(TensorComponentType x) const +{ + std::string var_name = _basename; + + switch(x) + { + case TensorComponentType::OffsetFirstElement: + var_name += "_offset_first_element"; + break; + case TensorComponentType::Stride0: + var_name += "_stride0"; + break; + case TensorComponentType::Stride1: + var_name += "_stride1"; + break; + case TensorComponentType::Stride2: + var_name += "_stride2"; + break; + case TensorComponentType::Stride3: + var_name += "_stride3"; + break; + case TensorComponentType::Stride4: + var_name += "_stride4"; + break; + case TensorComponentType::Dim0: + var_name += "_dim0"; + break; + case TensorComponentType::Dim1: + var_name += "_dim1"; + break; + case TensorComponentType::Dim2: + var_name += "_dim2"; + break; + case TensorComponentType::Dim3: + var_name += "_dim3"; + break; + case TensorComponentType::Dim4: + var_name += "_dim4"; + break; + case TensorComponentType::Dim1xDim2: + var_name += "_dim1xdim2"; + break; + case TensorComponentType::Dim2xDim3: + var_name += "_dim2xdim3"; + break; + case TensorComponentType::Dim1xDim2xDim3: + var_name += "_dim1xdim2xdim3"; + break; + default: + COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor component"); + return ""; + } + + return var_name; +} + +std::vector CLTensorArgument::storages() const +{ + std::vector storages; + for(auto &val : _storages_used) + { + TensorStorageVariable t; + t.val = create_storage_name(val); + t.type = cl_get_variable_storagetype_as_string(val); + storages.push_back(t); + } + + return storages; +} + +std::vector CLTensorArgument::components() const +{ + std::vector components; + + for(auto &val : _components_used) + { + TileVariable t; + t.str = create_component_name(val); + t.desc.dt = DataType::Int32; + t.desc.len = 1; + components.push_back(t); + } + + return components; +} +} // namespace ckw diff --git a/compute_kernel_writer/src/cl/CLTensorArgument.h b/compute_kernel_writer/src/cl/CLTensorArgument.h new file mode 100644 index 0000000000..cd924846c5 --- /dev/null +++ b/compute_kernel_writer/src/cl/CLTensorArgument.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef CKW_SRC_CL_CLTENSORARGUMENT_H +#define CKW_SRC_CL_CLTENSORARGUMENT_H + +#include "src/ITensorArgument.h" + +#include +#include + +namespace ckw +{ +// Forward declarations +class TensorInfo; + +/** OpenCL specific tensor argument + * Internally, the object keeps track of the components and storages used to minimize the number + * of kernel arguments required. Therefore, if we create this object but we do not access any components + * or storages, the storages() and components() method will return an empty list. +*/ +class CLTensorArgument : public ITensorArgument, ITensorStorageArgument, ITensorComponentArgument +{ +public: + /** Constructor + * + * @param[in] name Tensor name + * @param[in] info Tensor info + * @param[in] return_dims_by_value Flag to return the dimensions by value whenever it is possible. + * True, if the dimensions should be returned as value instead as variable. + */ + CLTensorArgument(const std::string &name, const TensorInfo &info, bool return_dims_by_value); + + // Inherited method overridden + TensorStorageVariable storage(TensorStorageType x); + TileVariable component(TensorComponentType x); + std::vector storages() const; + std::vector components() const; + +private: + std::string create_storage_name(TensorStorageType x) const; + std::string create_component_name(TensorComponentType x) const; + + bool _return_dims_by_value{ false }; + std::vector _storages_used{}; + std::vector _components_used{}; +}; +} // namespace ckw + +#endif // CKW_SRC_CL_CLTENSORARGUMENT_H diff --git a/compute_kernel_writer/src/types/TensorComponentType.h b/compute_kernel_writer/src/types/TensorComponentType.h new file mode 100644 index 0000000000..03f4f4f5c8 --- /dev/null +++ b/compute_kernel_writer/src/types/TensorComponentType.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef CKW_SRC_TYPES_TENSORCOMPONENTTYPE_H +#define CKW_SRC_TYPES_TENSORCOMPONENTTYPE_H + +#include + +namespace ckw +{ + +/** Compute Kernel Writer tensor component bitmask. + * + * The bitmask can be used to retrieve the info from @ref TensorComponent. + */ +enum class TensorComponentBitmask : uint32_t +{ + OffsetFirstElement = 0x01000000, // For example, OffsetFirstElement in TensorComponent + Stride = 0x02000000, // For example, stride0 in TensorComponent + Dimension = 0x04000000, // For example, Dim0 in TensorComponent + FoldedDimensions = 0x08000000, // For example, Dim0xDim1 in TensorComponent +}; + +/** Mask to retrieve the component index (for example, 1 for stride1, 2 for stride2, or 1 and 2 for Dim1xDim2). + * + * The 4 least significant half-bytes (nibbles) of the @ref TensorComponent are used to retrieve the specific component index. + * TensorComponent = | i7 | i6 | i5 | i4 | i3 | i2 | i1 | i0 |, where i7,...i0 are the nibbles + * of the TensorComponent hexadecimal number. i0, i1, i2 and i3 are reserved to the component index. + * + * In particular: + * + * -# i0: reserved to the first folded dimension component index + * -# i1: reserved to the second folded dimension component index + * -# i2: reserved to the third folded dimension component index + * -# i3: reserved to the fourth folded dimension component index + * + * Therefore, if there are no folded dimensions (dimensions and strides), only i0 is used. + * Instead, if there are two folded dimensions, only i0 and i1 are used. + * + * The component index is stored with the corresponding hexadecimal number + 1, + * hence the component index 0 is represented as 1, while the component index 3 is represented as 4. + */ +enum class TensorComponentIndexBitmask : uint32_t +{ + All = 0x0000ffff, // All nibbles reserved to the tensor component index + Index0 = 0x0000000f, // Folded dimension 0 + Index1 = 0x000000f0, // Folded dimension 1 + Index2 = 0x00000f00, // Folded dimension 2 + Index3 = 0x0000f000 // Folded dimension 3 +}; + +/** The maximum number of folded dimensions. */ +constexpr int tensor_component_index_max_count = 4; + +} // namespace ckw + +#endif // CKW_SRC_TYPES_TENSORCOMPONENTTYPE_H diff --git a/compute_kernel_writer/validation/Validation.cpp b/compute_kernel_writer/validation/Validation.cpp index e4884fa4aa..5d53a16eff 100644 --- a/compute_kernel_writer/validation/Validation.cpp +++ b/compute_kernel_writer/validation/Validation.cpp @@ -22,12 +22,13 @@ * SOFTWARE. */ +#include "tests/CLConstantTileTest.hpp" #include "tests/CLKernelWriterCommentTest.h" #include "tests/CLKernelWriterDeclareTileTest.h" -#include "tests/CLConstantTileTest.hpp" +#include "tests/CLTensorArgumentTest.h" #include "tests/CLTileTest.hpp" -#include "tests/TensorBitMaskTest.hpp" -#include "tests/UtilsTest.hpp" +#include "tests/TensorBitMaskTest.h" +#include "tests/UtilsTest.h" #include #include @@ -65,6 +66,13 @@ int32_t main() const auto test15 = std::make_unique(); #endif /* COMPUTE_KERNEL_WRITER_DEBUG_ENABLED */ const auto test16 = std::make_unique(); + const auto test17 = std::make_unique(); + const auto test18 = std::make_unique(); + const auto test19 = std::make_unique(); + const auto test20 = std::make_unique(); + const auto test21 = std::make_unique(); + const auto test22 = std::make_unique(); + const auto test23 = std::make_unique(); tests.push_back(test3.get()); tests.push_back(test4.get()); @@ -82,6 +90,13 @@ int32_t main() tests.push_back(test15.get()); #endif /* COMPUTE_KERNEL_WRITER_DEBUG_ENABLED */ tests.push_back(test16.get()); + tests.push_back(test17.get()); + tests.push_back(test18.get()); + tests.push_back(test19.get()); + tests.push_back(test20.get()); + tests.push_back(test21.get()); + tests.push_back(test22.get()); + tests.push_back(test23.get()); #endif /* COMPUTE_KERNEL_WRITER_OPENCL_ENABLED */ bool all_test_passed = true; diff --git a/compute_kernel_writer/validation/tests/CLTensorArgumentTest.h b/compute_kernel_writer/validation/tests/CLTensorArgumentTest.h new file mode 100644 index 0000000000..6db1384247 --- /dev/null +++ b/compute_kernel_writer/validation/tests/CLTensorArgumentTest.h @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef CKW_TESTS_CLTENSORARGUMENTTEST_H +#define CKW_TESTS_CLTENSORARGUMENTTEST_H + +#include "common/Common.h" +#include "src/cl/CLHelpers.h" +#include "src/cl/CLTensorArgument.h" + +#include +#include + +namespace ckw +{ +class CLTensorArgumentComponentNamesTest : public ITest +{ +public: + const DataType dt = DataType::Fp32; + const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } }); + const std::string tensor_name = "src"; + + CLTensorArgumentComponentNamesTest() + { + _components.push_back(TensorComponentType::Dim0); + _components.push_back(TensorComponentType::Dim1); + _components.push_back(TensorComponentType::Dim2); + _components.push_back(TensorComponentType::Dim3); + _components.push_back(TensorComponentType::Dim4); + _components.push_back(TensorComponentType::Dim1xDim2); + _components.push_back(TensorComponentType::Dim2xDim3); + _components.push_back(TensorComponentType::OffsetFirstElement); + _components.push_back(TensorComponentType::Stride0); + _components.push_back(TensorComponentType::Stride1); + _components.push_back(TensorComponentType::Stride2); + _components.push_back(TensorComponentType::Stride3); + _components.push_back(TensorComponentType::Stride4); + + _expected_vars.push_back("src_dim0"); + _expected_vars.push_back("src_dim1"); + _expected_vars.push_back("src_dim2"); + _expected_vars.push_back("src_dim3"); + _expected_vars.push_back("src_dim4"); + _expected_vars.push_back("src_dim1xdim2"); + _expected_vars.push_back("src_dim2xdim3"); + _expected_vars.push_back("src_offset_first_element"); + _expected_vars.push_back("src_stride0"); + _expected_vars.push_back("src_stride1"); + _expected_vars.push_back("src_stride2"); + _expected_vars.push_back("src_stride3"); + _expected_vars.push_back("src_stride4"); + } + + bool run() override + { + VALIDATE_ON_MSG(_components.size() == _expected_vars.size(), "The number of components and variables does not match"); + + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1); + + const size_t num_tests = _expected_vars.size(); + + int32_t test_idx = 0; + for(size_t i = 0; i < num_tests; ++i) + { + CLTensorArgument arg(tensor_name, info, false /* return_dims_by_value */); + + const std::string expected_var_name = _expected_vars[i]; + const std::string actual_var_name = arg.component(_components[i]).str; + + VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++); + } + return all_tests_passed; + } + + std::string name() override + { + return "CLTensorArgumentVariableNamesTest"; + } + +private: + std::vector _components{}; + std::vector _expected_vars{}; +}; + +class CLTensorArgumentStorageNamesTest : public ITest +{ +public: + const DataType dt = DataType::Fp32; + const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } }); + const std::string tensor_name = "src"; + + CLTensorArgumentStorageNamesTest() + { + _storages.push_back(TensorStorageType::BufferUint8Ptr); + _storages.push_back(TensorStorageType::Texture2dReadOnly); + _storages.push_back(TensorStorageType::Texture2dWriteOnly); + + _expected_vars.push_back("src_ptr"); + _expected_vars.push_back("src_img2d"); + _expected_vars.push_back("src_img2d"); + } + + bool run() override + { + VALIDATE_ON_MSG(_storages.size() == _expected_vars.size(), "The number of storages and variables does not match"); + + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1); + + const size_t num_tests = _expected_vars.size(); + + int32_t test_idx = 0; + for(size_t i = 0; i < num_tests; ++i) + { + CLTensorArgument arg(tensor_name, info, false /* return_dims_by_value */); + + const std::string expected_var_name = _expected_vars[i]; + const std::string actual_var_name = arg.storage(_storages[i]).val; + + VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++); + } + return all_tests_passed; + } + + std::string name() override + { + return "CLTensorArgumentStorageNamesTest"; + } + +private: + std::vector _storages{}; + std::vector _expected_vars{}; +}; + +class CLTensorArgumentComponentValuesTest : public ITest +{ +public: + const DataType dt = DataType::Fp32; + const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } }); + const std::string tensor_name = "src"; + + CLTensorArgumentComponentValuesTest() + { + _components.push_back(TensorComponentType::Dim0); + _components.push_back(TensorComponentType::Dim1); + _components.push_back(TensorComponentType::Dim2); + _components.push_back(TensorComponentType::Dim3); + _components.push_back(TensorComponentType::Dim4); + _components.push_back(TensorComponentType::Dim1xDim2); + _components.push_back(TensorComponentType::Dim2xDim3); + + _expected_vals.push_back(std::to_string(shape[0])); + _expected_vals.push_back(std::to_string(shape[1])); + _expected_vals.push_back(std::to_string(shape[2])); + _expected_vals.push_back(std::to_string(shape[3])); + _expected_vals.push_back(std::to_string(shape[4])); + _expected_vals.push_back(std::to_string(shape[1] * shape[2])); + _expected_vals.push_back(std::to_string(shape[2] * shape[3])); + } + + bool run() override + { + VALIDATE_ON_MSG(_components.size() == _expected_vals.size(), "The number of components and values does not match"); + + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1); + + const size_t num_tests = _expected_vals.size(); + + int32_t test_idx = 0; + for(size_t i = 0; i < num_tests; ++i) + { + CLTensorArgument arg(tensor_name, info, true /* return_dims_by_value */); + + const std::string expected_var_val = _expected_vals[i]; + const std::string actual_var_val = arg.component(_components[i]).str; + + VALIDATE_TEST(actual_var_val.compare(expected_var_val) == 0, all_tests_passed, test_idx++); + } + return all_tests_passed; + } + + std::string name() override + { + return "CLTensorArgumentComponentValuesTest"; + } + +private: + std::vector _components{}; + std::vector _expected_vals{}; +}; + +class CLTensorArgumentComponentsUsedPassByValueFalseTest : public ITest +{ +public: + const DataType dt = DataType::Fp32; + const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } }); + const std::string tensor_name = "src"; + + CLTensorArgumentComponentsUsedPassByValueFalseTest() + { + _components.push_back(TensorComponentType::Dim0); + _components.push_back(TensorComponentType::Dim2); + _components.push_back(TensorComponentType::Dim3); + _components.push_back(TensorComponentType::Dim1xDim2); + _components.push_back(TensorComponentType::OffsetFirstElement); + _components.push_back(TensorComponentType::Stride1); + _components.push_back(TensorComponentType::Stride2); + _components.push_back(TensorComponentType::Stride3); + _components.push_back(TensorComponentType::Dim0); // Repeat the query. The TensorArgument should not create a new variable + _components.push_back(TensorComponentType::Dim2); // Repeat the query. The TensorArgument should not create a new variable + _components.push_back(TensorComponentType::Dim3); // Repeat the query. The TensorArgument should not create a new variable + + _expected_vars.push_back("src_dim0"); + _expected_vars.push_back("src_dim2"); + _expected_vars.push_back("src_dim3"); + _expected_vars.push_back("src_dim1xdim2"); + _expected_vars.push_back("src_offset_first_element"); + _expected_vars.push_back("src_stride1"); + _expected_vars.push_back("src_stride2"); + _expected_vars.push_back("src_stride3"); + } + + bool run() override + { + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1); + + const size_t num_components = _components.size(); + + int32_t test_idx = 0; + + CLTensorArgument arg(tensor_name, info, false /* return_dims_by_value */); + for(size_t i = 0; i < num_components; ++i) + { + arg.component(_components[i]); + } + + const auto actual_vars = arg.components(); + + const size_t num_vars = _expected_vars.size(); + + VALIDATE_ON_MSG(actual_vars.size() == num_vars, "The number of variables must match the number of expected variables"); + + for(size_t i = 0; i < num_vars; ++i) + { + // Validate variable name + const std::string expected_var_name = _expected_vars[i]; + const std::string actual_var_name = actual_vars[i].str; + VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++); + + // Validate data type + const DataType expected_var_type = DataType::Int32; + const DataType actual_var_type = actual_vars[i].desc.dt; + VALIDATE_TEST(actual_var_type == expected_var_type, all_tests_passed, test_idx++); + + // Validate data type length + const int32_t expected_var_len = 1; + const int32_t actual_var_len = actual_vars[i].desc.len; + VALIDATE_TEST(actual_var_len == expected_var_len, all_tests_passed, test_idx++); + } + return all_tests_passed; + } + + std::string name() override + { + return "CLTensorArgumentComponentsUsedPassByValueFalseTest"; + } + +private: + std::vector _components{}; + std::vector _expected_vars{}; +}; + +class CLTensorArgumentComponentsUsedPassByValueTrueTest : public ITest +{ +public: + const DataType dt = DataType::Fp32; + const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } }); + const std::string tensor_name = "src"; + + CLTensorArgumentComponentsUsedPassByValueTrueTest() + { + _components.push_back(TensorComponentType::Dim0); + _components.push_back(TensorComponentType::Dim2); + _components.push_back(TensorComponentType::Dim3); + _components.push_back(TensorComponentType::Dim1xDim2); + _components.push_back(TensorComponentType::OffsetFirstElement); + _components.push_back(TensorComponentType::Stride1); + _components.push_back(TensorComponentType::Stride2); + _components.push_back(TensorComponentType::Stride3); + _components.push_back(TensorComponentType::OffsetFirstElement); // Repeat the query. The TensorArgument should not create a new variable + _components.push_back(TensorComponentType::Stride1); // Repeat the query. The TensorArgument should not create a new variable + + _expected_vars.push_back("src_offset_first_element"); + _expected_vars.push_back("src_stride1"); + _expected_vars.push_back("src_stride2"); + _expected_vars.push_back("src_stride3"); + } + + bool run() override + { + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1); + + const size_t num_components = _components.size(); + + int32_t test_idx = 0; + + CLTensorArgument arg(tensor_name, info, true /* return_dims_by_value */); + for(size_t i = 0; i < num_components; ++i) + { + arg.component(_components[i]); + } + + const auto actual_vars = arg.components(); + + const size_t num_vars = _expected_vars.size(); + + VALIDATE_ON_MSG(actual_vars.size() == num_vars, "The number of variables must match the number of expected variables"); + + // Since the dimensions are passed by value, we expect only the variables for the strides + for(size_t i = 0; i < num_vars; ++i) + { + // Validate variable name + const std::string expected_var_name = _expected_vars[i]; + const std::string actual_var_name = actual_vars[i].str; + VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++); + + // Validate data type + const DataType expected_var_type = DataType::Int32; + const DataType actual_var_type = actual_vars[i].desc.dt; + VALIDATE_TEST(actual_var_type == expected_var_type, all_tests_passed, test_idx++); + + // Validate data type length + const int32_t expected_var_len = 1; + const int32_t actual_var_len = actual_vars[i].desc.len; + VALIDATE_TEST(actual_var_len == expected_var_len, all_tests_passed, test_idx++); + } + return all_tests_passed; + } + + std::string name() override + { + return "CLTensorArgumentComponentsUsedPassByValueTrueTest"; + } + +private: + std::vector _components{}; + std::vector _expected_vars{}; +}; + +class CLTensorArgumentStoragesUsedTest : public ITest +{ +public: + const DataType dt = DataType::Fp32; + const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } }); + const std::string tensor_name = "src"; + + CLTensorArgumentStoragesUsedTest() + { + _storages.push_back(TensorStorageType::BufferUint8Ptr); + _storages.push_back(TensorStorageType::Texture2dReadOnly); + _storages.push_back(TensorStorageType::BufferUint8Ptr); // Repeat the query. The TensorArgument should not create a new variable + + _expected_vars.push_back("src_ptr"); + _expected_vars.push_back("src_img2d"); + } + + bool run() override + { + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1); + + const size_t num_storages = _storages.size(); + + int32_t test_idx = 0; + + CLTensorArgument arg(tensor_name, info, true /* return_dims_by_value */); + for(size_t i = 0; i < num_storages; ++i) + { + arg.storage(_storages[i]); + } + + const auto actual_vars = arg.storages(); + + const size_t num_vars = _expected_vars.size(); + + VALIDATE_ON_MSG(actual_vars.size() == num_vars, "The number of variables must match the number of expected variables"); + + for(size_t i = 0; i < num_vars; ++i) + { + // Validate variable name + const std::string expected_var_name = _expected_vars[i]; + const std::string actual_var_name = actual_vars[i].val; + VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++); + + // Validate storage type + const std::string expected_var_type = cl_get_variable_storagetype_as_string(_storages[i]); + const std::string actual_var_type = actual_vars[i].type; + VALIDATE_TEST(actual_var_type == expected_var_type, all_tests_passed, test_idx++); + } + return all_tests_passed; + } + + std::string name() override + { + return "CLTensorArgumentStoragesUsedTest"; + } + +private: + std::vector _storages{}; + std::vector _expected_vars{}; +}; + +class CLTensorArgumentComponentsUsedPassByValueTrueDynamicDimTrueTest : public ITest +{ +public: + const DataType dt = DataType::Fp32; + const TensorShape shape = TensorShape({ { -1, -1, 3, 1, 2 } }); + const std::string tensor_name = "src"; + + CLTensorArgumentComponentsUsedPassByValueTrueDynamicDimTrueTest() + { + _components.push_back(TensorComponentType::Dim0); + _components.push_back(TensorComponentType::Dim2); + _components.push_back(TensorComponentType::Dim3); + _components.push_back(TensorComponentType::Dim1xDim2); + _components.push_back(TensorComponentType::OffsetFirstElement); + _components.push_back(TensorComponentType::Stride1); + _components.push_back(TensorComponentType::Stride2); + _components.push_back(TensorComponentType::Stride3); + _components.push_back(TensorComponentType::OffsetFirstElement); // Repeat the query. The TensorArgument should not create a new variable + _components.push_back(TensorComponentType::Stride1); // Repeat the query. The TensorArgument should not create a new variable + + _expected_vars.push_back("src_dim0"); + _expected_vars.push_back("src_dim1xdim2"); + _expected_vars.push_back("src_offset_first_element"); + _expected_vars.push_back("src_stride1"); + _expected_vars.push_back("src_stride2"); + _expected_vars.push_back("src_stride3"); + } + + bool run() override + { + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1); + + const size_t num_components = _components.size(); + + int32_t test_idx = 0; + + CLTensorArgument arg(tensor_name, info, true /* return_dims_by_value */); + for(size_t i = 0; i < num_components; ++i) + { + arg.component(_components[i]); + } + + const auto actual_vars = arg.components(); + + const size_t num_vars = _expected_vars.size(); + + VALIDATE_ON_MSG(actual_vars.size() == num_vars, "The number of variables must match the number of expected variables"); + + // Since the dimensions are passed by value, we expect only the variables for the strides + for(size_t i = 0; i < num_vars; ++i) + { + // Validate variable name + const std::string expected_var_name = _expected_vars[i]; + const std::string actual_var_name = actual_vars[i].str; + VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++); + + // Validate data type + const DataType expected_var_type = DataType::Int32; + const DataType actual_var_type = actual_vars[i].desc.dt; + VALIDATE_TEST(actual_var_type == expected_var_type, all_tests_passed, test_idx++); + + // Validate data type length + const int32_t expected_var_len = 1; + const int32_t actual_var_len = actual_vars[i].desc.len; + VALIDATE_TEST(actual_var_len == expected_var_len, all_tests_passed, test_idx++); + } + return all_tests_passed; + } + + std::string name() override + { + return "CLTensorArgumentComponentsUsedPassByValueTrueDynamicDimTrueTest"; + } + +private: + std::vector _components{}; + std::vector _expected_vars{}; +}; +} // namespace ckw + +#endif // CKW_TESTS_CLTENSORARGUMENTTEST_H diff --git a/compute_kernel_writer/validation/tests/TensorBitMaskTest.h b/compute_kernel_writer/validation/tests/TensorBitMaskTest.h new file mode 100644 index 0000000000..759d926d18 --- /dev/null +++ b/compute_kernel_writer/validation/tests/TensorBitMaskTest.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef CKW_TESTS_TENSORBITMASKTEST_H +#define CKW_TESTS_TENSORBITMASKTEST_H + +#include "ckw/TensorInfo.h" +#include "ckw/types/TensorComponentType.h" +#include "common/Common.h" +#include "src/types/TensorComponentType.h" + +#include + +namespace ckw +{ +class TensorBitMaskTrueTest : public ITest +{ +public: + TensorBitMaskTrueTest() + { + _component.push_back(TensorComponentType::Dim0); + _component.push_back(TensorComponentType::Dim1); + _component.push_back(TensorComponentType::Dim2); + _component.push_back(TensorComponentType::Dim3); + _component.push_back(TensorComponentType::Dim4); + _component.push_back(TensorComponentType::Stride0); + _component.push_back(TensorComponentType::Stride1); + _component.push_back(TensorComponentType::Stride2); + _component.push_back(TensorComponentType::Stride3); + _component.push_back(TensorComponentType::Stride4); + _component.push_back(TensorComponentType::Dim1xDim2); + _component.push_back(TensorComponentType::Dim1xDim2xDim3); + _component.push_back(TensorComponentType::Dim2xDim3); + _component.push_back(TensorComponentType::OffsetFirstElement); + + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + } + + bool run() override + { + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + VALIDATE_ON_MSG(_component.size() == _bitmask.size(), + "The number of layouts and components does not match"); + const size_t num_tests = _component.size(); + for(size_t i = 0; i < num_tests; ++i) + { + const TensorComponentType component = _component[i]; + const TensorComponentBitmask bitmask = _bitmask[i]; + const bool out = static_cast(component) & static_cast(bitmask); + VALIDATE_TEST(out == true, all_tests_passed, i); + } + return all_tests_passed; + } + + std::string name() override + { + return "TensorBitMaskTrueTest"; + } + +private: + std::vector _component{}; + std::vector _bitmask{}; +}; + +class TensorBitMaskFalseTest : public ITest +{ +public: + TensorBitMaskFalseTest() + { + _component.push_back(TensorComponentType::Dim0); + _component.push_back(TensorComponentType::Dim1); + _component.push_back(TensorComponentType::Dim2); + _component.push_back(TensorComponentType::Dim3); + _component.push_back(TensorComponentType::Dim4); + _component.push_back(TensorComponentType::Dim0); + _component.push_back(TensorComponentType::Dim1); + _component.push_back(TensorComponentType::Dim2); + _component.push_back(TensorComponentType::Dim3); + _component.push_back(TensorComponentType::Dim4); + _component.push_back(TensorComponentType::Dim0); + _component.push_back(TensorComponentType::Dim1); + _component.push_back(TensorComponentType::Dim2); + _component.push_back(TensorComponentType::Dim3); + _component.push_back(TensorComponentType::Dim4); + _component.push_back(TensorComponentType::Stride0); + _component.push_back(TensorComponentType::Stride1); + _component.push_back(TensorComponentType::Stride2); + _component.push_back(TensorComponentType::Stride3); + _component.push_back(TensorComponentType::Stride4); + _component.push_back(TensorComponentType::Stride0); + _component.push_back(TensorComponentType::Stride1); + _component.push_back(TensorComponentType::Stride2); + _component.push_back(TensorComponentType::Stride3); + _component.push_back(TensorComponentType::Stride4); + _component.push_back(TensorComponentType::Stride0); + _component.push_back(TensorComponentType::Stride1); + _component.push_back(TensorComponentType::Stride2); + _component.push_back(TensorComponentType::Stride3); + _component.push_back(TensorComponentType::Stride4); + _component.push_back(TensorComponentType::Dim1xDim2); + _component.push_back(TensorComponentType::Dim1xDim2xDim3); + _component.push_back(TensorComponentType::Dim2xDim3); + _component.push_back(TensorComponentType::Dim1xDim2); + _component.push_back(TensorComponentType::Dim1xDim2xDim3); + _component.push_back(TensorComponentType::Dim2xDim3); + _component.push_back(TensorComponentType::Dim1xDim2); + _component.push_back(TensorComponentType::Dim1xDim2xDim3); + _component.push_back(TensorComponentType::Dim2xDim3); + _component.push_back(TensorComponentType::OffsetFirstElement); + _component.push_back(TensorComponentType::OffsetFirstElement); + _component.push_back(TensorComponentType::OffsetFirstElement); + + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); + _bitmask.push_back(TensorComponentBitmask::Dimension); + _bitmask.push_back(TensorComponentBitmask::Stride); + _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); + } + + bool run() override + { + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + VALIDATE_ON_MSG(_component.size() == _bitmask.size(), + "The number of layouts and components does not match"); + const size_t num_tests = _component.size(); + for(size_t i = 0; i < num_tests; ++i) + { + const TensorComponentType component = _component[i]; + const TensorComponentBitmask bitmask = _bitmask[i]; + const bool out = static_cast(component) & static_cast(bitmask); + VALIDATE_TEST(out == false, all_tests_passed, i); + } + return all_tests_passed; + } + + std::string name() override + { + return "TensorBitMaskFalseTest"; + } + +private: + std::vector _component{}; + std::vector _bitmask{}; +}; +} // namespace ckw + +#endif // CKW_TESTS_TENSORBITMASKTEST_H diff --git a/compute_kernel_writer/validation/tests/TensorBitMaskTest.hpp b/compute_kernel_writer/validation/tests/TensorBitMaskTest.hpp deleted file mode 100644 index 1e7d003879..0000000000 --- a/compute_kernel_writer/validation/tests/TensorBitMaskTest.hpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2023 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef COMPUTE_KERNEL_WRITER_TESTS_TENSORBITMASK_HPP -#define COMPUTE_KERNEL_WRITER_TESTS_TENSORBITMASK_HPP - -#include "ckw/TensorInfo.h" -#include "common/Common.h" - -#include - -namespace ckw -{ -class TensorBitMaskTrueTest : public ITest -{ -public: - TensorBitMaskTrueTest() - { - _component.push_back(TensorComponent::Dim0); - _component.push_back(TensorComponent::Dim1); - _component.push_back(TensorComponent::Dim2); - _component.push_back(TensorComponent::Dim3); - _component.push_back(TensorComponent::Dim4); - _component.push_back(TensorComponent::Stride0); - _component.push_back(TensorComponent::Stride1); - _component.push_back(TensorComponent::Stride2); - _component.push_back(TensorComponent::Stride3); - _component.push_back(TensorComponent::Stride4); - _component.push_back(TensorComponent::Dim1xDim2); - _component.push_back(TensorComponent::Dim1xDim2xDim3); - _component.push_back(TensorComponent::Dim2xDim3); - _component.push_back(TensorComponent::OffsetFirstElement); - - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - } - - bool run() override - { - // The status of this variable can change in VALIDATE_TEST() - bool all_tests_passed = true; - - VALIDATE_ON_MSG(_component.size() == _bitmask.size(), - "The number of layouts and components does not match"); - const size_t num_tests = _component.size(); - for(size_t i = 0; i < num_tests; ++i) - { - const TensorComponent component = _component[i]; - const TensorComponentBitmask bitmask = _bitmask[i]; - const bool out = static_cast(component) & static_cast(bitmask); - VALIDATE_TEST(out == true, all_tests_passed, i); - } - return all_tests_passed; - } - - std::string name() override - { - return "TensorBitMaskTrueTest"; - } - -private: - std::vector _component{}; - std::vector _bitmask{}; -}; - -class TensorBitMaskFalseTest : public ITest -{ -public: - TensorBitMaskFalseTest() - { - _component.push_back(TensorComponent::Dim0); - _component.push_back(TensorComponent::Dim1); - _component.push_back(TensorComponent::Dim2); - _component.push_back(TensorComponent::Dim3); - _component.push_back(TensorComponent::Dim4); - _component.push_back(TensorComponent::Dim0); - _component.push_back(TensorComponent::Dim1); - _component.push_back(TensorComponent::Dim2); - _component.push_back(TensorComponent::Dim3); - _component.push_back(TensorComponent::Dim4); - _component.push_back(TensorComponent::Dim0); - _component.push_back(TensorComponent::Dim1); - _component.push_back(TensorComponent::Dim2); - _component.push_back(TensorComponent::Dim3); - _component.push_back(TensorComponent::Dim4); - _component.push_back(TensorComponent::Stride0); - _component.push_back(TensorComponent::Stride1); - _component.push_back(TensorComponent::Stride2); - _component.push_back(TensorComponent::Stride3); - _component.push_back(TensorComponent::Stride4); - _component.push_back(TensorComponent::Stride0); - _component.push_back(TensorComponent::Stride1); - _component.push_back(TensorComponent::Stride2); - _component.push_back(TensorComponent::Stride3); - _component.push_back(TensorComponent::Stride4); - _component.push_back(TensorComponent::Stride0); - _component.push_back(TensorComponent::Stride1); - _component.push_back(TensorComponent::Stride2); - _component.push_back(TensorComponent::Stride3); - _component.push_back(TensorComponent::Stride4); - _component.push_back(TensorComponent::Dim1xDim2); - _component.push_back(TensorComponent::Dim1xDim2xDim3); - _component.push_back(TensorComponent::Dim2xDim3); - _component.push_back(TensorComponent::Dim1xDim2); - _component.push_back(TensorComponent::Dim1xDim2xDim3); - _component.push_back(TensorComponent::Dim2xDim3); - _component.push_back(TensorComponent::Dim1xDim2); - _component.push_back(TensorComponent::Dim1xDim2xDim3); - _component.push_back(TensorComponent::Dim2xDim3); - _component.push_back(TensorComponent::OffsetFirstElement); - _component.push_back(TensorComponent::OffsetFirstElement); - _component.push_back(TensorComponent::OffsetFirstElement); - - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement); - _bitmask.push_back(TensorComponentBitmask::Dimension); - _bitmask.push_back(TensorComponentBitmask::Stride); - _bitmask.push_back(TensorComponentBitmask::FoldedDimensions); - } - - bool run() override - { - // The status of this variable can change in VALIDATE_TEST() - bool all_tests_passed = true; - - VALIDATE_ON_MSG(_component.size() == _bitmask.size(), - "The number of layouts and components does not match"); - const size_t num_tests = _component.size(); - for(size_t i = 0; i < num_tests; ++i) - { - const TensorComponent component = _component[i]; - const TensorComponentBitmask bitmask = _bitmask[i]; - const bool out = static_cast(component) & static_cast(bitmask); - VALIDATE_TEST(out == false, all_tests_passed, i); - } - return all_tests_passed; - } - - std::string name() override - { - return "TensorBitMaskFalseTest"; - } - -private: - std::vector _component{}; - std::vector _bitmask{}; -}; -} // namespace ckw - -#endif /* COMPUTE_KERNEL_WRITER_TESTS_TENSORBITMASK_HPP */ diff --git a/compute_kernel_writer/validation/tests/UtilsTest.h b/compute_kernel_writer/validation/tests/UtilsTest.h new file mode 100644 index 0000000000..a335a48f81 --- /dev/null +++ b/compute_kernel_writer/validation/tests/UtilsTest.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef CKW_TESTS_UTILSTEST_H +#define CKW_TESTS_UTILSTEST_H + +#include "ckw/TensorInfo.h" +#include "ckw/types/TensorDataLayout.h" +#include "common/Common.h" +#include "src/TensorUtils.h" + +#include + +namespace ckw +{ +class UtilsTest : public ITest +{ +public: + UtilsTest() + { + _layout.push_back(TensorDataLayout::Nhwc); + _layout.push_back(TensorDataLayout::Nhwc); + _layout.push_back(TensorDataLayout::Nhwc); + _layout.push_back(TensorDataLayout::Nhwc); + _layout.push_back(TensorDataLayout::Ndhwc); + _layout.push_back(TensorDataLayout::Ndhwc); + _layout.push_back(TensorDataLayout::Ndhwc); + _layout.push_back(TensorDataLayout::Ndhwc); + _layout.push_back(TensorDataLayout::Ndhwc); + + _component.push_back(TensorDataLayoutComponent::N); + _component.push_back(TensorDataLayoutComponent::H); + _component.push_back(TensorDataLayoutComponent::W); + _component.push_back(TensorDataLayoutComponent::C); + _component.push_back(TensorDataLayoutComponent::N); + _component.push_back(TensorDataLayoutComponent::D); + _component.push_back(TensorDataLayoutComponent::H); + _component.push_back(TensorDataLayoutComponent::W); + _component.push_back(TensorDataLayoutComponent::C); + + _expected.push_back(TensorComponentType::Dim3); + _expected.push_back(TensorComponentType::Dim2); + _expected.push_back(TensorComponentType::Dim1); + _expected.push_back(TensorComponentType::Dim0); + _expected.push_back(TensorComponentType::Dim4); + _expected.push_back(TensorComponentType::Dim3); + _expected.push_back(TensorComponentType::Dim2); + _expected.push_back(TensorComponentType::Dim1); + _expected.push_back(TensorComponentType::Dim0); + } + + bool run() override + { + // The status of this variable can change in VALIDATE_TEST() + bool all_tests_passed = true; + + VALIDATE_ON_MSG(_layout.size() == _component.size(), "The number of layouts and components does not match"); + VALIDATE_ON_MSG(_layout.size() == _expected.size(), + "The number of layouts and expected outputs does not match"); + const size_t num_tests = _layout.size(); + for(size_t i = 0; i < num_tests; ++i) + { + const TensorDataLayout layout = _layout[i]; + const TensorDataLayoutComponent component = _component[i]; + const TensorComponentType expected = _expected[i]; + const TensorComponentType out = get_tensor_dimension(layout, component); + VALIDATE_TEST(out == expected, all_tests_passed, i); + } + return all_tests_passed; + } + + std::string name() override + { + return "UtilsTest"; + } + +private: + std::vector _layout{}; + std::vector _component{}; + std::vector _expected{}; +}; +} // namespace ckw + +#endif // CKW_TESTS_UTILSTEST_H diff --git a/compute_kernel_writer/validation/tests/UtilsTest.hpp b/compute_kernel_writer/validation/tests/UtilsTest.hpp deleted file mode 100644 index db1c8fd4ae..0000000000 --- a/compute_kernel_writer/validation/tests/UtilsTest.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2023 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef COMPUTE_KERNEL_WRITER_TESTS_UTILSTEST_HPP -#define COMPUTE_KERNEL_WRITER_TESTS_UTILSTEST_HPP - -#include "ckw/TensorInfo.h" -#include "common/Common.h" -#include "src/TensorUtils.h" - -#include - -namespace ckw -{ -class UtilsTest : public ITest -{ -public: - UtilsTest() - { - _layout.push_back(TensorDataLayout::Nhwc); - _layout.push_back(TensorDataLayout::Nhwc); - _layout.push_back(TensorDataLayout::Nhwc); - _layout.push_back(TensorDataLayout::Nhwc); - _layout.push_back(TensorDataLayout::Ndhwc); - _layout.push_back(TensorDataLayout::Ndhwc); - _layout.push_back(TensorDataLayout::Ndhwc); - _layout.push_back(TensorDataLayout::Ndhwc); - _layout.push_back(TensorDataLayout::Ndhwc); - - _component.push_back(TensorDataLayoutComponent::N); - _component.push_back(TensorDataLayoutComponent::H); - _component.push_back(TensorDataLayoutComponent::W); - _component.push_back(TensorDataLayoutComponent::C); - _component.push_back(TensorDataLayoutComponent::N); - _component.push_back(TensorDataLayoutComponent::D); - _component.push_back(TensorDataLayoutComponent::H); - _component.push_back(TensorDataLayoutComponent::W); - _component.push_back(TensorDataLayoutComponent::C); - - _expected.push_back(TensorComponent::Dim3); - _expected.push_back(TensorComponent::Dim2); - _expected.push_back(TensorComponent::Dim1); - _expected.push_back(TensorComponent::Dim0); - _expected.push_back(TensorComponent::Dim4); - _expected.push_back(TensorComponent::Dim3); - _expected.push_back(TensorComponent::Dim2); - _expected.push_back(TensorComponent::Dim1); - _expected.push_back(TensorComponent::Dim0); - } - - bool run() override - { - // The status of this variable can change in VALIDATE_TEST() - bool all_tests_passed = true; - - VALIDATE_ON_MSG(_layout.size() == _component.size(), "The number of layouts and components does not match"); - VALIDATE_ON_MSG(_layout.size() == _expected.size(), - "The number of layouts and expected outputs does not match"); - const size_t num_tests = _layout.size(); - for(size_t i = 0; i < num_tests; ++i) - { - const TensorDataLayout layout = _layout[i]; - const TensorDataLayoutComponent component = _component[i]; - const TensorComponent expected = _expected[i]; - const TensorComponent out = get_tensor_dimension(layout, component); - VALIDATE_TEST(out == expected, all_tests_passed, i); - } - return all_tests_passed; - } - - std::string name() override - { - return "UtilsTest"; - } - -private: - std::vector _layout{}; - std::vector _component{}; - std::vector _expected{}; -}; -} // namespace ckw - -#endif /* COMPUTE_KERNEL_WRITER_TESTS_UTILSTEST_HPP */ -- cgit v1.2.1