Merge remote-tracking branch 'upstream/3.4' into merge-3.4
[platform/upstream/opencv.git] / modules / ts / src / ts.cpp
index be23d5b..8a7dafb 100644 (file)
@@ -40,6 +40,8 @@
 //M*/
 
 #include "precomp.hpp"
+#include <opencv2/core/utils/configuration.private.hpp>
+
 #include "opencv2/core/core_c.h"
 
 #include <ctype.h>
 
 #include "opencv2/core/opencl/opencl_info.hpp"
 
+#include "opencv2/core/utils/allocator_stats.hpp"
+namespace cv { namespace ocl {
+cv::utils::AllocatorStatisticsInterface& getOpenCLAllocatorStatistics();
+}}
 #endif // HAVE_OPENCL
 
-#include "opencv2/core/utility.hpp"
+#include "opencv2/core/utils/allocator_stats.hpp"
+namespace cv {
+CV_EXPORTS cv::utils::AllocatorStatisticsInterface& getAllocatorStatistics();
+}
+
 #include "opencv_tests_config.hpp"
 
+#include "ts_tags.hpp"
+
+#if defined(__GNUC__) && defined(__linux__)
+extern "C" {
+size_t malloc_peak(void) __attribute__((weak));
+void malloc_reset_peak(void) __attribute__((weak));
+} // extern "C"
+#else // stubs
+static size_t (*malloc_peak)(void) = 0;
+static void (*malloc_reset_peak)(void) = 0;
+#endif
+
 namespace opencv_test {
 bool required_opencv_test_namespace = false;  // compilation check for non-refactored tests
 }
@@ -721,21 +743,112 @@ void checkIppStatus()
     }
 }
 
-static bool checkTestData = false;
+static bool checkTestData = cv::utils::getConfigurationParameterBool("OPENCV_TEST_REQUIRE_DATA", false);
 bool skipUnstableTests = false;
 bool runBigDataTests = false;
 int testThreads = 0;
 
+
+static size_t memory_usage_base = 0;
+static uint64_t memory_usage_base_opencv = 0;
+#ifdef HAVE_OPENCL
+static uint64_t memory_usage_base_opencl = 0;
+#endif
+
+void testSetUp()
+{
+    fflush(stdout); fflush(stderr);
+    cv::ipp::setIppStatus(0);
+    cv::theRNG().state = cvtest::param_seed;
+    cv::setNumThreads(cvtest::testThreads);
+    if (malloc_peak)  // if memory profiler is available
+    {
+        malloc_reset_peak();
+        memory_usage_base = malloc_peak(); // equal to malloc_current()
+    }
+    {
+        cv::utils::AllocatorStatisticsInterface& ocv_stats = cv::getAllocatorStatistics();
+        ocv_stats.resetPeakUsage();
+        memory_usage_base_opencv = ocv_stats.getCurrentUsage();
+    }
+#ifdef HAVE_OPENCL
+    {
+        cv::utils::AllocatorStatisticsInterface& ocl_stats = cv::ocl::getOpenCLAllocatorStatistics();
+        ocl_stats.resetPeakUsage();
+        memory_usage_base_opencl = ocl_stats.getCurrentUsage();
+    }
+#endif
+    checkTestTags();
+}
+
+void testTearDown()
+{
+    ::cvtest::checkIppStatus();
+    uint64_t memory_usage = 0;
+    uint64_t ocv_memory_usage = 0, ocv_peak = 0;
+    if (malloc_peak)  // if memory profiler is available
+    {
+        size_t peak = malloc_peak();
+        memory_usage = peak - memory_usage_base;
+        if (peak > 0)
+        {
+            CV_LOG_INFO(NULL, "Memory_usage (malloc): " << memory_usage << " (base=" << memory_usage_base << ")");
+        }
+    }
+    {
+        // core/src/alloc.cpp: #define OPENCV_ALLOC_ENABLE_STATISTICS
+        // handle large buffers via fastAlloc()
+        // (not always accurate on heavy 3rdparty usage, like protobuf)
+        cv::utils::AllocatorStatisticsInterface& ocv_stats = cv::getAllocatorStatistics();
+        ocv_peak = ocv_stats.getPeakUsage();
+        ocv_memory_usage = ocv_peak - memory_usage_base_opencv;
+        if (ocv_peak)
+        {
+            CV_LOG_INFO(NULL, "Memory_usage (OpenCV): " << ocv_memory_usage << " (base=" << memory_usage_base_opencv << "  current=" << ocv_stats.getCurrentUsage() << ")");
+        }
+        if (memory_usage == 0)  // external profiler has higher priority (and accuracy)
+            memory_usage = ocv_memory_usage;
+    }
+#ifdef HAVE_OPENCL
+    uint64_t ocl_memory_usage = 0, ocl_peak = 0;
+    {
+        cv::utils::AllocatorStatisticsInterface& ocl_stats = cv::ocl::getOpenCLAllocatorStatistics();
+        ocl_peak = ocl_stats.getPeakUsage();
+        ocl_memory_usage = ocl_peak - memory_usage_base_opencl;
+        if (ocl_memory_usage > 0)
+        {
+            CV_LOG_INFO(NULL, "Memory_usage (OpenCL): " << ocl_memory_usage << " (base=" << memory_usage_base_opencl << "  current=" << ocl_stats.getCurrentUsage() << ")");
+        }
+        ::testing::Test::RecordProperty("ocl_memory_usage",
+                cv::format("%llu", (unsigned long long)ocl_memory_usage));
+    }
+#else
+    uint64_t ocl_memory_usage = 0;
+#endif
+    if (malloc_peak      // external memory profiler is available
+        || ocv_peak > 0  // or enabled OpenCV builtin allocation statistics
+    )
+    {
+        CV_LOG_INFO(NULL, "Memory usage total: " << (memory_usage + ocl_memory_usage));
+        ::testing::Test::RecordProperty("memory_usage",
+                cv::format("%llu", (unsigned long long)memory_usage));
+        ::testing::Test::RecordProperty("total_memory_usage",
+                cv::format("%llu", (unsigned long long)(memory_usage + ocl_memory_usage)));
+    }
+}
+
 void parseCustomOptions(int argc, char **argv)
 {
-    const char * const command_line_keys =
+    const string command_line_keys = string(
         "{ ipp test_ipp_check |false    |check whether IPP works without failures }"
         "{ test_seed          |809564   |seed for random numbers generator }"
         "{ test_threads       |-1       |the number of worker threads, if parallel execution is enabled}"
         "{ skip_unstable      |false    |skip unstable tests }"
         "{ test_bigdata       |false    |run BigData tests (>=2Gb) }"
-        "{ test_require_data  |false    |fail on missing non-required test data instead of skip}"
-        "{ h   help           |false    |print help info                          }";
+        "{ test_require_data  |") + (checkTestData ? "true" : "false") + string("|fail on missing non-required test data instead of skip (env:OPENCV_TEST_REQUIRE_DATA)}"
+        CV_TEST_TAGS_PARAMS
+        "{ h   help           |false    |print help info                          }"
+    );
 
     cv::CommandLineParser parser(argc, argv, command_line_keys);
     if (parser.get<bool>("help"))
@@ -758,9 +871,11 @@ void parseCustomOptions(int argc, char **argv)
 
     skipUnstableTests = parser.get<bool>("skip_unstable");
     runBigDataTests = parser.get<bool>("test_bigdata");
-    checkTestData = parser.get<bool>("test_require_data");
-}
+    if (parser.has("test_require_data"))
+        checkTestData = parser.get<bool>("test_require_data");
 
+    activateTestTags(parser);
+}
 
 static bool isDirectory(const std::string& path)
 {
@@ -796,25 +911,35 @@ void addDataSearchSubDirectory(const std::string& subdir)
 
 static std::string findData(const std::string& relative_path, bool required, bool findDirectory)
 {
-#define TEST_TRY_FILE_WITH_PREFIX(prefix) \
+#define CHECK_FILE_WITH_PREFIX(prefix, result) \
 { \
+    result.clear(); \
     std::string path = path_join(prefix, relative_path); \
     /*printf("Trying %s\n", path.c_str());*/ \
     if (findDirectory) \
     { \
         if (isDirectory(path)) \
-            return path; \
+            result = path; \
     } \
     else \
     { \
         FILE* f = fopen(path.c_str(), "rb"); \
         if(f) { \
             fclose(f); \
-            return path; \
+            result = path; \
         } \
     } \
 }
 
+#define TEST_TRY_FILE_WITH_PREFIX(prefix) \
+{ \
+    std::string result__; \
+    CHECK_FILE_WITH_PREFIX(prefix, result__); \
+    if (!result__.empty()) \
+        return result__; \
+}
+
+
     const std::vector<std::string>& search_path = TS::ptr()->data_search_path;
     for(size_t i = search_path.size(); i > 0; i--)
     {
@@ -841,7 +966,19 @@ static std::string findData(const std::string& relative_path, bool required, boo
             {
                 const std::string& subdir = search_subdir[i - 1];
                 std::string prefix = path_join(datapath, subdir);
-                TEST_TRY_FILE_WITH_PREFIX(prefix);
+                std::string result_;
+                CHECK_FILE_WITH_PREFIX(prefix, result_);
+                if (!required && !result_.empty())
+                {
+                    std::cout << "TEST ERROR: Don't use 'optional' findData() for " << relative_path << std::endl;
+                    static bool checkOptionalFlag = cv::utils::getConfigurationParameterBool("OPENCV_TEST_CHECK_OPTIONAL_DATA", false);
+                    if (checkOptionalFlag)
+                    {
+                        CV_Assert(required || result_.empty());
+                    }
+                }
+                if (!result_.empty())
+                    return result_;
             }
         }
     }