From 310c483da83f37895e78599f582aac3731a7a7de Mon Sep 17 00:00:00 2001 From: Alexey Spizhevoy Date: Mon, 24 Jan 2011 10:33:01 +0000 Subject: [PATCH] added first version of gpu performance tests --- modules/gpu/src/match_template.cpp | 2 +- samples/gpu/CMakeLists.txt | 4 +- samples/gpu/performance/CMakeLists.txt | 29 ++++++++ samples/gpu/performance/performance.cpp | 93 +++++++++++++++++++++++ samples/gpu/performance/performance.h | 99 +++++++++++++++++++++++++ samples/gpu/performance/tests.cpp | 30 ++++++++ 6 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 samples/gpu/performance/CMakeLists.txt create mode 100644 samples/gpu/performance/performance.cpp create mode 100644 samples/gpu/performance/performance.h create mode 100644 samples/gpu/performance/tests.cpp diff --git a/modules/gpu/src/match_template.cpp b/modules/gpu/src/match_template.cpp index 5f5807c30..d5345038d 100644 --- a/modules/gpu/src/match_template.cpp +++ b/modules/gpu/src/match_template.cpp @@ -178,7 +178,7 @@ namespace if (depth == CV_8U) return 300; break; case CV_TM_SQDIFF: - if (depth == CV_8U) return 500; + if (depth == CV_8U) return 300; break; } CV_Error(CV_StsBadArg, "getTemplateThreshold: unsupported match template mode"); diff --git a/samples/gpu/CMakeLists.txt b/samples/gpu/CMakeLists.txt index eb73fdd5d..c65c2e60b 100644 --- a/samples/gpu/CMakeLists.txt +++ b/samples/gpu/CMakeLists.txt @@ -47,7 +47,9 @@ if (BUILD_EXAMPLES) foreach(sample_filename ${gpu_samples}) get_filename_component(sample ${sample_filename} NAME_WE) MY_DEFINE_EXAMPLE(${sample} ${sample_filename}) - endforeach() + endforeach() + + include("performance/CMakeLists.txt") endif(BUILD_EXAMPLES) if (NOT WIN32) diff --git a/samples/gpu/performance/CMakeLists.txt b/samples/gpu/performance/CMakeLists.txt new file mode 100644 index 000000000..3a17b283a --- /dev/null +++ b/samples/gpu/performance/CMakeLists.txt @@ -0,0 +1,29 @@ +set(the_target "example_gpu_performance") + +file(GLOB sources "performance/*.cpp") +file(GLOB headers "performance/*.h") + +add_executable(${the_target} ${sources} ${headers}) + +set_target_properties(${the_target} PROPERTIES + OUTPUT_NAME "performance_gpu" + PROJECT_LABEL "(EXAMPLE_GPU) performance") + +add_dependencies(${the_target} opencv_core opencv_flann opencv_imgproc opencv_highgui + opencv_ml opencv_video opencv_objdetect opencv_features2d + opencv_calib3d opencv_legacy opencv_contrib opencv_gpu) + +target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} opencv_core + opencv_flann opencv_imgproc opencv_highgui opencv_ml opencv_video opencv_objdetect + opencv_features2d opencv_calib3d opencv_legacy opencv_contrib opencv_gpu) + +if(WIN32) + install(TARGETS ${the_target} RUNTIME DESTINATION "samples/gpu" COMPONENT main) +endif() + +if(NOT WIN32) + file(GLOB GPU_FILES performance/*.cpp performance/*.h) + install(FILES ${GPU_FILES} + DESTINATION share/opencv/samples/gpu/performance + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) +endif() \ No newline at end of file diff --git a/samples/gpu/performance/performance.cpp b/samples/gpu/performance/performance.cpp new file mode 100644 index 000000000..035a12354 --- /dev/null +++ b/samples/gpu/performance/performance.cpp @@ -0,0 +1,93 @@ +#include +#include "performance.h" + +using namespace std; +using namespace cv; + + +void Test::gen(Mat& mat, int rows, int cols, int type, Scalar low, Scalar high) +{ + mat.create(rows, cols, type); + + RNG rng(0); + rng.fill(mat, RNG::UNIFORM, low, high); +} + + +void Test::gen(Mat& mat, int rows, int cols, int type) +{ + mat.create(rows, cols, type); + + Mat mat8u(rows, cols * mat.elemSize(), CV_8U, mat.data, mat.step); + + RNG rng(0); + rng.fill(mat, RNG::UNIFORM, Scalar(0), Scalar(256)); +} + + +void TestSystem::run() +{ + cout << setiosflags(ios_base::left); + cout << " " << setw(10) << "CPU, ms" << setw(10) << "GPU, ms" + << setw(10) << "SPEEDUP" << "DESCRIPTION\n"; + cout << resetiosflags(ios_base::left); + + vector::iterator it = tests_.begin(); + for (; it != tests_.end(); ++it) + { + can_flush_ = false; + Test* test = *it; + + cout << endl << test->name() << ":\n"; + test->run(); + + flush(); + } + + cout << setiosflags(ios_base::fixed | ios_base::left); + cout << "\nCPU Total: " << setprecision(3) << cpu_total_ / getTickFrequency() << " sec\n"; + cout << "GPU Total: " << setprecision(3) << gpu_total_ / getTickFrequency() << " sec (x" + << setprecision(3) << (double)cpu_total_ / gpu_total_ << ")\n"; + cout << resetiosflags(ios_base::fixed | ios_base::left); +} + + +void TestSystem::flush() +{ + if (!can_flush_) + return; + + int cpu_time = static_cast(cpu_elapsed_ / getTickFrequency() * 1000.0); + int gpu_time = static_cast(gpu_elapsed_ / getTickFrequency() * 1000.0); + double speedup = (double)cpu_time / gpu_time; + + cpu_elapsed_ = 0; + gpu_elapsed_ = 0; + + cout << " " << setiosflags(ios_base::fixed | ios_base::left); + + stringstream stream; + stream << cpu_time; + cout << setw(10) << stream.str(); + + stream.str(""); + stream << gpu_time; + cout << setw(10) << stream.str(); + + stream.str(""); + stream << "x" << setprecision(3) << speedup; + cout << setw(10) << stream.str(); + + cout << description_.str(); + description_.str(""); + + cout << resetiosflags(ios_base::fixed | ios_base::left) << endl; + can_flush_ = false; +} + + +int main() +{ + TestSystem::instance()->run(); + return 0; +} \ No newline at end of file diff --git a/samples/gpu/performance/performance.h b/samples/gpu/performance/performance.h new file mode 100644 index 000000000..ef0787cf8 --- /dev/null +++ b/samples/gpu/performance/performance.h @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include + +class Test +{ +public: + Test(const std::string& name): name_(name) {} + + const std::string& name() const { return name_; } + + void gen(cv::Mat& mat, int rows, int cols, int type, + cv::Scalar low, cv::Scalar high); + + void gen(cv::Mat& mat, int rows, int cols, int type); + + virtual void run() = 0; + +private: + std::string name_; +}; + + +class TestSystem +{ +public: + static TestSystem* instance() + { + static TestSystem me; + return &me; + } + + void add(Test* test) { tests_.push_back(test); } + + void run(); + + void cpuOn() { cpu_started_ = cv::getTickCount(); } + + void cpuOff() + { + int64 delta = cv::getTickCount() - cpu_started_; + cpu_elapsed_ += delta; + cpu_total_ += delta; + can_flush_ = true; + } + + void gpuOn() { gpu_started_ = cv::getTickCount(); } + + void gpuOff() + { + int64 delta = cv::getTickCount() - gpu_started_; + gpu_elapsed_ += delta; + gpu_total_ += delta; + can_flush_ = true; + } + + // Ends current subtest and starts new one + std::stringstream& subtest() + { + flush(); + return description_; + } + +private: + TestSystem(): can_flush_(false), + cpu_elapsed_(0), cpu_total_(0), + gpu_elapsed_(0), gpu_total_(0) {}; + + void flush(); + + std::vector tests_; + + // Current test (subtest) description + std::stringstream description_; + + bool can_flush_; + + int64 cpu_started_, cpu_elapsed_, cpu_total_; + int64 gpu_started_, gpu_elapsed_, gpu_total_; +}; + + +#define TEST(name) \ + struct name##_test: public Test \ + { \ + name##_test(): Test(#name) { TestSystem::instance()->add(this); } \ + void run(); \ + } name##_test_instance; \ + void name##_test::run() + + +#define CPU_ON TestSystem::instance()->cpuOn() +#define GPU_ON TestSystem::instance()->gpuOn() +#define CPU_OFF TestSystem::instance()->cpuOff() +#define GPU_OFF TestSystem::instance()->gpuOff() +#define SUBTEST TestSystem::instance()->subtest() +#define DESCRIPTION TestSystem::instance()->subtest() \ No newline at end of file diff --git a/samples/gpu/performance/tests.cpp b/samples/gpu/performance/tests.cpp new file mode 100644 index 000000000..bd4957fd9 --- /dev/null +++ b/samples/gpu/performance/tests.cpp @@ -0,0 +1,30 @@ +#include +#include +#include "performance.h" + +using namespace std; +using namespace cv; + +TEST(matchTemplate) +{ + for (int templ_size = 5; templ_size <= 1000; templ_size *= 2) + { + SUBTEST << "img 3000, templ " << templ_size << ", 8U, SQDIFF"; + + Mat image; gen(image, 3000, 3000, CV_8U); + Mat templ; gen(templ, templ_size, templ_size, CV_8U); + Mat result; + + CPU_ON; + matchTemplate(image, templ, result, CV_TM_SQDIFF); + CPU_OFF; + + gpu::GpuMat d_image(image); + gpu::GpuMat d_templ(templ); + gpu::GpuMat d_result; + + GPU_ON; + gpu::matchTemplate(d_image, d_templ, d_result, CV_TM_SQDIFF); + GPU_OFF; + } +}