1 #ifndef __OPENCV_TS_PERF_HPP__
2 #define __OPENCV_TS_PERF_HPP__
4 #include "opencv2/core/core.hpp"
5 #include "opencv2/imgproc/imgproc.hpp"
6 #include "opencv2/features2d/features2d.hpp"
10 #include "tbb/task_scheduler_init.h"
13 #if !(defined(LOGD) || defined(LOGI) || defined(LOGW) || defined(LOGE))
14 # if defined(ANDROID) && defined(USE_ANDROID_LOGGING)
15 # include <android/log.h>
17 # define PERF_TESTS_LOG_TAG "OpenCV_perf"
18 # define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, PERF_TESTS_LOG_TAG, __VA_ARGS__))
19 # define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, PERF_TESTS_LOG_TAG, __VA_ARGS__))
20 # define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, PERF_TESTS_LOG_TAG, __VA_ARGS__))
21 # define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, PERF_TESTS_LOG_TAG, __VA_ARGS__))
23 # define LOGD(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
24 # define LOGI(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
25 # define LOGW(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
26 # define LOGE(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
30 // declare major namespaces to avoid errors on unknown namespace
31 namespace cv { namespace gpu {} namespace ocl {} }
37 /*****************************************************************************************\
38 * Predefined typical frame sizes and typical test parameters *
39 \*****************************************************************************************/
40 const cv::Size szQVGA = cv::Size(320, 240);
41 const cv::Size szVGA = cv::Size(640, 480);
42 const cv::Size szSVGA = cv::Size(800, 600);
43 const cv::Size szXGA = cv::Size(1024, 768);
44 const cv::Size szSXGA = cv::Size(1280, 1024);
45 const cv::Size szWQHD = cv::Size(2560, 1440);
47 const cv::Size sznHD = cv::Size(640, 360);
48 const cv::Size szqHD = cv::Size(960, 540);
49 const cv::Size sz240p = szQVGA;
50 const cv::Size sz720p = cv::Size(1280, 720);
51 const cv::Size sz1080p = cv::Size(1920, 1080);
52 const cv::Size sz1440p = szWQHD;
53 const cv::Size sz2160p = cv::Size(3840, 2160);//UHDTV1 4K
54 const cv::Size sz4320p = cv::Size(7680, 4320);//UHDTV2 8K
56 const cv::Size sz3MP = cv::Size(2048, 1536);
57 const cv::Size sz5MP = cv::Size(2592, 1944);
58 const cv::Size sz2K = cv::Size(2048, 2048);
60 const cv::Size szODD = cv::Size(127, 61);
62 const cv::Size szSmall24 = cv::Size(24, 24);
63 const cv::Size szSmall32 = cv::Size(32, 32);
64 const cv::Size szSmall64 = cv::Size(64, 64);
65 const cv::Size szSmall128 = cv::Size(128, 128);
67 #define SZ_ALL_VGA ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA)
68 #define SZ_ALL_GA ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA)
69 #define SZ_ALL_HD ::testing::Values(::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
70 #define SZ_ALL_SMALL ::testing::Values(::perf::szSmall24, ::perf::szSmall32, ::perf::szSmall64, ::perf::szSmall128)
71 #define SZ_ALL ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA, ::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
72 #define SZ_TYPICAL ::testing::Values(::perf::szVGA, ::perf::szqHD, ::perf::sz720p, ::perf::szODD)
75 #define TYPICAL_MAT_SIZES ::perf::szVGA, ::perf::sz720p, ::perf::sz1080p, ::perf::szODD
76 #define TYPICAL_MAT_TYPES CV_8UC1, CV_8UC4, CV_32FC1
77 #define TYPICAL_MATS testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( TYPICAL_MAT_TYPES ) )
78 #define TYPICAL_MATS_C1 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC1, CV_32FC1 ) )
79 #define TYPICAL_MATS_C4 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC4 ) )
82 /*****************************************************************************************\
83 * MatType - printable wrapper over integer 'type' of Mat *
84 \*****************************************************************************************/
88 MatType(int val=0) : _type(val) {}
89 operator int() const {return _type;}
95 /*****************************************************************************************\
96 * CV_ENUM and CV_FLAGS - macro to create printable wrappers for defines and enums *
97 \*****************************************************************************************/
99 #define CV_ENUM(class_name, ...) \
101 struct class_name { \
102 class_name(int val = 0) : val_(val) {} \
103 operator int() const { return val_; } \
104 void PrintTo(std::ostream* os) const { \
105 using namespace cv;using namespace cv::gpu; using namespace cv::ocl; \
106 const int vals[] = { __VA_ARGS__ }; \
107 const char* svals = #__VA_ARGS__; \
108 for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i) { \
109 while(isspace(svals[pos]) || svals[pos] == ',') ++pos; \
111 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0)) \
113 if (val_ == vals[i]) { \
114 *os << std::string(svals + start, svals + pos); \
120 static ::testing::internal::ParamGenerator<class_name> all() { \
121 using namespace cv;using namespace cv::gpu; using namespace cv::ocl; \
122 static class_name vals[] = { __VA_ARGS__ }; \
123 return ::testing::ValuesIn(vals); \
127 inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
129 #define CV_FLAGS(class_name, ...) \
131 struct class_name { \
132 class_name(int val = 0) : val_(val) {} \
133 operator int() const { return val_; } \
134 void PrintTo(std::ostream* os) const { \
135 using namespace cv;using namespace cv::gpu; using namespace cv::ocl; \
136 const int vals[] = { __VA_ARGS__ }; \
137 const char* svals = #__VA_ARGS__; \
140 for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i) { \
141 while(isspace(svals[pos]) || svals[pos] == ',') ++pos; \
143 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0)) \
145 if ((value & vals[i]) == vals[i]) { \
147 if (first) first = false; else *os << "|"; \
148 *os << std::string(svals + start, svals + pos); \
149 if (!value) return; \
152 if (first) *os << "UNKNOWN"; \
156 inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
158 CV_ENUM(MatDepth, CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, CV_USRTYPE1)
160 /*****************************************************************************************\
161 * Regression control utility for performance testing *
162 \*****************************************************************************************/
169 class CV_EXPORTS Regression
172 static Regression& add(TestBase* test, const std::string& name, cv::InputArray array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
173 static Regression& addKeypoints(TestBase* test, const std::string& name, const std::vector<cv::KeyPoint>& array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
174 static Regression& addMatches(TestBase* test, const std::string& name, const std::vector<cv::DMatch>& array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
175 static void Init(const std::string& testSuitName, const std::string& ext = ".xml");
177 Regression& operator() (const std::string& name, cv::InputArray array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
180 static Regression& instance();
184 Regression(const Regression&);
185 Regression& operator=(const Regression&);
187 cv::RNG regRNG;//own random numbers generator to make collection and verification work identical
188 std::string storageInPath;
189 std::string storageOutPath;
190 cv::FileStorage storageIn;
191 cv::FileStorage storageOut;
193 std::string currentTestNodeName;
194 std::string suiteName;
196 cv::FileStorage& write();
198 static std::string getCurrentTestNodeName();
199 static bool isVector(cv::InputArray a);
200 static double getElem(cv::Mat& m, int x, int y, int cn = 0);
202 void init(const std::string& testSuitName, const std::string& ext);
203 void write(cv::InputArray array);
204 void write(cv::Mat m);
205 void verify(cv::FileNode node, cv::InputArray array, double eps, ERROR_TYPE err);
206 void verify(cv::FileNode node, cv::Mat actual, double eps, std::string argname, ERROR_TYPE err);
209 #define SANITY_CHECK(array, ...) ::perf::Regression::add(this, #array, array , ## __VA_ARGS__)
210 #define SANITY_CHECK_KEYPOINTS(array, ...) ::perf::Regression::addKeypoints(this, #array, array , ## __VA_ARGS__)
211 #define SANITY_CHECK_MATCHES(array, ...) ::perf::Regression::addMatches(this, #array, array , ## __VA_ARGS__)
213 class CV_EXPORTS GpuPerf
216 static bool targetDevice();
219 #define PERF_RUN_GPU() ::perf::GpuPerf::targetDevice()
221 /*****************************************************************************************\
222 * Container for performance metrics *
223 \*****************************************************************************************/
224 typedef struct CV_EXPORTS performance_metrics
228 unsigned int samples;
229 unsigned int outliers;
231 double gstddev;//stddev for log(time)
237 int terminationReason;
248 performance_metrics();
249 } performance_metrics;
252 /*****************************************************************************************\
253 * Base fixture for performance tests *
254 \*****************************************************************************************/
255 class CV_EXPORTS TestBase: public ::testing::Test
260 static void Init(int argc, const char* const argv[]);
261 static void Init(const std::vector<std::string> & availableImpls,
262 int argc, const char* const argv[]);
263 static void RecordRunParameters();
264 static std::string getDataPath(const std::string& relativePath);
265 static std::string getSelectedImpl();
268 virtual void PerfTestBody() = 0;
270 virtual void SetUp();
271 virtual void TearDown();
277 //_declareHelper declare;
287 void reportMetrics(bool toJUnitXML = false);
288 static void warmup(cv::InputOutputArray a, int wtype = WARMUP_READ);
290 performance_metrics& calcMetrics();
291 void RunPerfTestBody();
293 typedef std::vector<std::pair<int, cv::Size> > SizeVector;
294 typedef std::vector<int64> TimeVector;
296 SizeVector inputData;
297 SizeVector outputData;
298 unsigned int getTotalInputSize() const;
299 unsigned int getTotalOutputSize() const;
305 static int64 timeLimitDefault;
306 static unsigned int iterationsLimitDefault;
309 unsigned int currentIter;
310 unsigned int runsPerIteration;
312 performance_metrics metrics;
313 void validateMetrics();
315 static int64 _timeadjustment;
316 static int64 _calibrate();
318 static void warmup_impl(cv::Mat m, int wtype);
319 static int getSizeInBytes(cv::InputArray a);
320 static cv::Size getSize(cv::InputArray a);
321 static void declareArray(SizeVector& sizes, cv::InputOutputArray a, int wtype = 0);
323 class CV_EXPORTS _declareHelper
326 _declareHelper& in(cv::InputOutputArray a1, int wtype = WARMUP_READ);
327 _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, int wtype = WARMUP_READ);
328 _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, int wtype = WARMUP_READ);
329 _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, int wtype = WARMUP_READ);
331 _declareHelper& out(cv::InputOutputArray a1, int wtype = WARMUP_WRITE);
332 _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, int wtype = WARMUP_WRITE);
333 _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, int wtype = WARMUP_WRITE);
334 _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, int wtype = WARMUP_WRITE);
336 _declareHelper& iterations(unsigned int n);
337 _declareHelper& time(double timeLimitSecs);
338 _declareHelper& tbb_threads(int n = -1);
339 _declareHelper& runs(unsigned int runsNumber);
342 _declareHelper(TestBase* t);
343 _declareHelper(const _declareHelper&);
344 _declareHelper& operator=(const _declareHelper&);
345 friend class TestBase;
347 friend class _declareHelper;
348 friend class Regression;
353 _declareHelper declare;
356 template<typename T> class TestBaseWithParam: public TestBase, public ::testing::WithParamInterface<T> {};
358 typedef std::tr1::tuple<cv::Size, MatType> Size_MatType_t;
359 typedef TestBaseWithParam<Size_MatType_t> Size_MatType;
361 /*****************************************************************************************\
362 * Print functions for googletest *
363 \*****************************************************************************************/
364 CV_EXPORTS void PrintTo(const MatType& t, std::ostream* os);
371 CV_EXPORTS void PrintTo(const Size& sz, ::std::ostream* os);
376 /*****************************************************************************************\
377 * Macro definitions for performance tests *
378 \*****************************************************************************************/
379 #define PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) \
380 test_case_name##_##test_name##_perf_namespace_proxy
382 // Defines a performance test.
384 // The first parameter is the name of the test case, and the second
385 // parameter is the name of the test within the test case.
387 // The user should put his test code between braces after using this
390 // PERF_TEST(FooTest, InitializesCorrectly) {
392 // EXPECT_TRUE(foo.StatusIsOK());
394 #define PERF_TEST(test_case_name, test_name)\
395 namespace PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) {\
396 class TestBase {/*compile error for this class means that you are trying to use perf::TestBase as a fixture*/};\
397 class test_case_name : public ::perf::TestBase {\
401 virtual void PerfTestBody();\
403 TEST_F(test_case_name, test_name){ RunPerfTestBody(); }\
405 void PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name)::test_case_name::PerfTestBody()
407 // Defines a performance test that uses a test fixture.
409 // The first parameter is the name of the test fixture class, which
410 // also doubles as the test case name. The second parameter is the
411 // name of the test within the test case.
413 // A test fixture class must be declared earlier. The user should put
414 // his test code between braces after using this macro. Example:
416 // class FooTest : public ::perf::TestBase {
418 // virtual void SetUp() { TestBase::SetUp(); b_.AddElement(3); }
424 // PERF_TEST_F(FooTest, InitializesCorrectly) {
425 // EXPECT_TRUE(a_.StatusIsOK());
428 // PERF_TEST_F(FooTest, ReturnsElementCountCorrectly) {
429 // EXPECT_EQ(0, a_.size());
430 // EXPECT_EQ(1, b_.size());
432 #define PERF_TEST_F(fixture, testname) \
433 namespace PERF_PROXY_NAMESPACE_NAME_(fixture, testname) {\
434 class TestBase {/*compile error for this class means that you are trying to use perf::TestBase as a fixture*/};\
435 class fixture : public ::fixture {\
439 virtual void PerfTestBody();\
441 TEST_F(fixture, testname){ RunPerfTestBody(); }\
443 void PERF_PROXY_NAMESPACE_NAME_(fixture, testname)::fixture::PerfTestBody()
445 // Defines a parametrized performance test.
447 // The first parameter is the name of the test fixture class, which
448 // also doubles as the test case name. The second parameter is the
449 // name of the test within the test case.
451 // The user should put his test code between braces after using this
454 // typedef ::perf::TestBaseWithParam<cv::Size> FooTest;
456 // PERF_TEST_P(FooTest, DoTestingRight, ::testing::Values(::perf::szVGA, ::perf::sz720p) {
457 // cv::Mat b(GetParam(), CV_8U, cv::Scalar(10));
458 // cv::Mat a(GetParam(), CV_8U, cv::Scalar(20));
459 // cv::Mat c(GetParam(), CV_8U, cv::Scalar(0));
461 // declare.in(a, b).out(c).time(0.5);
463 // TEST_CYCLE() cv::add(a, b, c);
467 #define PERF_TEST_P(fixture, name, params) \
468 class fixture##_##name : public fixture {\
470 fixture##_##name() {}\
472 virtual void PerfTestBody();\
474 TEST_P(fixture##_##name, name /*perf*/){ RunPerfTestBody(); }\
475 INSTANTIATE_TEST_CASE_P(/*none*/, fixture##_##name, params);\
476 void fixture##_##name::PerfTestBody()
478 #if defined(_MSC_VER) && (_MSC_VER <= 1400)
479 #define CV_PERF_TEST_MAIN_INTERNALS_ARGS(...) \
480 while (++argc >= (--argc,-1)) {__VA_ARGS__; break;} /*this ugly construction is needed for VS 2005*/
482 #define CV_PERF_TEST_MAIN_INTERNALS_ARGS(...) \
486 #define CV_PERF_TEST_MAIN_INTERNALS(modulename, impls, ...) \
487 CV_PERF_TEST_MAIN_INTERNALS_ARGS(__VA_ARGS__) \
488 ::perf::Regression::Init(#modulename);\
489 ::perf::TestBase::Init(std::vector<std::string>(impls, impls + sizeof impls / sizeof *impls),\
491 ::testing::InitGoogleTest(&argc, argv);\
492 cvtest::printVersionInfo();\
493 ::testing::Test::RecordProperty("cv_module_name", #modulename);\
494 ::perf::TestBase::RecordRunParameters();\
495 return RUN_ALL_TESTS();
497 // impls must be an array, not a pointer; "plain" should always be one of the implementations
498 #define CV_PERF_TEST_MAIN_WITH_IMPLS(modulename, impls, ...) \
499 int main(int argc, char **argv)\
501 CV_PERF_TEST_MAIN_INTERNALS(modulename, impls, __VA_ARGS__)\
504 #define CV_PERF_TEST_MAIN(modulename, ...) \
505 int main(int argc, char **argv)\
507 const char * plain_only[] = { "plain" };\
508 CV_PERF_TEST_MAIN_INTERNALS(modulename, plain_only, __VA_ARGS__)\
511 #define TEST_CYCLE_N(n) for(declare.iterations(n); startTimer(), next(); stopTimer())
512 #define TEST_CYCLE() for(; startTimer(), next(); stopTimer())
513 #define TEST_CYCLE_MULTIRUN(runsNum) for(declare.runs(runsNum); startTimer(), next(); stopTimer()) for(int r = 0; r < runsNum; ++r)
517 namespace comparators
521 struct CV_EXPORTS RectLess_
523 bool operator()(const cv::Rect_<T>& r1, const cv::Rect_<T>& r2) const
526 || (r1.x == r2.x && r1.y < r2.y)
527 || (r1.x == r2.x && r1.y == r2.y && r1.width < r2.width)
528 || (r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height < r2.height);
532 typedef RectLess_<int> RectLess;
534 struct CV_EXPORTS KeypointGreater
536 bool operator()(const cv::KeyPoint& kp1, const cv::KeyPoint& kp2) const
538 if(kp1.response > kp2.response) return true;
539 if(kp1.response < kp2.response) return false;
540 if(kp1.size > kp2.size) return true;
541 if(kp1.size < kp2.size) return false;
542 if(kp1.octave > kp2.octave) return true;
543 if(kp1.octave < kp2.octave) return false;
544 if(kp1.pt.y < kp2.pt.y) return false;
545 if(kp1.pt.y > kp2.pt.y) return true;
546 return kp1.pt.x < kp2.pt.x;
550 } //namespace comparators
552 void CV_EXPORTS sort(std::vector<cv::KeyPoint>& pts, cv::InputOutputArray descriptors);
555 #endif //__OPENCV_TS_PERF_HPP__