From d5ef6338663e5f42f81835a90112f894f5f545f5 Mon Sep 17 00:00:00 2001 From: Mark Horvath Date: Mon, 23 Sep 2024 22:20:24 +0200 Subject: [PATCH] Speed up conformity tests Lower the number of iterations for the long running operations. --- conformity/opencv/CMakeLists.txt | 2 + conformity/opencv/test_gaussian_blur.cpp | 83 +++++++++---------- conformity/opencv/test_in_range.cpp | 20 ++--- conformity/opencv/test_rgb2yuv.cpp | 24 +++--- conformity/opencv/test_scale.cpp | 33 ++++---- .../opencv/test_separable_filter_2d.cpp | 82 +++++++++--------- conformity/opencv/test_sobel.cpp | 24 +++--- conformity/opencv/test_yuv2rgb.cpp | 24 +++--- conformity/opencv/utils.cpp | 17 ++++ conformity/opencv/utils.h | 2 + 10 files changed, 157 insertions(+), 154 deletions(-) create mode 100644 conformity/opencv/utils.cpp diff --git a/conformity/opencv/CMakeLists.txt b/conformity/opencv/CMakeLists.txt index 3daa88943..85111dc2f 100644 --- a/conformity/opencv/CMakeLists.txt +++ b/conformity/opencv/CMakeLists.txt @@ -32,6 +32,7 @@ add_executable( manager manager.cpp tests.cpp + utils.cpp ${conformity_test_sources} ) @@ -67,6 +68,7 @@ add_executable( subordinate subordinate.cpp tests.cpp + utils.cpp ${conformity_test_sources} ) diff --git a/conformity/opencv/test_gaussian_blur.cpp b/conformity/opencv/test_gaussian_blur.cpp index 776fbec2b..8b189c74e 100644 --- a/conformity/opencv/test_gaussian_blur.cpp +++ b/conformity/opencv/test_gaussian_blur.cpp @@ -6,13 +6,13 @@ #include "tests.h" -template +template cv::Mat exec_gaussian_blur(cv::Mat& input) { double sigma = - *reinterpret_cast(&input.at(input.rows - 2, 0)); + *reinterpret_cast(&input.at(input.rows - 1, 0)); // clone is required, otherwise the result matrix is treated as part of a // bigger image, and it would have impact on what border types are supported - cv::Mat input_mat = input.rowRange(0, input.rows - 2).clone(); + cv::Mat input_mat = input.rowRange(0, input.rows - 1).clone(); cv::Size kernel(KernelSize, KernelSize); cv::Mat result; cv::GaussianBlur(input_mat, result, kernel, sigma, sigma, BorderType); @@ -20,54 +20,47 @@ cv::Mat exec_gaussian_blur(cv::Mat& input) { } #if MANAGER -template bool test_gaussian_blur(int index, RecreatedMessageQueue& request_queue, RecreatedMessageQueue& reply_queue) { cv::RNG rng(0); - size_t size_min = 5; - size_t size_max = 16; - if constexpr (KernelSize == 15) { - size_min = 14; - size_max = 32; - } + // Minimal width is sizeof(double) and one more row is allcated to place the + // value of sigma next to the real input + for (auto size : typical_test_sizes( + std::max(KernelSize - 1, static_cast(sizeof(double))), + KernelSize - 1)) { + cv::Mat input(size.height + 1, size.width, CV_8UC(Channels)); + rng.fill(input, cv::RNG::UNIFORM, 0, 255); + + double sigma = 0.0; + + if constexpr (!Binomial) { + // cv::rng returns [0,1) range in case of float or double, so it is + // multiplied by 10 + sigma = static_cast(rng) * 10; + } + + // sigma is embedded into the input matrix + *reinterpret_cast(&input.at(input.rows - 1, 0)) = sigma; + + cv::Mat actual = exec_gaussian_blur(input); + cv::Mat expected = + get_expected_from_subordinate(index, request_queue, reply_queue, input); + + uint8_t threshold = 0; + // There are currently rounding differences sometimes + // between the OpenCV and KleidiCV implementations that use + // the 15x15 kernel size, so we ignore any non-matching + // values that fall within the specified threshold. + if constexpr (KernelSize == 15) { + threshold = 2; + } - for (size_t y = size_min; y <= size_max; ++y) { - for (size_t x = size_min; x <= size_max; ++x) { - // Two extra lines allocated to be sure sigma can be placed next to the - // real input - cv::Mat input(y + 2, x, CV_8UC(Channels)); - rng.fill(input, cv::RNG::UNIFORM, 0, 255); - - double sigma = 0.0; - - if constexpr (!Binomial) { - // cv::rng returns [0,1) range in case of float or double, so it is - // multiplied by 10 - sigma = static_cast(rng) * 10; - } - - // sigma is embedded into the input matrix - *reinterpret_cast(&input.at(input.rows - 2, 0)) = sigma; - - cv::Mat actual = exec_gaussian_blur(input); - cv::Mat expected = get_expected_from_subordinate(index, request_queue, - reply_queue, input); - - uint8_t threshold = 0; - // There are currently rounding differences sometimes - // between the OpenCV and KleidiCV implementations that use - // the 15x15 kernel size, so we ignore any non-matching - // values that fall within the specified threshold. - if constexpr (KernelSize == 15) { - threshold = 2; - } - - if (are_matrices_different(threshold, actual, expected)) { - fail_print_matrices(y, x, input, actual, expected); - return true; - } + if (are_matrices_different(threshold, actual, expected)) { + fail_print_matrices(size.height, size.width, input, actual, expected); + return true; } } diff --git a/conformity/opencv/test_in_range.cpp b/conformity/opencv/test_in_range.cpp index 315474e05..e3b6aa94e 100644 --- a/conformity/opencv/test_in_range.cpp +++ b/conformity/opencv/test_in_range.cpp @@ -19,18 +19,16 @@ bool test_in_range(int index, RecreatedMessageQueue& request_queue, RecreatedMessageQueue& reply_queue) { cv::RNG rng(0); - for (size_t x = 5; x <= 16; ++x) { - for (size_t y = 5; y <= 16; ++y) { - cv::Mat input(x, y, Format); - rng.fill(input, cv::RNG::UNIFORM, 0, 255); - cv::Mat actual = exec_in_range(input); - cv::Mat expected = get_expected_from_subordinate(index, request_queue, - reply_queue, input); + for (auto size : typical_test_sizes(1, 1)) { + cv::Mat input(size.height, size.width, Format); + rng.fill(input, cv::RNG::UNIFORM, 0, 255); + cv::Mat actual = exec_in_range(input); + cv::Mat expected = + get_expected_from_subordinate(index, request_queue, reply_queue, input); - if (are_matrices_different(0, actual, expected)) { - fail_print_matrices(x, y, input, actual, expected); - return true; - } + if (are_matrices_different(0, actual, expected)) { + fail_print_matrices(size.height, size.width, input, actual, expected); + return true; } } diff --git a/conformity/opencv/test_rgb2yuv.cpp b/conformity/opencv/test_rgb2yuv.cpp index de27c4808..9889f4b71 100644 --- a/conformity/opencv/test_rgb2yuv.cpp +++ b/conformity/opencv/test_rgb2yuv.cpp @@ -23,19 +23,17 @@ bool test_rgb2yuv(int index, RecreatedMessageQueue& request_queue, RecreatedMessageQueue& reply_queue) { cv::RNG rng(0); - for (size_t x = 5; x <= 16; ++x) { - for (size_t y = 5; y <= 16; ++y) { - cv::Mat input(x, y, CV_8UC(Channels)); - rng.fill(input, cv::RNG::UNIFORM, 0, 255); - - cv::Mat actual = exec_rgb2yuv(input); - cv::Mat expected = get_expected_from_subordinate(index, request_queue, - reply_queue, input); - - if (are_matrices_different(0, actual, expected)) { - fail_print_matrices(x, y, input, actual, expected); - return true; - } + for (auto size : typical_test_sizes(1, 1)) { + cv::Mat input(size.height, size.width, CV_8UC(Channels)); + rng.fill(input, cv::RNG::UNIFORM, 0, 255); + + cv::Mat actual = exec_rgb2yuv(input); + cv::Mat expected = + get_expected_from_subordinate(index, request_queue, reply_queue, input); + + if (are_matrices_different(0, actual, expected)) { + fail_print_matrices(size.height, size.width, input, actual, expected); + return true; } } diff --git a/conformity/opencv/test_scale.cpp b/conformity/opencv/test_scale.cpp index bc1614a17..b82d882c4 100644 --- a/conformity/opencv/test_scale.cpp +++ b/conformity/opencv/test_scale.cpp @@ -22,24 +22,23 @@ bool test_scale(int index, RecreatedMessageQueue& request_queue, RecreatedMessageQueue& reply_queue) { cv::RNG rng(0); - for (size_t x = 5; x <= 16; ++x) { - for (size_t y = 5; y <= 16; ++y) { - cv::Mat input_mat(x, y, Format); - rng.fill(input_mat, cv::RNG::NORMAL, 0.0, 1.0e10); - cv::Mat actual_mat = exec_scale(input_mat); - cv::Mat expected_mat = get_expected_from_subordinate( - index, request_queue, reply_queue, input_mat); + for (auto size : typical_test_sizes(1, 1)) { + cv::Mat input_mat(size.height, size.width, Format); + rng.fill(input_mat, cv::RNG::NORMAL, 0.0, 1.0e10); + cv::Mat actual_mat = exec_scale(input_mat); + cv::Mat expected_mat = get_expected_from_subordinate( + index, request_queue, reply_queue, input_mat); - bool success = - (CV_MAT_DEPTH(Format) == CV_32F && - !are_float_matrices_different(1e-5, actual_mat, - expected_mat)) || - (CV_MAT_DEPTH(Format) == CV_8U && - !are_matrices_different(0, actual_mat, expected_mat)); - if (!success) { - fail_print_matrices(x, y, input_mat, actual_mat, expected_mat); - return true; - } + bool success = + (CV_MAT_DEPTH(Format) == CV_32F && + !are_float_matrices_different(1e-5, actual_mat, + expected_mat)) || + (CV_MAT_DEPTH(Format) == CV_8U && + !are_matrices_different(0, actual_mat, expected_mat)); + if (!success) { + fail_print_matrices(size.height, size.width, input_mat, actual_mat, + expected_mat); + return true; } } diff --git a/conformity/opencv/test_separable_filter_2d.cpp b/conformity/opencv/test_separable_filter_2d.cpp index fda861ef8..2979e94c7 100644 --- a/conformity/opencv/test_separable_filter_2d.cpp +++ b/conformity/opencv/test_separable_filter_2d.cpp @@ -11,7 +11,7 @@ // specified InputType and KernelType. An exception should be thrown in case the // constraint in the HAL has not been met. // Returns a 1x1-sized boolean matrix. -template +template cv::Mat exec_separable_filter_2d_channel_check(cv::Mat& input) { cv::Mat kernel(KernelSize, 1, KernelType); cv::Mat result; @@ -24,7 +24,7 @@ cv::Mat exec_separable_filter_2d_channel_check(cv::Mat& input) { return cv::Mat(1, 1, CV_8UC1, cv::Scalar(0)); } -template +template cv::Mat exec_separable_filter_2d(cv::Mat& input) { uint32_t kernel_seed = *reinterpret_cast(&input.at(input.rows - 1, 0)); @@ -51,7 +51,7 @@ cv::Mat exec_separable_filter_2d(cv::Mat& input) { #if MANAGER // The purpose of this test is to check one of the initial constraints of the // Separable Filter 2D HAL, that the kernel can only have one channel. -template +template bool test_separable_filter_2d_channel_check( int index, RecreatedMessageQueue& request_queue, RecreatedMessageQueue& reply_queue) { @@ -81,53 +81,51 @@ bool test_separable_filter_2d_channel_check( return false; } -template bool test_separable_filter_2d(int index, RecreatedMessageQueue& request_queue, RecreatedMessageQueue& reply_queue) { cv::RNG rng(0); - for (size_t y = 5; y <= 16; ++y) { - for (size_t x = 5; x <= 16; ++x) { - // One extra line allocated to be sure the kernel seed can be placed next - // to the real input - cv::Mat input(y + 1, x, get_opencv_matrix_type()); - // use the minimum value 1 for the input in order to properly work around - // the potential OpenCV bug (mentioned lower) - rng.fill(input, cv::RNG::UNIFORM, 1, - std::numeric_limits::max()); - - uint32_t kernel_seed = rng.next(); - - // kernel seed is embedded into the input matrix - *reinterpret_cast(&input.at(input.rows - 1, 0)) = - kernel_seed; - - cv::Mat actual = - exec_separable_filter_2d(input); - cv::Mat expected = get_expected_from_subordinate(index, request_queue, - reply_queue, input); - - // bypass OpenCV bug/inconsistency where the output matrix contains 0's - // (or also the smallest negative value for signed types), whereas this - // should not be possible mathematically - for (size_t i = 0; i < (y * Channels); ++i) { - for (size_t j = 0; j < (x * Channels); ++j) { - if (expected.at(i, j) == - std::numeric_limits::lowest()) { - expected.at(i, j) = - std::numeric_limits::max(); - } else if (expected.at(i, j) == 0) { - expected.at(i, j) = - std::numeric_limits::max(); - } + // Minimal width is sizeof(uint32_t) and one more row is allcated to place + // the kernel seed next to the real input + for (auto size : typical_test_sizes( + std::max(KernelSize - 1, static_cast(sizeof(uint32_t))), + KernelSize - 1)) { + cv::Mat input(size.height + 1, size.width, + get_opencv_matrix_type()); + // use the minimum value 1 for the input in order to properly work around + // the potential OpenCV bug (mentioned lower) + rng.fill(input, cv::RNG::UNIFORM, 1, std::numeric_limits::max()); + + uint32_t kernel_seed = rng.next(); + + // kernel seed is embedded into the input matrix + *reinterpret_cast(&input.at(input.rows - 1, 0)) = + kernel_seed; + + cv::Mat actual = + exec_separable_filter_2d(input); + cv::Mat expected = + get_expected_from_subordinate(index, request_queue, reply_queue, input); + + // bypass OpenCV bug/inconsistency where the output matrix contains 0's + // (or also the smallest negative value for signed types), whereas this + // should not be possible mathematically + for (size_t i = 0; i < static_cast(size.height); ++i) { + for (size_t j = 0; j < (size.width * Channels); ++j) { + if (expected.at(i, j) == + std::numeric_limits::lowest()) { + expected.at(i, j) = std::numeric_limits::max(); + } else if (expected.at(i, j) == 0) { + expected.at(i, j) = std::numeric_limits::max(); } } + } - if (are_matrices_different(0, actual, expected)) { - fail_print_matrices(y, x, input, actual, expected); - return true; - } + if (are_matrices_different(0, actual, expected)) { + fail_print_matrices(size.height, size.width, input, actual, expected); + return true; } } diff --git a/conformity/opencv/test_sobel.cpp b/conformity/opencv/test_sobel.cpp index 807af0c8a..99ad47aa6 100644 --- a/conformity/opencv/test_sobel.cpp +++ b/conformity/opencv/test_sobel.cpp @@ -23,19 +23,17 @@ bool test_sobel(int index, RecreatedMessageQueue& request_queue, RecreatedMessageQueue& reply_queue) { cv::RNG rng(0); - for (size_t x = 5; x <= 16; ++x) { - for (size_t y = 5; y <= 16; ++y) { - cv::Mat input(x, y, CV_8UC(Channels)); - rng.fill(input, cv::RNG::UNIFORM, 0, 255); - - cv::Mat actual = exec_sobel(input); - cv::Mat expected = get_expected_from_subordinate(index, request_queue, - reply_queue, input); - - if (are_matrices_different(0, actual, expected)) { - fail_print_matrices(x, y, input, actual, expected); - return true; - } + for (auto size : typical_test_sizes(2, 2)) { + cv::Mat input(size.height, size.width, CV_8UC(Channels)); + rng.fill(input, cv::RNG::UNIFORM, 0, 255); + + cv::Mat actual = exec_sobel(input); + cv::Mat expected = + get_expected_from_subordinate(index, request_queue, reply_queue, input); + + if (are_matrices_different(0, actual, expected)) { + fail_print_matrices(size.height, size.width, input, actual, expected); + return true; } } diff --git a/conformity/opencv/test_yuv2rgb.cpp b/conformity/opencv/test_yuv2rgb.cpp index 4a0573efc..f0414c66d 100644 --- a/conformity/opencv/test_yuv2rgb.cpp +++ b/conformity/opencv/test_yuv2rgb.cpp @@ -23,19 +23,17 @@ bool test_yuv2rgb(int index, RecreatedMessageQueue& request_queue, RecreatedMessageQueue& reply_queue) { cv::RNG rng(0); - for (size_t x = 5; x <= 16; ++x) { - for (size_t y = 5; y <= 16; ++y) { - cv::Mat input(x, y, CV_8UC3); - rng.fill(input, cv::RNG::UNIFORM, 0, 255); - - cv::Mat actual = exec_yuv2rgb(input); - cv::Mat expected = get_expected_from_subordinate(index, request_queue, - reply_queue, input); - - if (are_matrices_different(0, actual, expected)) { - fail_print_matrices(x, y, input, actual, expected); - return true; - } + for (auto size : typical_test_sizes(1, 1)) { + cv::Mat input(size.height, size.width, CV_8UC3); + rng.fill(input, cv::RNG::UNIFORM, 0, 255); + + cv::Mat actual = exec_yuv2rgb(input); + cv::Mat expected = + get_expected_from_subordinate(index, request_queue, reply_queue, input); + + if (are_matrices_different(0, actual, expected)) { + fail_print_matrices(size.height, size.width, input, actual, expected); + return true; } } diff --git a/conformity/opencv/utils.cpp b/conformity/opencv/utils.cpp new file mode 100644 index 000000000..d7c25e694 --- /dev/null +++ b/conformity/opencv/utils.cpp @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2024 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: Apache-2.0 + +#include "utils.h" + +#if MANAGER + +std::array typical_test_sizes(int min_width, int min_height) { + // Tests around the minimal width and height and some rudimentary sizes + return std::array{{{min_width, min_height}, + {min_width + 1, min_height + 1}, + {64 * 4, min_height * 2}, + {(64 * 4) + 1, min_height * 2}}}; +} + +#endif diff --git a/conformity/opencv/utils.h b/conformity/opencv/utils.h index c6778d4f0..12f0af353 100644 --- a/conformity/opencv/utils.h +++ b/conformity/opencv/utils.h @@ -23,6 +23,8 @@ constexpr int get_opencv_matrix_type() { } #if MANAGER +std::array typical_test_sizes(int min_width, int min_height); + template static auto abs_diff(T a, T b) { return a > b ? a - b : b - a; -- GitLab