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