From c11423df1e92a9f098cd256800b9cb8bd325e372 Mon Sep 17 00:00:00 2001 From: Andrey Golubev Date: Tue, 16 Jul 2019 19:01:45 +0300 Subject: [PATCH] Merge pull request #15012 from andrey-golubev:test_output G-API: Add output allocation tests for backends (#15012) * Add output tests for backends * Fix large size test: output is in fact reallocated * Use cv::Mat copies for reallocation tracking * Separate LargeSizeWithCorrectSubmatrix test * Rename backed output allocation tests * Address code review feedback Update test names Add illustrative "expect (non-)empty" checks Rename mat "copy" to mat reference Add more pointer checks * Add illustrative checks --- modules/gapi/test/common/gapi_core_tests.hpp | 12 + .../gapi/test/common/gapi_core_tests_inl.hpp | 211 ++++++++++++++++++ modules/gapi/test/cpu/gapi_core_tests_cpu.cpp | 15 ++ .../gapi/test/cpu/gapi_core_tests_fluid.cpp | 15 ++ modules/gapi/test/gpu/gapi_core_tests_gpu.cpp | 16 ++ 5 files changed, 269 insertions(+) diff --git a/modules/gapi/test/common/gapi_core_tests.hpp b/modules/gapi/test/common/gapi_core_tests.hpp index 891edb8def..e01d3276e7 100644 --- a/modules/gapi/test/common/gapi_core_tests.hpp +++ b/modules/gapi/test/common/gapi_core_tests.hpp @@ -165,6 +165,18 @@ GAPI_TEST_FIXTURE(PhaseTest, initMatsRandU, FIXTURE_API(bool), 1, angle_in_degre GAPI_TEST_FIXTURE(SqrtTest, initMatrixRandU, <>, 0) GAPI_TEST_FIXTURE(NormalizeTest, initNothing, FIXTURE_API(compare_f,double,double,int,MatType), 5, cmpF, a, b, norm_type, ddepth) +struct BackendOutputAllocationTest : TestWithParamBase<> +{ + BackendOutputAllocationTest() + { + in_mat1 = cv::Mat(sz, type); + in_mat2 = cv::Mat(sz, type); + cv::randu(in_mat1, cv::Scalar::all(1), cv::Scalar::all(15)); + cv::randu(in_mat2, cv::Scalar::all(1), cv::Scalar::all(15)); + } +}; +// FIXME: move all tests from this fixture to the base class once all issues are resolved +struct BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest : BackendOutputAllocationTest {}; } // opencv_test #endif //OPENCV_GAPI_CORE_TESTS_HPP diff --git a/modules/gapi/test/common/gapi_core_tests_inl.hpp b/modules/gapi/test/common/gapi_core_tests_inl.hpp index ca6533af89..c5aef0fe19 100644 --- a/modules/gapi/test/common/gapi_core_tests_inl.hpp +++ b/modules/gapi/test/common/gapi_core_tests_inl.hpp @@ -1267,6 +1267,217 @@ TEST_P(NormalizeTest, Test) } } +TEST_P(BackendOutputAllocationTest, EmptyOutput) +{ + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in1, in2, out; + out = cv::gapi::mul(in1, in2); + cv::GComputation c(cv::GIn(in1, in2), cv::GOut(out)); + + EXPECT_TRUE(out_mat_gapi.empty()); + c.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat_gapi), getCompileArgs()); + EXPECT_FALSE(out_mat_gapi.empty()); + + // OpenCV code ///////////////////////////////////////////////////////////// + cv::multiply(in_mat1, in_mat2, out_mat_ocv); + + // Comparison ////////////////////////////////////////////////////////////// + // Expected: output is allocated to the needed size + EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); + EXPECT_EQ(sz, out_mat_gapi.size()); +} + +TEST_P(BackendOutputAllocationTest, CorrectlyPreallocatedOutput) +{ + out_mat_gapi = cv::Mat(sz, type); + auto out_mat_gapi_ref = out_mat_gapi; // shallow copy to ensure previous data is not deleted + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in1, in2, out; + out = cv::gapi::add(in1, in2); + cv::GComputation c(cv::GIn(in1, in2), cv::GOut(out)); + c.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat_gapi), getCompileArgs()); + + // OpenCV code ///////////////////////////////////////////////////////////// + cv::add(in_mat1, in_mat2, out_mat_ocv); + + // Comparison ////////////////////////////////////////////////////////////// + // Expected: output is not reallocated + EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); + EXPECT_EQ(sz, out_mat_gapi.size()); + + EXPECT_EQ(out_mat_gapi_ref.data, out_mat_gapi.data); +} + +// FIXME: known issue with OCL backend - PR #14985 +TEST_P(BackendOutputAllocationTest, DISABLED_IncorrectOutputMeta) +{ + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in1, in2, out; + out = cv::gapi::add(in1, in2); + cv::GComputation c(cv::GIn(in1, in2), cv::GOut(out)); + + const auto run_and_compare = [&c, this] () + { + auto out_mat_gapi_ref = out_mat_gapi; // shallow copy to ensure previous data is not deleted + + // G-API code ////////////////////////////////////////////////////////////// + c.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat_gapi), getCompileArgs()); + + // OpenCV code ///////////////////////////////////////////////////////////// + cv::add(in_mat1, in_mat2, out_mat_ocv, cv::noArray()); + + // Comparison ////////////////////////////////////////////////////////////// + // Expected: size is changed, type is changed, output is reallocated + EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); + EXPECT_EQ(sz, out_mat_gapi.size()); + EXPECT_EQ(type, out_mat_gapi.type()); + + EXPECT_NE(out_mat_gapi_ref.data, out_mat_gapi.data); + }; + + const auto chan = CV_MAT_CN(type); + + out_mat_gapi = cv::Mat(sz, CV_MAKE_TYPE(CV_64F, chan)); + run_and_compare(); + + out_mat_gapi = cv::Mat(sz, CV_MAKE_TYPE(CV_MAT_DEPTH(type), chan + 1)); + run_and_compare(); +} + +TEST_P(BackendOutputAllocationTest, SmallerPreallocatedSize) +{ + out_mat_gapi = cv::Mat(sz / 2, type); + auto out_mat_gapi_ref = out_mat_gapi; // shallow copy to ensure previous data is not deleted + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in1, in2, out; + out = cv::gapi::mul(in1, in2); + cv::GComputation c(cv::GIn(in1, in2), cv::GOut(out)); + c.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat_gapi), getCompileArgs()); + + // OpenCV code ///////////////////////////////////////////////////////////// + cv::multiply(in_mat1, in_mat2, out_mat_ocv); + + // Comparison ////////////////////////////////////////////////////////////// + // Expected: size is changed, output is reallocated due to original size < curr size + EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); + EXPECT_EQ(sz, out_mat_gapi.size()); + + EXPECT_NE(out_mat_gapi_ref.data, out_mat_gapi.data); +} + +TEST_P(BackendOutputAllocationTest, SmallerPreallocatedSizeWithSubmatrix) +{ + out_mat_gapi = cv::Mat(sz / 2, type); + + cv::Mat out_mat_gapi_submat = out_mat_gapi(cv::Rect({10, 0}, sz / 5)); + EXPECT_EQ(out_mat_gapi.data, out_mat_gapi_submat.datastart); + + auto out_mat_gapi_submat_ref = out_mat_gapi_submat; // shallow copy to ensure previous data is not deleted + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in1, in2, out; + out = cv::gapi::mul(in1, in2); + cv::GComputation c(cv::GIn(in1, in2), cv::GOut(out)); + c.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat_gapi_submat), getCompileArgs()); + + // OpenCV code ///////////////////////////////////////////////////////////// + cv::multiply(in_mat1, in_mat2, out_mat_ocv); + + // Comparison ////////////////////////////////////////////////////////////// + // Expected: submatrix is reallocated and is "detached", original matrix is unchanged + EXPECT_EQ(0, cv::countNonZero(out_mat_gapi_submat != out_mat_ocv)); + EXPECT_EQ(sz, out_mat_gapi_submat.size()); + EXPECT_EQ(sz / 2, out_mat_gapi.size()); + + EXPECT_NE(out_mat_gapi_submat_ref.data, out_mat_gapi_submat.data); + EXPECT_NE(out_mat_gapi.data, out_mat_gapi_submat.datastart); +} + +TEST_P(BackendOutputAllocationTest, LargerPreallocatedSize) +{ + out_mat_gapi = cv::Mat(sz * 2, type); + auto out_mat_gapi_ref = out_mat_gapi; // shallow copy to ensure previous data is not deleted + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in1, in2, out; + out = cv::gapi::mul(in1, in2); + cv::GComputation c(cv::GIn(in1, in2), cv::GOut(out)); + c.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat_gapi), getCompileArgs()); + + // OpenCV code ///////////////////////////////////////////////////////////// + cv::multiply(in_mat1, in_mat2, out_mat_ocv); + + // Comparison ////////////////////////////////////////////////////////////// + // Expected: size is changed, output is reallocated + EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); + EXPECT_EQ(sz, out_mat_gapi.size()); + + EXPECT_NE(out_mat_gapi_ref.data, out_mat_gapi.data); +} + +TEST_P(BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest, + LargerPreallocatedSizeWithCorrectSubmatrix) +{ + out_mat_gapi = cv::Mat(sz * 2, type); + auto out_mat_gapi_ref = out_mat_gapi; // shallow copy to ensure previous data is not deleted + + cv::Mat out_mat_gapi_submat = out_mat_gapi(cv::Rect({5, 8}, sz)); + EXPECT_EQ(out_mat_gapi.data, out_mat_gapi_submat.datastart); + + auto out_mat_gapi_submat_ref = out_mat_gapi_submat; + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in1, in2, out; + out = cv::gapi::mul(in1, in2); + cv::GComputation c(cv::GIn(in1, in2), cv::GOut(out)); + c.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat_gapi_submat), getCompileArgs()); + + // OpenCV code ///////////////////////////////////////////////////////////// + cv::multiply(in_mat1, in_mat2, out_mat_ocv); + + // Comparison ////////////////////////////////////////////////////////////// + // Expected: submatrix is not reallocated, original matrix is not reallocated + EXPECT_EQ(0, cv::countNonZero(out_mat_gapi_submat != out_mat_ocv)); + EXPECT_EQ(sz, out_mat_gapi_submat.size()); + EXPECT_EQ(sz * 2, out_mat_gapi.size()); + + EXPECT_EQ(out_mat_gapi_ref.data, out_mat_gapi.data); + EXPECT_EQ(out_mat_gapi_submat_ref.data, out_mat_gapi_submat.data); + EXPECT_EQ(out_mat_gapi.data, out_mat_gapi_submat.datastart); +} + +TEST_P(BackendOutputAllocationTest, LargerPreallocatedSizeWithSmallSubmatrix) +{ + out_mat_gapi = cv::Mat(sz * 2, type); + auto out_mat_gapi_ref = out_mat_gapi; // shallow copy to ensure previous data is not deleted + + cv::Mat out_mat_gapi_submat = out_mat_gapi(cv::Rect({5, 8}, sz / 2)); + EXPECT_EQ(out_mat_gapi.data, out_mat_gapi_submat.datastart); + + auto out_mat_gapi_submat_ref = out_mat_gapi_submat; + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in1, in2, out; + out = cv::gapi::mul(in1, in2); + cv::GComputation c(cv::GIn(in1, in2), cv::GOut(out)); + c.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat_gapi_submat), getCompileArgs()); + + // OpenCV code ///////////////////////////////////////////////////////////// + cv::multiply(in_mat1, in_mat2, out_mat_ocv); + + // Comparison ////////////////////////////////////////////////////////////// + // Expected: submatrix is reallocated and is "detached", original matrix is unchanged + EXPECT_EQ(0, cv::countNonZero(out_mat_gapi_submat != out_mat_ocv)); + EXPECT_EQ(sz, out_mat_gapi_submat.size()); + EXPECT_EQ(sz * 2, out_mat_gapi.size()); + + EXPECT_EQ(out_mat_gapi_ref.data, out_mat_gapi.data); + EXPECT_NE(out_mat_gapi_submat_ref.data, out_mat_gapi_submat.data); + EXPECT_NE(out_mat_gapi.data, out_mat_gapi_submat.datastart); +} + } // opencv_test #endif //OPENCV_GAPI_CORE_TESTS_INL_HPP diff --git a/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp b/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp index b59e1a984c..ce54ea759e 100644 --- a/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp +++ b/modules/gapi/test/cpu/gapi_core_tests_cpu.cpp @@ -489,4 +489,19 @@ INSTANTIATE_TEST_CASE_P(NormalizeTestCPU, NormalizeTest, Values(1.0, 120.0, 255.0), Values(NORM_MINMAX, NORM_INF, NORM_L1, NORM_L2), Values(-1, CV_8U, CV_16U, CV_16S, CV_32F))); + +INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestCPU, BackendOutputAllocationTest, + Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1), + Values(cv::Size(50, 50)), + Values(-1), + Values(false), + Values(CORE_CPU))); + +INSTANTIATE_TEST_CASE_P(BackendOutputAllocationLargeSizeWithCorrectSubmatrixTestCPU, + BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest, + Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1), + Values(cv::Size(50, 50)), + Values(-1), + Values(false), + Values(CORE_CPU))); } diff --git a/modules/gapi/test/cpu/gapi_core_tests_fluid.cpp b/modules/gapi/test/cpu/gapi_core_tests_fluid.cpp index e955651ead..818eddccf1 100644 --- a/modules/gapi/test/cpu/gapi_core_tests_fluid.cpp +++ b/modules/gapi/test/cpu/gapi_core_tests_fluid.cpp @@ -283,6 +283,21 @@ INSTANTIATE_TEST_CASE_P(ResizeTestFluid, ResizeTest, cv::Size(64, 64), cv::Size(30, 30)))); +INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestFluid, BackendOutputAllocationTest, + Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1), + Values(cv::Size(50, 50)), + Values(-1), + Values(false), + Values(CORE_FLUID))); + +INSTANTIATE_TEST_CASE_P(BackendOutputAllocationLargeSizeWithCorrectSubmatrixTestFluid, + BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest, + Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1), + Values(cv::Size(50, 50)), + Values(-1), + Values(false), + Values(CORE_FLUID))); + //---------------------------------------------------------------------- // FIXME: Clean-up test configurations which are enabled already #if 0 diff --git a/modules/gapi/test/gpu/gapi_core_tests_gpu.cpp b/modules/gapi/test/gpu/gapi_core_tests_gpu.cpp index 03289781d2..e1b69c0403 100644 --- a/modules/gapi/test/gpu/gapi_core_tests_gpu.cpp +++ b/modules/gapi/test/gpu/gapi_core_tests_gpu.cpp @@ -426,6 +426,22 @@ INSTANTIATE_TEST_CASE_P(ConcatVertTestGPU, ConcatVertTest, Values(false), Values(CORE_GPU))); +INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestGPU, BackendOutputAllocationTest, + Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1), + Values(cv::Size(50, 50)), + Values(-1), + Values(false), + Values(CORE_GPU))); + +// FIXME: there's an issue in OCL backend with matrix reallocation that shouldn't happen +INSTANTIATE_TEST_CASE_P(DISABLED_BackendOutputAllocationLargeSizeWithCorrectSubmatrixTestGPU, + BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest, + Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1), + Values(cv::Size(50, 50)), + Values(-1), + Values(false), + Values(CORE_GPU))); + //TODO: fix this backend to allow ConcatVertVec ConcatHorVec #if 0 INSTANTIATE_TEST_CASE_P(ConcatVertVecTestGPU, ConcatVertVecTest,