1 #ifndef __OPENCV_TS_PERF_HPP__
\r
2 #define __OPENCV_TS_PERF_HPP__
\r
4 #include "opencv2/core/core.hpp"
\r
5 #include "ts_gtest.h"
\r
8 #include "tbb/task_scheduler_init.h"
\r
11 #if defined(ANDROID) && defined(USE_ANDROID_LOGGING)
\r
12 #include <android/log.h>
\r
14 #define PERF_TESTS_LOG_TAG "OpenCV_perf"
\r
15 #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, PERF_TESTS_LOG_TAG, __VA_ARGS__))
\r
16 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, PERF_TESTS_LOG_TAG, __VA_ARGS__))
\r
17 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, PERF_TESTS_LOG_TAG, __VA_ARGS__))
\r
18 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, PERF_TESTS_LOG_TAG, __VA_ARGS__))
\r
20 #define LOGD(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
\r
21 #define LOGI(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
\r
22 #define LOGW(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
\r
23 #define LOGE(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
\r
30 /*****************************************************************************************\
\r
31 * Predefined typical frame sizes and typical test parameters *
\r
32 \*****************************************************************************************/
\r
33 const cv::Size szQVGA = cv::Size(320, 240);
\r
34 const cv::Size szVGA = cv::Size(640, 480);
\r
35 const cv::Size szSVGA = cv::Size(800, 600);
\r
36 const cv::Size szXGA = cv::Size(1024, 768);
\r
37 const cv::Size szSXGA = cv::Size(1280, 1024);
\r
39 const cv::Size sznHD = cv::Size(640, 360);
\r
40 const cv::Size szqHD = cv::Size(960, 540);
\r
41 const cv::Size sz720p = cv::Size(1280, 720);
\r
42 const cv::Size sz1080p = cv::Size(1920, 1080);
\r
44 const cv::Size sz2K = cv::Size(2048, 2048);
\r
46 const cv::Size szODD = cv::Size(127, 61);
\r
48 const cv::Size szSmall24 = cv::Size(24, 24);
\r
49 const cv::Size szSmall32 = cv::Size(32, 32);
\r
50 const cv::Size szSmall64 = cv::Size(64, 64);
\r
51 const cv::Size szSmall128 = cv::Size(128, 128);
\r
53 #define SZ_ALL_VGA ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA)
\r
54 #define SZ_ALL_GA ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA)
\r
55 #define SZ_ALL_HD ::testing::Values(::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
\r
56 #define SZ_ALL_SMALL ::testing::Values(::perf::szSmall24, ::perf::szSmall32, ::perf::szSmall64, ::perf::szSmall128)
\r
57 #define SZ_ALL ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA, ::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
\r
58 #define SZ_TYPICAL ::testing::Values(::perf::szVGA, ::perf::szqHD, ::perf::sz720p, ::perf::szODD)
\r
61 #define TYPICAL_MAT_SIZES ::perf::szVGA, ::perf::sz720p, ::perf::sz1080p, ::perf::szODD
\r
62 #define TYPICAL_MAT_TYPES CV_8UC1, CV_8UC4, CV_32FC1
\r
63 #define TYPICAL_MATS testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( TYPICAL_MAT_TYPES ) )
\r
64 #define TYPICAL_MATS_C1 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC1, CV_32FC1 ) )
\r
65 #define TYPICAL_MATS_C4 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC4 ) )
\r
68 /*****************************************************************************************\
\r
69 * MatType - printable wrapper over integer 'type' of Mat *
\r
70 \*****************************************************************************************/
\r
74 MatType(int val=0) : _type(val) {}
\r
75 operator int() const {return _type;}
\r
81 /*****************************************************************************************\
\r
82 * CV_ENUM and CV_FLAGS - macro to create printable wrappers for defines and enums *
\r
83 \*****************************************************************************************/
\r
85 #define CV_ENUM(class_name, ...) \
\r
86 class CV_EXPORTS class_name {\
\r
88 class_name(int val = 0) : _val(val) {}\
\r
89 operator int() const {return _val;}\
\r
90 void PrintTo(std::ostream* os) const {\
\r
91 const int vals[] = {__VA_ARGS__};\
\r
92 const char* svals = #__VA_ARGS__;\
\r
93 for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i){\
\r
94 while(isspace(svals[pos]) || svals[pos] == ',') ++pos;\
\r
96 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0)) ++pos;\
\r
97 if (_val == vals[i]) {\
\r
98 *os << std::string(svals + start, svals + pos);\
\r
105 typedef class_name value_type;\
\r
106 Container(class_name* first, size_t len): _begin(first), _end(first+len){}\
\r
107 const class_name* begin() const {return _begin;}\
\r
108 const class_name* end() const {return _end;}\
\r
109 private: class_name *_begin, *_end;\
\r
111 static Container all(){\
\r
112 static class_name vals[] = {__VA_ARGS__};\
\r
113 return Container(vals, sizeof(vals)/sizeof(vals[0]));\
\r
115 private: int _val;\
\r
117 inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); }
\r
119 #define CV_FLAGS(class_name, ...) \
\r
120 class CV_EXPORTS class_name {\
\r
122 class_name(int val = 0) : _val(val) {}\
\r
123 operator int() const {return _val;}\
\r
124 void PrintTo(std::ostream* os) const {\
\r
125 const int vals[] = {__VA_ARGS__};\
\r
126 const char* svals = #__VA_ARGS__;\
\r
128 bool first = true;\
\r
129 for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i){\
\r
130 while(isspace(svals[pos]) || svals[pos] == ',') ++pos;\
\r
132 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0)) ++pos;\
\r
133 if ((value & vals[i]) == vals[i]) {\
\r
134 value &= ~vals[i]; \
\r
135 if (first) first = false; else *os << "|"; \
\r
136 *os << std::string(svals + start, svals + pos);\
\r
137 if (!value) return;\
\r
140 if (first) *os << "UNKNOWN";\
\r
142 private: int _val;\
\r
144 inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); }
\r
146 CV_ENUM(MatDepth, CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, CV_USRTYPE1)
\r
148 /*****************************************************************************************\
\r
149 * Regression control utility for performance testing *
\r
150 \*****************************************************************************************/
\r
151 class CV_EXPORTS Regression
\r
154 static Regression& add(const std::string& name, cv::InputArray array, double eps = DBL_EPSILON);
\r
155 static void Init(const std::string& testSuitName, const std::string& ext = ".xml");
\r
157 Regression& operator() (const std::string& name, cv::InputArray array, double eps = DBL_EPSILON);
\r
160 static Regression& instance();
\r
164 Regression(const Regression&);
\r
165 Regression& operator=(const Regression&);
\r
167 cv::RNG regRNG;//own random numbers generator to make collection and verification work identical
\r
168 std::string storageInPath;
\r
169 std::string storageOutPath;
\r
170 cv::FileStorage storageIn;
\r
171 cv::FileStorage storageOut;
\r
172 cv::FileNode rootIn;
\r
173 std::string currentTestNodeName;
\r
174 cv::FileStorage& write();
\r
176 static std::string getCurrentTestNodeName();
\r
177 static bool isVector(cv::InputArray a);
\r
178 static double getElem(cv::Mat& m, int x, int y, int cn = 0);
\r
180 void init(const std::string& testSuitName, const std::string& ext);
\r
181 void write(cv::InputArray array);
\r
182 void write(cv::Mat m);
\r
183 void verify(cv::FileNode node, cv::InputArray array, double eps);
\r
184 void verify(cv::FileNode node, cv::Mat actual, double eps, std::string argname);
\r
187 #define SANITY_CHECK(array, ...) ::perf::Regression::add(#array, array , ## __VA_ARGS__)
\r
190 /*****************************************************************************************\
\r
191 * Container for performance metrics *
\r
192 \*****************************************************************************************/
\r
193 typedef struct CV_EXPORTS performance_metrics
\r
197 unsigned int samples;
\r
198 unsigned int outliers;
\r
200 double gstddev;//stddev for log(time)
\r
206 int terminationReason;
\r
210 TERM_ITERATIONS = 0,
\r
212 TERM_INTERRUPT = 2,
\r
213 TERM_EXCEPTION = 3,
\r
217 performance_metrics();
\r
218 } performance_metrics;
\r
221 /*****************************************************************************************\
\r
222 * Base fixture for performance tests *
\r
223 \*****************************************************************************************/
\r
224 class CV_EXPORTS TestBase: public ::testing::Test
\r
229 static void Init(int argc, const char* const argv[]);
\r
230 static std::string getDataPath(const std::string& relativePath);
\r
233 virtual void PerfTestBody() = 0;
\r
235 virtual void SetUp();
\r
236 virtual void TearDown();
\r
242 //_declareHelper declare;
\r
252 void reportMetrics(bool toJUnitXML = false);
\r
253 static void warmup(cv::InputOutputArray a, int wtype = WARMUP_READ);
\r
255 performance_metrics& calcMetrics();
\r
256 void RunPerfTestBody();
\r
258 typedef std::vector<std::pair<int, cv::Size> > SizeVector;
\r
259 typedef std::vector<int64> TimeVector;
\r
261 SizeVector inputData;
\r
262 SizeVector outputData;
\r
263 unsigned int getTotalInputSize() const;
\r
264 unsigned int getTotalOutputSize() const;
\r
270 static int64 timeLimitDefault;
\r
272 unsigned int nIters;
\r
273 unsigned int currentIter;
\r
275 performance_metrics metrics;
\r
276 void validateMetrics();
\r
278 static int64 _timeadjustment;
\r
279 static int64 _calibrate();
\r
281 static void warmup_impl(cv::Mat m, int wtype);
\r
282 static int getSizeInBytes(cv::InputArray a);
\r
283 static cv::Size getSize(cv::InputArray a);
\r
284 static void declareArray(SizeVector& sizes, cv::InputOutputArray a, int wtype = 0);
\r
286 class CV_EXPORTS _declareHelper
\r
289 _declareHelper& in(cv::InputOutputArray a1, int wtype = WARMUP_READ);
\r
290 _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, int wtype = WARMUP_READ);
\r
291 _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, int wtype = WARMUP_READ);
\r
292 _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, int wtype = WARMUP_READ);
\r
294 _declareHelper& out(cv::InputOutputArray a1, int wtype = WARMUP_WRITE);
\r
295 _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, int wtype = WARMUP_WRITE);
\r
296 _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, int wtype = WARMUP_WRITE);
\r
297 _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, int wtype = WARMUP_WRITE);
\r
299 _declareHelper& iterations(int n);
\r
300 _declareHelper& time(double timeLimitSecs);
\r
301 _declareHelper& tbb_threads(int n = -1);
\r
304 _declareHelper(TestBase* t);
\r
305 _declareHelper(const _declareHelper&);
\r
306 _declareHelper& operator=(const _declareHelper&);
\r
307 friend class TestBase;
\r
309 friend class _declareHelper;
\r
312 cv::Ptr<tbb::task_scheduler_init> p_tbb_initializer;
\r
316 _declareHelper declare;
\r
319 template<typename T> class TestBaseWithParam: public TestBase, public ::testing::WithParamInterface<T> {};
\r
321 typedef std::tr1::tuple<cv::Size, MatType> Size_MatType_t;
\r
322 typedef TestBaseWithParam<Size_MatType_t> Size_MatType;
\r
324 /*****************************************************************************************\
\r
325 * Print functions for googletest *
\r
326 \*****************************************************************************************/
\r
327 CV_EXPORTS void PrintTo(const MatType& t, std::ostream* os);
\r
334 CV_EXPORTS void PrintTo(const Size& sz, ::std::ostream* os);
\r
339 /*****************************************************************************************\
\r
340 * Macro definitions for performance tests *
\r
341 \*****************************************************************************************/
\r
342 #define PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) \
\r
343 test_case_name##_##test_name##_perf_namespace_proxy
\r
345 // Defines a performance test.
\r
347 // The first parameter is the name of the test case, and the second
\r
348 // parameter is the name of the test within the test case.
\r
350 // The user should put his test code between braces after using this
\r
353 // PERF_TEST(FooTest, InitializesCorrectly) {
\r
355 // EXPECT_TRUE(foo.StatusIsOK());
\r
357 #define PERF_TEST(test_case_name, test_name)\
\r
358 namespace PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) {\
\r
359 class TestBase {/*compile error for this class means that you are trying to use perf::TestBase as a fixture*/};\
\r
360 class test_case_name : public ::perf::TestBase {\
\r
362 test_case_name() {}\
\r
364 virtual void PerfTestBody();\
\r
366 TEST_F(test_case_name, test_name){ RunPerfTestBody(); }\
\r
368 void PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name)::test_case_name::PerfTestBody()
\r
370 // Defines a performance test that uses a test fixture.
\r
372 // The first parameter is the name of the test fixture class, which
\r
373 // also doubles as the test case name. The second parameter is the
\r
374 // name of the test within the test case.
\r
376 // A test fixture class must be declared earlier. The user should put
\r
377 // his test code between braces after using this macro. Example:
\r
379 // class FooTest : public ::perf::TestBase {
\r
381 // virtual void SetUp() { TestBase::SetUp(); b_.AddElement(3); }
\r
387 // PERF_TEST_F(FooTest, InitializesCorrectly) {
\r
388 // EXPECT_TRUE(a_.StatusIsOK());
\r
391 // PERF_TEST_F(FooTest, ReturnsElementCountCorrectly) {
\r
392 // EXPECT_EQ(0, a_.size());
\r
393 // EXPECT_EQ(1, b_.size());
\r
395 #define PERF_TEST_F(fixture, testname) \
\r
396 namespace PERF_PROXY_NAMESPACE_NAME_(fixture, testname) {\
\r
397 class TestBase {/*compile error for this class means that you are trying to use perf::TestBase as a fixture*/};\
\r
398 class fixture : public ::fixture {\
\r
402 virtual void PerfTestBody();\
\r
404 TEST_F(fixture, testname){ RunPerfTestBody(); }\
\r
406 void PERF_PROXY_NAMESPACE_NAME_(fixture, testname)::fixture::PerfTestBody()
\r
408 // Defines a parametrized performance test.
\r
410 // The first parameter is the name of the test fixture class, which
\r
411 // also doubles as the test case name. The second parameter is the
\r
412 // name of the test within the test case.
\r
414 // The user should put his test code between braces after using this
\r
417 // typedef ::perf::TestBaseWithParam<cv::Size> FooTest;
\r
419 // PERF_TEST_P(FooTest, DoTestingRight, ::testing::Values(::perf::szVGA, ::perf::sz720p) {
\r
420 // cv::Mat b(GetParam(), CV_8U, cv::Scalar(10));
\r
421 // cv::Mat a(GetParam(), CV_8U, cv::Scalar(20));
\r
422 // cv::Mat c(GetParam(), CV_8U, cv::Scalar(0));
\r
424 // declare.in(a, b).out(c).time(0.5);
\r
426 // SIMPLE_TEST_CYCLE() cv::add(a, b, c);
\r
428 // SANITY_CHECK(c);
\r
430 #define PERF_TEST_P(fixture, name, params) \
\r
431 class fixture##_##name : public ::fixture {\
\r
433 fixture##_##name() {}\
\r
435 virtual void PerfTestBody();\
\r
437 TEST_P(fixture##_##name, name /*perf*/){ RunPerfTestBody(); }\
\r
438 INSTANTIATE_TEST_CASE_P(/*none*/, fixture##_##name, params);\
\r
439 void fixture##_##name::PerfTestBody()
\r
442 #define CV_PERF_TEST_MAIN(testsuitname) \
\r
443 int main(int argc, char **argv)\
\r
445 ::perf::Regression::Init(#testsuitname);\
\r
446 ::perf::TestBase::Init(argc, argv);\
\r
447 ::testing::InitGoogleTest(&argc, argv);\
\r
448 return RUN_ALL_TESTS();\
\r
451 #define TEST_CYCLE(n) for(declare.iterations(n); startTimer(), next(); stopTimer())
\r
452 #define SIMPLE_TEST_CYCLE() for(; startTimer(), next(); stopTimer())
\r
457 //GTEST_DECLARE_int32_(allowed_outliers);
\r
460 #endif //__OPENCV_TS_PERF_HPP__
\r