From 3d7cb8a0dadc1e4dd2e3fa2a5e57dbf14767b27d Mon Sep 17 00:00:00 2001 From: Istvan Stefan Date: Tue, 9 Jan 2024 17:46:56 +0100 Subject: [PATCH 1/2] [test] Add multi-channel support to framework --- test/framework/array.h | 4 ++-- test/framework/kernel.h | 3 +-- test/framework/operation.h | 4 ++-- test/framework/test_array2d.cpp | 12 ++++++------ test/framework/test_border.cpp | 4 ++-- test/framework/test_kernel.cpp | 2 +- test/framework/utils.cpp | 16 ++++++++-------- 7 files changed, 22 insertions(+), 23 deletions(-) diff --git a/test/framework/array.h b/test/framework/array.h index 2cb2a2efa..16878d6b8 100644 --- a/test/framework/array.h +++ b/test/framework/array.h @@ -37,10 +37,10 @@ class Array2D : public TwoDimensional { : Array2D(layout.width, layout.height, layout.padding, layout.channels) {} explicit Array2D(size_t width, size_t height, size_t padding, size_t channels) - : width_{width}, + : width_{width * channels}, height_{height}, channels_{channels}, - stride_{width * sizeof(ElementType) + padding} { + stride_{width * sizeof(ElementType) * channels + padding} { try_allocate(); fill_padding(); } diff --git a/test/framework/kernel.h b/test/framework/kernel.h index d88e63053..ba06efd6b 100644 --- a/test/framework/kernel.h +++ b/test/framework/kernel.h @@ -186,8 +186,7 @@ class KernelTest { ASSERT_TRUE(actual_.valid()); input_with_borders_ = Array2D{ - array_layout.width + - (kernel.left() + kernel.right()) * array_layout.channels, + array_layout.width + (kernel.left() + kernel.right()), array_layout.height + kernel.top() + kernel.bottom(), 0, array_layout.channels}; ASSERT_TRUE(input_with_borders_.valid()); diff --git a/test/framework/operation.h b/test/framework/operation.h index a69b47aa2..896b456cb 100644 --- a/test/framework/operation.h +++ b/test/framework/operation.h @@ -33,7 +33,7 @@ class OperationTest { return *this; } - void test() { + virtual void test() { for (auto& input : inputs_) { input = ArrayType{width(), height(), padding()}; ASSERT_TRUE(input.valid()); @@ -59,7 +59,7 @@ class OperationTest { virtual const std::vector& test_elements() = 0; /// Prepares inputs and expected outputs for the operation. - void setup() { + virtual void setup() { auto elements_list = test_elements(); // Check that the number of elements fit into the buffers. ASSERT_LE(elements_list.size(), height()); diff --git a/test/framework/test_array2d.cpp b/test/framework/test_array2d.cpp index 7aed9667a..617c231de 100644 --- a/test/framework/test_array2d.cpp +++ b/test/framework/test_array2d.cpp @@ -45,10 +45,10 @@ TEST(Array2D, ConstructFromArrayLayout) { size_t width = 1, height = 2, padding = 3, channels = 4; test::ArrayLayout layout{width, height, padding, channels}; test::Array2D array{layout}; - EXPECT_EQ(array.width(), width); + EXPECT_EQ(array.width(), width * channels); EXPECT_EQ(array.height(), height); EXPECT_EQ(array.channels(), channels); - EXPECT_EQ(array.stride(), width * sizeof(ElementType) + padding); + EXPECT_EQ(array.stride(), width * sizeof(ElementType) * channels + padding); EXPECT_TRUE(array.valid()); } @@ -69,10 +69,10 @@ TEST(Array2D, MoveAssignment) { test::Array2D array_2; array_2 = std::move(array_1); - EXPECT_EQ(array_2.width(), width); + EXPECT_EQ(array_2.width(), width * channels); EXPECT_EQ(array_2.height(), height); EXPECT_EQ(array_2.channels(), channels); - EXPECT_EQ(array_2.stride(), width * sizeof(uint32_t)); + EXPECT_EQ(array_2.stride(), width * sizeof(uint32_t) * channels); EXPECT_TRUE(array_2.valid()); EXPECT_EQ(array_1.width(), 0); @@ -270,7 +270,7 @@ TEST(Array2D, ExpectEq_NotEqual_Channels) { struct Test { static void test() { size_t width = 5, height = 2; - test::Array2D array_1{width, height, 0, 1}; + test::Array2D array_1{width * 2, height, 0, 1}; test::Array2D array_2{width, height, 0, 2}; EXPECT_EQ_ARRAY2D(array_1, array_2); } @@ -346,7 +346,7 @@ TEST(Array2D, ExpectNe_NotEqual_Channels) { struct Test { static void test() { size_t width = 5, height = 2; - test::Array2D array_1{width, height, 0, 1}; + test::Array2D array_1{width * 2, height, 0, 1}; test::Array2D array_2{width, height, 0, 2}; EXPECT_NE_ARRAY2D(array_1, array_2); } diff --git a/test/framework/test_border.cpp b/test/framework/test_border.cpp index ebbf03fc1..71d6cf830 100644 --- a/test/framework/test_border.cpp +++ b/test/framework/test_border.cpp @@ -87,7 +87,7 @@ TEST(Border, Replicate_1Ch_2Elements) { TEST(Border, Replicate_2Ch_1Element) { using ElementType = uint8_t; - const size_t width = 8, height = 5, channels = 2; + const size_t width = 4, height = 5, channels = 2; test::Array2D actual{width, height, 0, channels}; actual.set(0, 0, {0, 0, 0, 0, 0, 0, 0, 0}); @@ -114,7 +114,7 @@ TEST(Border, Replicate_2Ch_1Element) { TEST(Border, Replicate_2Ch_2Elements) { using ElementType = uint8_t; - const size_t width = 12, height = 6, channels = 2; + const size_t width = 6, height = 6, channels = 2; test::Array2D actual{width, height, 0, channels}; actual.set(0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); diff --git a/test/framework/test_kernel.cpp b/test/framework/test_kernel.cpp index 2818859a7..21dc85d82 100644 --- a/test/framework/test_kernel.cpp +++ b/test/framework/test_kernel.cpp @@ -108,7 +108,7 @@ class ExampleKernelTest : public test::KernelTest { const test::ArrayLayout &expected_array_layout = kArrayLayouts[array_layouts_ % kArrayLayouts.size()]; - EXPECT_EQ(expected_array_layout.width, input->width()); + EXPECT_EQ(expected_array_layout.width * input->channels(), input->width()); EXPECT_EQ(expected_array_layout.height, input->height()); EXPECT_EQ(expected_array_layout.padding, input->stride() - input->width() * sizeof(InputType)); diff --git a/test/framework/utils.cpp b/test/framework/utils.cpp index 0640bb2e0..4a41cb492 100644 --- a/test/framework/utils.cpp +++ b/test/framework/utils.cpp @@ -57,17 +57,17 @@ std::array default_array_layouts(size_t min_width, // clang-format off // width, height, padding, channels { min_width, min_height, 0, 1}, - { min_width * 2, min_height, 0, 2}, - { min_width * 3, min_height, 0, 3}, + { min_width , min_height, 0, 2}, + { min_width , min_height, 0, 3}, { min_width, min_height, vl, 1}, - { min_width * 2, min_height, vl, 2}, - { min_width * 3, min_height, vl, 3}, + { min_width , min_height, vl, 2}, + { min_width , min_height, vl, 3}, { width - 1, min_height, 0, 1}, - {2 * (width - 1), min_height + 1, 0, 2}, - {3 * (width - 1), min_height + 2, 0, 3}, + { (width - 1), min_height + 1, 0, 2}, + { (width - 1), min_height + 2, 0, 3}, { width - 1, min_height, vl, 1}, - {2 * (width - 1), min_height + 1, vl, 2}, - {3 * (width - 1), min_height + 2, vl, 3}, + { (width - 1), min_height + 1, vl, 2}, + { (width - 1), min_height + 2, vl, 3}, // clang-format on }}; } -- GitLab From 9a53ef8d8ca242f42b88b4b02882fa15da0a9f50 Mon Sep 17 00:00:00 2001 From: Istvan Stefan Date: Thu, 11 Jan 2024 11:00:34 +0100 Subject: [PATCH 2/2] [test] Implementation of tests for merge and split --- test/api/test_merge.cpp | 126 ++++++++++++++++++++++++++++++++++++++++ test/api/test_split.cpp | 118 +++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 test/api/test_merge.cpp create mode 100644 test/api/test_split.cpp diff --git a/test/api/test_merge.cpp b/test/api/test_merge.cpp new file mode 100644 index 000000000..887fbbd8d --- /dev/null +++ b/test/api/test_merge.cpp @@ -0,0 +1,126 @@ +// SPDX-FileCopyrightText: 2023 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include + +#include "framework/operation.h" + +template +class MergeOperation : public OperationTest {}; + +template +class MergeTest final : public MergeOperation { + /// Expose constructor of base class. + using MergeOperation::MergeOperation; + using ArrayType = test::Array2D; + + public: + MergeTest() : channelnumber_(ChannelNumber) {} + + void test() override { + for (auto& input : this->inputs_) { + input = ArrayType{this->width(), this->height(), this->padding()}; + ASSERT_TRUE(input.valid()); + } + + for (auto& expected : this->expected_) { + expected = ArrayType{this->width(), this->height(), this->padding(), + channelnumber()}; + ASSERT_TRUE(expected.valid()); + } + for (auto& actual : this->actual_) { + actual = ArrayType{this->width(), this->height(), this->padding(), + channelnumber()}; + ASSERT_TRUE(actual.valid()); + } + + this->setup(); + call_api(); + this->check(); + } + + protected: + using Elements = typename MergeOperation::Elements; + + /// Calls the API-under-test in the appropriate way. + void call_api() override { + const ElementType* srcs[] = { + this->inputs_[0].data(), this->inputs_[1].data(), + this->inputs_[2].data(), this->inputs_[3].data()}; + const size_t src_strides[] = { + this->inputs_[0].stride(), this->inputs_[1].stride(), + this->inputs_[2].stride(), this->inputs_[3].stride()}; + + intrinsiccv_merge(reinterpret_cast(srcs), src_strides, + this->actual_[0].data(), this->actual_[0].stride(), + this->width(), this->height(), channelnumber(), + sizeof(ElementType)); + } + + /// Returns different test data. + const std::vector& test_elements() override { + static const std::vector kTestElements = {{1, 2, 3, 4}}; + return kTestElements; + } + + /// Prepares inputs and expected output for the operation. + void setup() override { + auto elements_list = test_elements(); + // Check that the number of elements fit into the buffers. + ASSERT_LE(elements_list.size(), this->height()); + + size_t row_index = 0; + for (auto elements : elements_list) { + // Fill elements one by one. + for (size_t column_index = 0; column_index < this->width(); + ++column_index) { + for (size_t index = 0; index < channelnumber(); ++index) { + this->inputs_[index].set( + row_index, column_index, + {static_cast( + row_index + elements.values[index % channelnumber()])}); + } + } + for (size_t column_index = 0; + column_index < this->width() * channelnumber(); ++column_index) { + for (size_t index = 0; index < channelnumber(); ++index) { + this->expected_[0].set( + row_index, column_index, + {static_cast( + row_index + + elements.values[column_index % channelnumber()])}); + } + } + + // Increment loop counter. + ++row_index; + } + } + // Returns the number of channel of the output. + size_t channelnumber() const { return channelnumber_; } + + private: + size_t channelnumber_; +}; // end of class MergeTest + +template +class Merge : public testing::Test {}; + +using ElementTypes = ::testing::Types; +TYPED_TEST_SUITE(Merge, ElementTypes); + +/// Tests \ref intrinsiccv_merge API. +TYPED_TEST(Merge, API) { + // Test without padding. + MergeTest{}.test(); + MergeTest{}.test(); + MergeTest{}.test(); + // Test with padding. + MergeTest{}.with_padding(test::Options::vector_length()).test(); + MergeTest{}.with_padding(test::Options::vector_length()).test(); + MergeTest{}.with_padding(test::Options::vector_length()).test(); +} diff --git a/test/api/test_split.cpp b/test/api/test_split.cpp new file mode 100644 index 000000000..550c02055 --- /dev/null +++ b/test/api/test_split.cpp @@ -0,0 +1,118 @@ +// SPDX-FileCopyrightText: 2023 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include + +#include "framework/operation.h" + +template +class SplitOperation : public OperationTest {}; + +template +class SplitTest final : public SplitOperation { + /// Expose constructor of base class. + using SplitOperation::SplitOperation; + using ArrayType = test::Array2D; + + public: + SplitTest() : channelnumber_(ChannelNumber) {} + + void test() override { + for (auto& input : this->inputs_) { + input = ArrayType{this->width(), this->height(), this->padding(), + channelnumber()}; + ASSERT_TRUE(input.valid()); + } + + for (auto& expected : this->expected_) { + expected = ArrayType{this->width(), this->height(), this->padding()}; + ASSERT_TRUE(expected.valid()); + } + for (auto& actual : this->actual_) { + actual = ArrayType{this->width(), this->height(), this->padding()}; + ASSERT_TRUE(actual.valid()); + } + + this->setup(); + call_api(); + this->check(); + } + + protected: + using Elements = typename SplitOperation::Elements; + + /// Calls the API-under-test in the appropriate way. + void call_api() override { + ElementType* dsts[] = {this->actual_[0].data(), this->actual_[1].data(), + this->actual_[2].data(), this->actual_[3].data()}; + size_t dst_strides[] = { + this->actual_[0].stride(), this->actual_[1].stride(), + this->actual_[2].stride(), this->actual_[3].stride()}; + + intrinsiccv_split(this->inputs_[0].data(), this->inputs_[0].stride(), + reinterpret_cast(dsts), dst_strides, + this->width(), this->height(), channelnumber(), + sizeof(ElementType)); + } + + /// Returns different test data for signed and unsigned element types. + const std::vector& test_elements() override { + static const std::vector kTestElements = {{1, 2, 3, 4}}; + return kTestElements; + } + + /// Prepares inputs and expected outputs for the operation. + void setup() override { + auto elements_list = test_elements(); + // Check that the number of elements fit into the buffers. + ASSERT_LE(elements_list.size(), this->height()); + + size_t row_index = 0; + for (auto elements : elements_list) { + // Fill elements one by one. + for (size_t column_index = 0; column_index < this->inputs_[0].width(); + ++column_index) { + this->inputs_[0].set(row_index, column_index, + {elements.values[column_index % channelnumber()]}); + } + for (size_t column_index = 0; column_index < this->expected_[0].width(); + ++column_index) { + for (size_t index = 0; index < channelnumber(); ++index) { + this->expected_[index].set( + row_index, column_index, + {elements.values[index % channelnumber()]}); + } + } + + // Increment loop counter. + ++row_index; + } + } + // Returns the number of channel of the output. + size_t channelnumber() const { return channelnumber_; } + + private: + size_t channelnumber_; +}; // end of class MergeTest + +template +class Split : public testing::Test {}; + +using ElementTypes = ::testing::Types; +TYPED_TEST_SUITE(Split, ElementTypes); + +// /// Tests \ref intrinsiccv_merge API. +TYPED_TEST(Split, API) { + // Test without padding. + SplitTest{}.test(); + SplitTest{}.test(); + SplitTest{}.test(); + // Test with padding. + SplitTest{}.with_padding(test::Options::vector_length()).test(); + SplitTest{}.with_padding(test::Options::vector_length()).test(); + SplitTest{}.with_padding(test::Options::vector_length()).test(); +} -- GitLab