我目前使用OpenCV和ImageMagick进行一些吞吐量基准测试,我发现使用GPU比CPU更快。我们在网站上的用例是根据服务调用动态调整主副本请求的大小,并尝试评估GPU是否有意义动态调整每个服务调用的大小。
分享我为OpenCV编写的代码。我正在为串行存储在文件夹中的所有图像运行以下函数。最终我正在运行N个这样的过程来实现X个图像调整大小。我想了解我的方法是否不正确评估或者如果用例没有不适合典型的GPU用例。什么可能限制GPU性能。我甚至没有将利用率最大化到接近100%的任何地方
resizeGPU.cpp : {
cv::Mat::setDefaultAllocator(cv::cuda::HostMem::getAllocator (cv::cuda::HostMem::AllocType::PAGE_LOCKED));
auto t_start = std::chrono::high_resolution_clock::now();
Mat src = imread(input_file,CV_LOAD_IMAGE_COLOR);
auto t_end_read = std::chrono::high_resolution_clock::now();
if(!src.data){
std::cout<<"Image Not Found: "<< input_file << std::endl;
return;
}
cuda::GpuMat d_src;
d_src.upload(src,stream);
auto t_end_h2d = std::chrono::high_resolution_clock::now();
cuda::GpuMat d_dst;
cuda::resize(d_src, d_dst, Size(400, 400),0,0, CV_INTER_AREA,stream);
auto t_end_resize = std::chrono::high_resolution_clock::now();
Mat dst;
d_dst.download(dst,stream);
auto t_end_d2h = std::chrono::high_resolution_clock::now();
std::cout<<"read,"<<std::chrono::duration<double, std::milli>(t_end_read-t_start).count()<<",host2device,"<<std::chrono::duration<double, std::milli>(t_end_h2d-t_end_read).count()
<<",resize,"<<std::chrono::duration<double, std::milli>(t_end_resize-t_end_h2d).count()
<<",device2host,"<<std::chrono::duration<double, std::milli>(t_end_d2h-t_end_resize).count()
<<",total,"<<std::chrono::duration<double, std::milli>(t_end_d2h-t_start).count()<<endl;
}
resizeCPU.cpp:
auto t_start = std::chrono::high_resolution_clock::now();
Mat src = imread(input_file,CV_LOAD_IMAGE_COLOR);
auto t_end_read = std::chrono::high_resolution_clock::now();
if(!src.data){
std::cout<<"Image Not Found: "<< input_file << std::endl;
return;
}
Mat dst;
resize(src, dst, Size(400, 400),0,0, CV_INTER_AREA);
auto t_end_resize = std::chrono::high_resolution_clock::now();
std::cout<<"read,"<<std::chrono::duration<double, std::milli>(t_end_read-t_start).count()<<",resize,"<<std::chrono::duration<double, std::milli>(t_end_resize-t_end_read).count()
<<",total,"<<std::chrono::duration<double, std::milli>(t_end_resize-t_start).count()<<endl;
正在编译:g ++ -std = c ++ 11 resizeCPU.cpp -o resizeCPU pkg-config --cflags --libs opencv
我运行每个程序N次,由以下代码控制:runMultipleGPU.sh
#!/bin/bash
echo $1
START=1
END=$1
for (( c=$START; c<=$END; c++ ))
do
./resizeGPU "$c" &#>/dev/null #&disown;
done
wait
echo All done
运行:./ runMultipleGPU.sh
这些定时器导致跟随汇总数据
No_processes resizeCPU resizeGPU memcpyGPU totalresizeGPU
1 1.51 0.55 2.13 2.68
10 5.67 0.37 2.43 2.80
15 6.35 2.30 12.45 14.75
20 6.30 2.05 10.56 12.61
30 8.09 4.57 23.97 28.55
每个进程都没有运行图像:267
图片的平均尺寸:624Kb
根据上面的数据,随着我们增加进程数量(导致同时调整大小的数量增加),调整大小执行 在GPU与CPU之间,ance(包括实际调整大小+主机到设备和设备到主机副本)显着增加。
使用在
下使用OpenCL的ImageMagick后的类似结果代码:
setenv("MAGICK_OCL_DEVICE","OFF",1); //Turn in ON to use GPU acceleration
Image image;
auto t_start_read = std::chrono::high_resolution_clock::now();
image.read( full_path );
auto t_end_read = std::chrono::high_resolution_clock::now();
image.resize( Geometry(400,400) );
auto t_end_resize = std::chrono::high_resolution_clock::now();
结果:
No_procs resizeCPU resizeGPU
1 63.23 8.54
10 76.16 31.04
15 76.56 50.79
20 76.58 71.68
30 86.29 140.17
测试机器配置:
4 GPU(Tesla P100) - 但测试仅使用1个GPU
64个CPU内核(通过Intel Xeon 2680 v4 CPU)
OpenCV版本:3.4.0
ImageMagick版本:6.9.9-26 Q16 x86_64 2018-01-17
Cuda Toolkit:9.0
答案 0 :(得分:0)
高度可行,为时已晚,无法为您提供帮助。但是,对于希望看到此答案的人们,这是我建议提高性能的建议。设置固定内存的方式并不能帮助您寻找所需的内存。 这是:使用
//method 1
cv::Mat::setDefaultAllocator(cv::cuda::HostMem::getAllocator(cv::cuda::HostMem::AllocType::PAGE_LOCKED));
在this discussion的注释中。有人建议像你一样做。回答者说,速度较慢。我正在安排实施与Coldvision.io Sobel中的sobel衍生品相近的sobel衍生品,主要步骤是:
相反,我实现了一个版本,交换了第2步和第3步的顺序。先转换为灰度,然后通过传递高斯对结果进行降噪。
我在Windows 10中运行openCV3.4。CUDA9.0。我的CPU是i7-6820HQ。 GPU是Quadro M1200。
我尝试您的方法以及这一方法:
//Method 2
//allocate pinned memory
cv::cuda::HostMem memory(siz.height, siz.width, CV_8U, cv::cuda::HostMem::PAGE_LOCKED);
//Read input image from the disk
Mat input = imread(input_file, CV_LOAD_IMAGE_COLOR);
if (input.empty())
{
std::cout << "Image Not Found: " << input_file << std::endl;
return;
}
input.copyTo(memory);
// copy the input image from CPU to GPU memory
cuda::GpuMat gpuInput;
cv::cuda::Stream stream;
gpuInput.upload(memory, stream);
//Do your processing...
//allocate pinned memory for output
cv::cuda::HostMem outMemory(siz.height, siz.width, CV_8U, cv::cuda::HostMem::PAGE_LOCKED);
gpuOutput.download(outMemory, stream);
cv::Mat output = outMemory.createMatHeader();
我将增益计算为:(t1-t2)/t1*100
。其中t1是正常运行代码的时间。 t2使用固定内存运行它。负值是当该方法比在非固定内存中运行慢时。
image size Gain % Method 1 Gain % Method 2
800x600 2.9 8.2
1280x1024 2.5 15.3
1600x1200 0.2 7.0
2048x1536 -2.3 14.6
4096x3072 -1.0 17.2