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