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