Merge pull request #10806 from alalek:build_cxx17
[platform/upstream/opencv.git] / modules / ts / include / opencv2 / ts / ts_perf.hpp
1 #ifndef OPENCV_TS_PERF_HPP
2 #define OPENCV_TS_PERF_HPP
3
4 #include "opencv2/ts.hpp"
5
6 #include "ts_gtest.h"
7 #include "ts_ext.hpp"
8
9 #include <functional>
10
11 #if !(defined(LOGD) || defined(LOGI) || defined(LOGW) || defined(LOGE))
12 # if defined(__ANDROID__) && defined(USE_ANDROID_LOGGING)
13 #  include <android/log.h>
14
15 #  define PERF_TESTS_LOG_TAG "OpenCV_perf"
16 #  define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, PERF_TESTS_LOG_TAG, __VA_ARGS__))
17 #  define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, PERF_TESTS_LOG_TAG, __VA_ARGS__))
18 #  define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, PERF_TESTS_LOG_TAG, __VA_ARGS__))
19 #  define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, PERF_TESTS_LOG_TAG, __VA_ARGS__))
20 # else
21 #  define LOGD(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
22 #  define LOGI(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
23 #  define LOGW(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
24 #  define LOGE(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
25 # endif
26 #endif
27
28 // declare major namespaces to avoid errors on unknown namespace
29 namespace cv { namespace cuda {} namespace ocl {} }
30 namespace cvtest { }
31
32 namespace perf
33 {
34
35 // Tuple stuff from Google Tests
36 using testing::get;
37 using testing::make_tuple;
38 using testing::tuple;
39 using testing::tuple_size;
40 using testing::tuple_element;
41
42 class TestBase;
43
44 /*****************************************************************************************\
45 *                Predefined typical frame sizes and typical test parameters               *
46 \*****************************************************************************************/
47 const static cv::Size szQVGA = cv::Size(320, 240);
48 const static cv::Size szVGA = cv::Size(640, 480);
49 const static cv::Size szSVGA = cv::Size(800, 600);
50 const static cv::Size szXGA = cv::Size(1024, 768);
51 const static cv::Size szSXGA = cv::Size(1280, 1024);
52 const static cv::Size szWQHD = cv::Size(2560, 1440);
53
54 const static cv::Size sznHD = cv::Size(640, 360);
55 const static cv::Size szqHD = cv::Size(960, 540);
56 const static cv::Size sz240p = szQVGA;
57 const static cv::Size sz720p = cv::Size(1280, 720);
58 const static cv::Size sz1080p = cv::Size(1920, 1080);
59 const static cv::Size sz1440p = szWQHD;
60 const static cv::Size sz2160p = cv::Size(3840, 2160);//UHDTV1 4K
61 const static cv::Size sz4320p = cv::Size(7680, 4320);//UHDTV2 8K
62
63 const static cv::Size sz3MP = cv::Size(2048, 1536);
64 const static cv::Size sz5MP = cv::Size(2592, 1944);
65 const static cv::Size sz2K = cv::Size(2048, 2048);
66
67 const static cv::Size szODD = cv::Size(127, 61);
68
69 const static cv::Size szSmall24 = cv::Size(24, 24);
70 const static cv::Size szSmall32 = cv::Size(32, 32);
71 const static cv::Size szSmall64 = cv::Size(64, 64);
72 const static cv::Size szSmall128 = cv::Size(128, 128);
73
74 #define SZ_ALL_VGA ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA)
75 #define SZ_ALL_GA  ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA)
76 #define SZ_ALL_HD  ::testing::Values(::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
77 #define SZ_ALL_SMALL ::testing::Values(::perf::szSmall24, ::perf::szSmall32, ::perf::szSmall64, ::perf::szSmall128)
78 #define SZ_ALL  ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA, ::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
79 #define SZ_TYPICAL  ::testing::Values(::perf::szVGA, ::perf::szqHD, ::perf::sz720p, ::perf::szODD)
80
81
82 #define TYPICAL_MAT_SIZES ::perf::szVGA, ::perf::sz720p, ::perf::sz1080p, ::perf::szODD
83 #define TYPICAL_MAT_TYPES CV_8UC1, CV_8UC4, CV_32FC1
84 #define TYPICAL_MATS testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( TYPICAL_MAT_TYPES ) )
85 #define TYPICAL_MATS_C1 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC1, CV_32FC1 ) )
86 #define TYPICAL_MATS_C4 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC4 ) )
87
88
89 /*****************************************************************************************\
90 *                MatType - printable wrapper over integer 'type' of Mat                   *
91 \*****************************************************************************************/
92 class MatType
93 {
94 public:
95     MatType(int val=0) : _type(val) {}
96     operator int() const {return _type;}
97
98 private:
99     int _type;
100 };
101
102 /*****************************************************************************************\
103 *     CV_ENUM and CV_FLAGS - macro to create printable wrappers for defines and enums     *
104 \*****************************************************************************************/
105
106 #define CV_ENUM(class_name, ...)                                                        \
107     namespace {                                                                         \
108     using namespace cv;using namespace cv::cuda; using namespace cv::ocl;               \
109     struct class_name {                                                                 \
110         class_name(int val = 0) : val_(val) {}                                          \
111         operator int() const { return val_; }                                           \
112         void PrintTo(std::ostream* os) const {                                          \
113             const int vals[] = { __VA_ARGS__ };                                         \
114             const char* svals = #__VA_ARGS__;                                           \
115             for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i) {         \
116                 while(isspace(svals[pos]) || svals[pos] == ',') ++pos;                  \
117                 int start = pos;                                                        \
118                 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0))   \
119                     ++pos;                                                              \
120                 if (val_ == vals[i]) {                                                  \
121                     *os << std::string(svals + start, svals + pos);                     \
122                     return;                                                             \
123                 }                                                                       \
124             }                                                                           \
125             *os << "UNKNOWN";                                                           \
126         }                                                                               \
127         static ::testing::internal::ParamGenerator<class_name> all() {                  \
128             const class_name vals[] = { __VA_ARGS__ };                                  \
129             return ::testing::ValuesIn(vals);                                           \
130         }                                                                               \
131     private: int val_;                                                                  \
132     };                                                                                  \
133     static inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
134
135 #define CV_FLAGS(class_name, ...)                                                       \
136     namespace {                                                                         \
137     struct class_name {                                                                 \
138         class_name(int val = 0) : val_(val) {}                                          \
139         operator int() const { return val_; }                                           \
140         void PrintTo(std::ostream* os) const {                                          \
141             using namespace cv;using namespace cv::cuda; using namespace cv::ocl;        \
142             const int vals[] = { __VA_ARGS__ };                                         \
143             const char* svals = #__VA_ARGS__;                                           \
144             int value = val_;                                                           \
145             bool first = true;                                                          \
146             for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i) {         \
147                 while(isspace(svals[pos]) || svals[pos] == ',') ++pos;                  \
148                 int start = pos;                                                        \
149                 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0))   \
150                     ++pos;                                                              \
151                 if ((value & vals[i]) == vals[i]) {                                     \
152                     value &= ~vals[i];                                                  \
153                     if (first) first = false; else *os << "|";                          \
154                     *os << std::string(svals + start, svals + pos);                     \
155                     if (!value) return;                                                 \
156                 }                                                                       \
157             }                                                                           \
158             if (first) *os << "UNKNOWN";                                                \
159         }                                                                               \
160     private: int val_;                                                                  \
161     };                                                                                  \
162     static inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
163
164 CV_ENUM(MatDepth, CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, CV_USRTYPE1)
165
166 /*****************************************************************************************\
167 *                 Regression control utility for performance testing                      *
168 \*****************************************************************************************/
169 enum ERROR_TYPE
170 {
171     ERROR_ABSOLUTE = 0,
172     ERROR_RELATIVE = 1
173 };
174
175 class Regression
176 {
177 public:
178     static Regression& add(TestBase* test, const std::string& name, cv::InputArray array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
179     static Regression& addMoments(TestBase* test, const std::string& name, const cv::Moments & array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
180     static Regression& addKeypoints(TestBase* test, const std::string& name, const std::vector<cv::KeyPoint>& array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
181     static Regression& addMatches(TestBase* test, const std::string& name, const std::vector<cv::DMatch>& array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
182     static void Init(const std::string& testSuitName, const std::string& ext = ".xml");
183
184     Regression& operator() (const std::string& name, cv::InputArray array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
185
186 private:
187     static Regression& instance();
188     Regression();
189     ~Regression();
190
191     Regression(const Regression&);
192     Regression& operator=(const Regression&);
193
194     cv::RNG regRNG;//own random numbers generator to make collection and verification work identical
195     std::string storageInPath;
196     std::string storageOutPath;
197     cv::FileStorage storageIn;
198     cv::FileStorage storageOut;
199     cv::FileNode rootIn;
200     std::string currentTestNodeName;
201     std::string suiteName;
202
203     cv::FileStorage& write();
204
205     static std::string getCurrentTestNodeName();
206     static bool isVector(cv::InputArray a);
207     static double getElem(cv::Mat& m, int x, int y, int cn = 0);
208
209     void init(const std::string& testSuitName, const std::string& ext);
210     void write(cv::InputArray array);
211     void write(cv::Mat m);
212     void verify(cv::FileNode node, cv::InputArray array, double eps, ERROR_TYPE err);
213     void verify(cv::FileNode node, cv::Mat actual, double eps, std::string argname, ERROR_TYPE err);
214 };
215
216 #define SANITY_CHECK(array, ...) ::perf::Regression::add(this, #array, array , ## __VA_ARGS__)
217 #define SANITY_CHECK_MOMENTS(array, ...) ::perf::Regression::addMoments(this, #array, array , ## __VA_ARGS__)
218 #define SANITY_CHECK_KEYPOINTS(array, ...) ::perf::Regression::addKeypoints(this, #array, array , ## __VA_ARGS__)
219 #define SANITY_CHECK_MATCHES(array, ...) ::perf::Regression::addMatches(this, #array, array , ## __VA_ARGS__)
220 #define SANITY_CHECK_NOTHING() this->setVerified()
221
222 class GpuPerf
223 {
224 public:
225   static bool targetDevice();
226 };
227
228 #define PERF_RUN_CUDA()  ::perf::GpuPerf::targetDevice()
229
230 /*****************************************************************************************\
231 *                            Container for performance metrics                            *
232 \*****************************************************************************************/
233 typedef struct performance_metrics
234 {
235     size_t bytesIn;
236     size_t bytesOut;
237     unsigned int samples;
238     unsigned int outliers;
239     double gmean;
240     double gstddev;//stddev for log(time)
241     double mean;
242     double stddev;
243     double median;
244     double min;
245     double frequency;
246     int terminationReason;
247
248     enum
249     {
250         TERM_ITERATIONS = 0,
251         TERM_TIME = 1,
252         TERM_INTERRUPT = 2,
253         TERM_EXCEPTION = 3,
254         TERM_SKIP_TEST = 4, // there are some limitations and test should be skipped
255         TERM_UNKNOWN = -1
256     };
257
258     performance_metrics();
259     void clear();
260 } performance_metrics;
261
262
263 /*****************************************************************************************\
264 *                           Strategy for performance measuring                            *
265 \*****************************************************************************************/
266 enum PERF_STRATEGY
267 {
268     PERF_STRATEGY_DEFAULT = -1,
269     PERF_STRATEGY_BASE = 0,
270     PERF_STRATEGY_SIMPLE = 1
271 };
272
273
274 /*****************************************************************************************\
275 *                           Base fixture for performance tests                            *
276 \*****************************************************************************************/
277 #ifdef CV_COLLECT_IMPL_DATA
278 // Implementation collection processing class.
279 // Accumulates and shapes implementation data.
280 typedef struct ImplData
281 {
282     bool ipp;
283     bool icv;
284     bool ipp_mt;
285     bool ocl;
286     bool plain;
287     std::vector<int> implCode;
288     std::vector<cv::String> funName;
289
290     ImplData()
291     {
292         Reset();
293     }
294
295     void Reset()
296     {
297         cv::setImpl(0);
298         ipp = icv = ocl = ipp_mt = false;
299         implCode.clear();
300         funName.clear();
301     }
302
303     void GetImpl()
304     {
305         flagsToVars(cv::getImpl(implCode, funName));
306     }
307
308     std::vector<cv::String> GetCallsForImpl(int impl)
309     {
310         std::vector<cv::String> out;
311
312         for(int i = 0; i < (int)implCode.size(); i++)
313         {
314             if(impl == implCode[i])
315                 out.push_back(funName[i]);
316         }
317         return out;
318     }
319
320     // Remove duplicate entries
321     void ShapeUp()
322     {
323         std::vector<int> savedCode;
324         std::vector<cv::String> savedName;
325
326         for(int i = 0; i < (int)implCode.size(); i++)
327         {
328             bool match = false;
329             for(int j = 0; j < (int)savedCode.size(); j++)
330             {
331                 if(implCode[i] == savedCode[j] && !funName[i].compare(savedName[j]))
332                 {
333                     match = true;
334                     break;
335                 }
336             }
337             if(!match)
338             {
339                 savedCode.push_back(implCode[i]);
340                 savedName.push_back(funName[i]);
341             }
342         }
343
344         implCode = savedCode;
345         funName = savedName;
346     }
347
348     // convert flags register to more handy variables
349     void flagsToVars(int flags)
350     {
351 #if defined(HAVE_IPP_ICV)
352         ipp    = 0;
353         icv    = ((flags&CV_IMPL_IPP) > 0);
354 #else
355         ipp    = ((flags&CV_IMPL_IPP) > 0);
356         icv    = 0;
357 #endif
358         ipp_mt = ((flags&CV_IMPL_MT) > 0);
359         ocl    = ((flags&CV_IMPL_OCL) > 0);
360         plain  = (flags == 0);
361     }
362
363 } ImplData;
364 #endif
365
366 #ifdef ENABLE_INSTRUMENTATION
367 class InstumentData
368 {
369 public:
370     static ::cv::String treeToString();
371     static void         printTree();
372 };
373 #endif
374
375 class TestBase: public ::testing::Test
376 {
377 public:
378     TestBase();
379
380     static void Init(int argc, const char* const argv[]);
381     static void Init(const std::vector<std::string> & availableImpls,
382                      int argc, const char* const argv[]);
383     static void RecordRunParameters();
384     static std::string getDataPath(const std::string& relativePath);
385     static std::string getSelectedImpl();
386
387     static enum PERF_STRATEGY getCurrentModulePerformanceStrategy();
388     static enum PERF_STRATEGY setModulePerformanceStrategy(enum PERF_STRATEGY strategy);
389
390     class PerfSkipTestException: public cv::Exception
391     {
392     public:
393         int dummy; // workaround for MacOSX Xcode 7.3 bug (don't make class "empty")
394         PerfSkipTestException() : dummy(0) {}
395     };
396
397 protected:
398     virtual void PerfTestBody() = 0;
399
400     virtual void SetUp();
401     virtual void TearDown();
402
403     bool startTimer(); // bool is dummy for conditional loop
404     void stopTimer();
405     bool next();
406
407     PERF_STRATEGY getCurrentPerformanceStrategy() const;
408
409     enum WarmUpType
410     {
411         WARMUP_READ,
412         WARMUP_WRITE,
413         WARMUP_RNG,
414         WARMUP_NONE
415     };
416
417     void reportMetrics(bool toJUnitXML = false);
418     static void warmup(cv::InputOutputArray a, WarmUpType wtype = WARMUP_READ);
419
420     performance_metrics& calcMetrics();
421
422     void RunPerfTestBody();
423
424 #ifdef CV_COLLECT_IMPL_DATA
425     ImplData implConf;
426 #endif
427 #ifdef ENABLE_INSTRUMENTATION
428     InstumentData instrConf;
429 #endif
430
431 private:
432     typedef std::vector<std::pair<int, cv::Size> > SizeVector;
433     typedef std::vector<int64> TimeVector;
434
435     SizeVector inputData;
436     SizeVector outputData;
437     unsigned int getTotalInputSize() const;
438     unsigned int getTotalOutputSize() const;
439
440     enum PERF_STRATEGY testStrategy;
441
442     TimeVector times;
443     int64 lastTime;
444     int64 totalTime;
445     int64 timeLimit;
446     static int64 timeLimitDefault;
447     static unsigned int iterationsLimitDefault;
448
449     unsigned int minIters;
450     unsigned int nIters;
451     unsigned int currentIter;
452     unsigned int runsPerIteration;
453     unsigned int perfValidationStage;
454
455     performance_metrics metrics;
456     void validateMetrics();
457
458     static int64 _timeadjustment;
459     static int64 _calibrate();
460
461     static void warmup_impl(cv::Mat m, WarmUpType wtype);
462     static int getSizeInBytes(cv::InputArray a);
463     static cv::Size getSize(cv::InputArray a);
464     static void declareArray(SizeVector& sizes, cv::InputOutputArray a, WarmUpType wtype);
465
466     class _declareHelper
467     {
468     public:
469         _declareHelper& in(cv::InputOutputArray a1, WarmUpType wtype = WARMUP_READ);
470         _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, WarmUpType wtype = WARMUP_READ);
471         _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, WarmUpType wtype = WARMUP_READ);
472         _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, WarmUpType wtype = WARMUP_READ);
473
474         _declareHelper& out(cv::InputOutputArray a1, WarmUpType wtype = WARMUP_WRITE);
475         _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, WarmUpType wtype = WARMUP_WRITE);
476         _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, WarmUpType wtype = WARMUP_WRITE);
477         _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, WarmUpType wtype = WARMUP_WRITE);
478
479         _declareHelper& iterations(unsigned int n);
480         _declareHelper& time(double timeLimitSecs);
481         _declareHelper& tbb_threads(int n = -1);
482         _declareHelper& runs(unsigned int runsNumber);
483
484         _declareHelper& strategy(enum PERF_STRATEGY s);
485     private:
486         TestBase* test;
487         _declareHelper(TestBase* t);
488         _declareHelper(const _declareHelper&);
489         _declareHelper& operator=(const _declareHelper&);
490         friend class TestBase;
491     };
492     friend class _declareHelper;
493
494     bool verified;
495
496 public:
497     _declareHelper declare;
498
499     void setVerified() { this->verified = true; }
500 };
501
502 template<typename T> class TestBaseWithParam: public TestBase, public ::testing::WithParamInterface<T> {};
503
504 typedef tuple<cv::Size, MatType> Size_MatType_t;
505 typedef TestBaseWithParam<Size_MatType_t> Size_MatType;
506
507 /*****************************************************************************************\
508 *                              Print functions for googletest                             *
509 \*****************************************************************************************/
510 void PrintTo(const MatType& t, std::ostream* os);
511
512 } //namespace perf
513
514 namespace cv
515 {
516
517 void PrintTo(const String& str, ::std::ostream* os);
518 void PrintTo(const Size& sz, ::std::ostream* os);
519
520 } //namespace cv
521
522
523 /*****************************************************************************************\
524 *                        Macro definitions for performance tests                          *
525 \*****************************************************************************************/
526
527 #define CV__PERF_TEST_BODY_IMPL(name) \
528     { \
529        CV__TEST_NAMESPACE_CHECK \
530        CV__TRACE_APP_FUNCTION_NAME("PERF_TEST: " name); \
531        RunPerfTestBody(); \
532     }
533
534 #define PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) \
535   test_case_name##_##test_name##_perf_namespace_proxy
536
537 // Defines a performance test.
538 //
539 // The first parameter is the name of the test case, and the second
540 // parameter is the name of the test within the test case.
541 //
542 // The user should put his test code between braces after using this
543 // macro.  Example:
544 //
545 //   PERF_TEST(FooTest, InitializesCorrectly) {
546 //     Foo foo;
547 //     EXPECT_TRUE(foo.StatusIsOK());
548 //   }
549 #define PERF_TEST(test_case_name, test_name)\
550     namespace PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) {\
551      class TestBase {/*compile error for this class means that you are trying to use perf::TestBase as a fixture*/};\
552      class test_case_name : public ::perf::TestBase {\
553       public:\
554        test_case_name() {}\
555       protected:\
556        virtual void PerfTestBody();\
557      };\
558      TEST_F(test_case_name, test_name){ CV__PERF_TEST_BODY_IMPL(#test_case_name "_" #test_name); }\
559     }\
560     void PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name)::test_case_name::PerfTestBody()
561
562 // Defines a performance test that uses a test fixture.
563 //
564 // The first parameter is the name of the test fixture class, which
565 // also doubles as the test case name.  The second parameter is the
566 // name of the test within the test case.
567 //
568 // A test fixture class must be declared earlier.  The user should put
569 // his test code between braces after using this macro.  Example:
570 //
571 //   class FooTest : public ::perf::TestBase {
572 //    protected:
573 //     virtual void SetUp() { TestBase::SetUp(); b_.AddElement(3); }
574 //
575 //     Foo a_;
576 //     Foo b_;
577 //   };
578 //
579 //   PERF_TEST_F(FooTest, InitializesCorrectly) {
580 //     EXPECT_TRUE(a_.StatusIsOK());
581 //   }
582 //
583 //   PERF_TEST_F(FooTest, ReturnsElementCountCorrectly) {
584 //     EXPECT_EQ(0, a_.size());
585 //     EXPECT_EQ(1, b_.size());
586 //   }
587 #define PERF_TEST_F(fixture, testname) \
588     namespace PERF_PROXY_NAMESPACE_NAME_(fixture, testname) {\
589      class TestBase {/*compile error for this class means that you are trying to use perf::TestBase as a fixture*/};\
590      class fixture : public ::fixture {\
591       public:\
592        fixture() {}\
593       protected:\
594        virtual void PerfTestBody();\
595      };\
596      TEST_F(fixture, testname){ CV__PERF_TEST_BODY_IMPL(#fixture "_" #testname); }\
597     }\
598     void PERF_PROXY_NAMESPACE_NAME_(fixture, testname)::fixture::PerfTestBody()
599
600 // Defines a parametrized performance test.
601 //
602 // @Note PERF_TEST_P() below violates behavior of original Google Tests - there is no tests instantiation in original TEST_P()
603 // This macro is intended for usage with separate INSTANTIATE_TEST_CASE_P macro
604 #define PERF_TEST_P_(test_case_name, test_name) CV__TEST_P(test_case_name, test_name, PerfTestBody, CV__PERF_TEST_BODY_IMPL)
605
606 // Defines a parametrized performance test.
607 //
608 // @Note Original TEST_P() macro doesn't instantiate tests with parameters. To keep original usage use PERF_TEST_P_() macro
609 //
610 // The first parameter is the name of the test fixture class, which
611 // also doubles as the test case name.  The second parameter is the
612 // name of the test within the test case.
613 //
614 // The user should put his test code between braces after using this
615 // macro.  Example:
616 //
617 //   typedef ::perf::TestBaseWithParam<cv::Size> FooTest;
618 //
619 //   PERF_TEST_P(FooTest, DoTestingRight, ::testing::Values(::perf::szVGA, ::perf::sz720p) {
620 //     cv::Mat b(GetParam(), CV_8U, cv::Scalar(10));
621 //     cv::Mat a(GetParam(), CV_8U, cv::Scalar(20));
622 //     cv::Mat c(GetParam(), CV_8U, cv::Scalar(0));
623 //
624 //     declare.in(a, b).out(c).time(0.5);
625 //
626 //     TEST_CYCLE() cv::add(a, b, c);
627 //
628 //     SANITY_CHECK(c);
629 //   }
630 #define PERF_TEST_P(fixture, name, params)  \
631     class fixture##_##name : public fixture {\
632      public:\
633       fixture##_##name() {}\
634      protected:\
635       virtual void PerfTestBody();\
636     };\
637     CV__TEST_P(fixture##_##name, name, PerfTestBodyDummy, CV__PERF_TEST_BODY_IMPL){} \
638     INSTANTIATE_TEST_CASE_P(/*none*/, fixture##_##name, params);\
639     void fixture##_##name::PerfTestBody()
640
641 #ifndef __CV_TEST_EXEC_ARGS
642 #if defined(_MSC_VER) && (_MSC_VER <= 1400)
643 #define __CV_TEST_EXEC_ARGS(...)    \
644     while (++argc >= (--argc,-1)) {__VA_ARGS__; break;} /*this ugly construction is needed for VS 2005*/
645 #else
646 #define __CV_TEST_EXEC_ARGS(...)    \
647     __VA_ARGS__;
648 #endif
649 #endif
650
651 #ifdef HAVE_OPENCL
652 namespace cvtest { namespace ocl {
653 void dumpOpenCLDevice();
654 }}
655 #define TEST_DUMP_OCL_INFO cvtest::ocl::dumpOpenCLDevice();
656 #else
657 #define TEST_DUMP_OCL_INFO
658 #endif
659
660
661 #define CV_PERF_TEST_MAIN_INTERNALS(modulename, impls, ...)     \
662     CV_TRACE_FUNCTION(); \
663     { CV_TRACE_REGION("INIT"); \
664     ::perf::Regression::Init(#modulename); \
665     ::perf::TestBase::Init(std::vector<std::string>(impls, impls + sizeof impls / sizeof *impls), \
666                            argc, argv); \
667     ::testing::InitGoogleTest(&argc, argv); \
668     cvtest::printVersionInfo(); \
669     ::testing::Test::RecordProperty("cv_module_name", #modulename); \
670     ::perf::TestBase::RecordRunParameters(); \
671     __CV_TEST_EXEC_ARGS(__VA_ARGS__) \
672     TEST_DUMP_OCL_INFO \
673     } \
674     return RUN_ALL_TESTS();
675
676 // impls must be an array, not a pointer; "plain" should always be one of the implementations
677 #define CV_PERF_TEST_MAIN_WITH_IMPLS(modulename, impls, ...) \
678 int main(int argc, char **argv)\
679 {\
680     CV_PERF_TEST_MAIN_INTERNALS(modulename, impls, __VA_ARGS__)\
681 }
682
683 #define CV_PERF_TEST_MAIN(modulename, ...) \
684 int main(int argc, char **argv)\
685 {\
686     const char * plain_only[] = { "plain" };\
687     CV_PERF_TEST_MAIN_INTERNALS(modulename, plain_only, __VA_ARGS__)\
688 }
689
690 //! deprecated
691 #define TEST_CYCLE_N(n) for(declare.iterations(n); next() && startTimer(); stopTimer())
692 //! deprecated
693 #define TEST_CYCLE() for(; next() && startTimer(); stopTimer())
694 //! deprecated
695 #define TEST_CYCLE_MULTIRUN(runsNum) for(declare.runs(runsNum); next() && startTimer(); stopTimer()) for(int r = 0; r < runsNum; ++r)
696
697 #define PERF_SAMPLE_BEGIN() \
698     for(; next() && startTimer(); stopTimer()) \
699     { \
700         CV_TRACE_REGION("iteration");
701 #define PERF_SAMPLE_END() \
702     }
703
704 namespace perf
705 {
706 namespace comparators
707 {
708
709 template<typename T>
710 #ifdef CV_CXX11
711 struct RectLess_
712 #else
713 struct RectLess_ : public std::binary_function<cv::Rect_<T>, cv::Rect_<T>, bool>
714 #endif
715 {
716   bool operator()(const cv::Rect_<T>& r1, const cv::Rect_<T>& r2) const
717   {
718     return r1.x < r2.x ||
719             (r1.x == r2.x && r1.y < r2.y) ||
720             (r1.x == r2.x && r1.y == r2.y && r1.width < r2.width) ||
721             (r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height < r2.height);
722   }
723 };
724
725 typedef RectLess_<int> RectLess;
726
727 #ifdef CV_CXX11
728 struct KeypointGreater
729 #else
730 struct KeypointGreater : public std::binary_function<cv::KeyPoint, cv::KeyPoint, bool>
731 #endif
732 {
733     bool operator()(const cv::KeyPoint& kp1, const cv::KeyPoint& kp2) const
734     {
735         if (kp1.response > kp2.response) return true;
736         if (kp1.response < kp2.response) return false;
737         if (kp1.size > kp2.size) return true;
738         if (kp1.size < kp2.size) return false;
739         if (kp1.octave > kp2.octave) return true;
740         if (kp1.octave < kp2.octave) return false;
741         if (kp1.pt.y < kp2.pt.y) return false;
742         if (kp1.pt.y > kp2.pt.y) return true;
743         return kp1.pt.x < kp2.pt.x;
744     }
745 };
746
747 } //namespace comparators
748
749 void sort(std::vector<cv::KeyPoint>& pts, cv::InputOutputArray descriptors);
750 } //namespace perf
751
752 #endif //OPENCV_TS_PERF_HPP