OPENCV :不同方法的 CUDA 上下文初始化
OPENCV : CUDA context initialization for different methods
我正在开发一个简单的 c++ 程序来评估一些 Opencv GPU 方法的性能 (cv::cuda)。我在 Ubuntu 15(带有 CUDA 7.5)和 GeForce 770 上使用 Opencv 3.1。
我之前读过我们需要初始化 CUDA 环境以避免第一次调用时进程缓慢。因此,我使用 cv::cuda::getDevice() 和 setDevice() 初始化我的程序。
然后,我测试2种方法:
- cv::cuda::resize() (系数 0.5)
- 和 cv::cuda::meanStdDev。
初始化需要 400 毫秒。然后,调整大小需要 2 或 3 毫秒,没关系。但。。。平均标准开发需要 476 毫秒!如果我连续运行 2 个 meanStdDev,第二个要快得多(3 毫秒)。
我真的不明白为什么初始化对 resize() 有影响,但对 meanStdDev() 没有影响。
我用 -DCUDA_ARCH_BIN=3.0 编译 OPENCV。我尝试使用 -DCUDA_ARCH_PTX=",但问题仍然相同。
#include <opencv2/opencv.hpp>
#include <opencv2/cudaimgproc.hpp>
#include "opencv2/cudawarping.hpp"
#include "opencv2/cudaarithm.hpp"
using namespace std;
int main(int argc, char *argv[])
{
double t_init_cuda = (double)cv::getTickCount();
int CudaDevice;
if(cv::cuda::getCudaEnabledDeviceCount()==0)
{
cerr<<endl<<"ERROR: NO CudaEnabledDevice"<<endl;
exit(2);
}
else
{
CudaDevice = cv::cuda::getDevice();
cv::cuda::setDevice(CudaDevice);
}
t_init_cuda = ((double)cv::getTickCount() - t_init_cuda)/cv::getTickFrequency() * 1000;
cout<<endl<<"t*T_INIT_CUDA="<<t_init_cuda<<"msn";;
cv::Mat src = cv::imread(argv[1], 0);
if (!src.data) exit(1);
cv::cuda::GpuMat d_src(src);
//CV::CUDA::RESIZE
cv::cuda::GpuMat d_dst;
double factor = 0.5;
double t_gpu_resize = cv::getTickCount();
cv::cuda::resize(d_src, d_dst, cv::Size( (int) ((float) (d_src.cols)*factor) , (int) ((float) (d_src.rows)*factor)), 0, 0, CV_INTER_AREA);
t_gpu_resize = ((double)cv::getTickCount() - t_gpu_resize)/cv::getTickFrequency() * 1000;
cout<<endl<<"D_SRC="<<d_src.rows<<"x"<<d_src.cols<<" => D_DST="<<d_dst.rows<<"x"<<d_dst.cols<<endl;
cout<<endl<<"t*T_GPU_RESIZE="<<t_gpu_resize<<"msn";;
//CV::CUDA::MEANSTDDEV
double t_meanstddev = (double)cv::getTickCount();
cv::Scalar mean, stddev;
std::vector<cv::cuda::GpuMat> d_src_split;
cv::cuda::split(d_src, d_src_split);
cv::cuda::meanStdDev (d_src_split[0], mean, stddev);
t_meanstddev = ((double)cv::getTickCount() - t_meanstddev)/cv::getTickFrequency() * 1000.0;
cout<<endl<<"mean="<<mean.val[0]<<" | stddev="<<stddev.val[0]<<endl;
cout<<endl<<"t*T_GPU_MEANSTDDEV="<<t_meanstddev<<"msn";
return 0;
}
我的朋友,当你调用同一个函数两次时:
1-首次在设备上分配新内存以调整大小。"根据OpenCV的WIKI"
2-第二次重复使用分配的内存,因此速度很快。
我从OpenCV中为你获取了这个功能,所以你可以理解它为什么这么说。
void cv::cuda::meanStdDev(InputArray _src, OutputArray _dst, Stream& stream)
{
if (!deviceSupports(FEATURE_SET_COMPUTE_13))
CV_Error(cv::Error::StsNotImplemented, "Not sufficient compute capebility");
const GpuMat src = getInputMat(_src, stream);
CV_Assert( src.type() == CV_8UC1 );
GpuMat dst = getOutputMat(_dst, 1, 2, CV_64FC1, stream);
NppiSize sz;
sz.width = src.cols;
sz.height = src.rows;
int bufSize;
#if (CUDA_VERSION <= 4020)
nppSafeCall( nppiMeanStdDev8uC1RGetBufferHostSize(sz, &bufSize) );
#else
nppSafeCall( nppiMeanStdDevGetBufferHostSize_8u_C1R(sz, &bufSize) );
#endif
BufferPool pool(stream);
GpuMat buf = pool.getBuffer(1, bufSize, CV_8UC1); // <--- this line create new GpuMat
NppStreamHandler h(StreamAccessor::getStream(stream));
nppSafeCall( nppiMean_StdDev_8u_C1R(src.ptr<Npp8u>(), static_cast<int>(src.step), sz, buf.ptr<Npp8u>(), dst.ptr<Npp64f>(), dst.ptr<Npp64f>() + 1) );
syncOutput(dst, _dst, stream);
}
此函数
GpuMat cv::cuda::BufferPool::getBuffer(int rows, int cols, int type)
{
GpuMat buf(allocator_);
buf.create(rows, cols, type);
return buf;
}
我希望这对你有帮助。
相关文章:
- 编译时未启用intel oneApi CUDA支持
- #为""定义宏;静态";针对不同的上下文
- 与互斥锁相比,旋转锁可以保证上下文切换
- 在cuda线程之间共享大量常量数据
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- 为什么即使使用-cudart-static进行编译,库用户仍然需要链接到cuda运行时
- 为什么我不能使用 EGL 创建无头 OpenGl 上下文?
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它
- CUDA内核和数学函数的显式命名空间
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 为什么在逗号分隔符上下文中将预增量的结果强制转换为void
- CUDA:统一内存和指针地址的更改
- 错误"Could not find Boost"(缺少:上下文标头)
- 使用 mod_gsoap 部署服务时,如何在 Gsoap 中更改 soap 上下文的模式?
- 调试 CUDA MMU 故障
- 使用 CUDA 和纹理进行图像减法
- 将 2D 推力::d evice_vector 复矩阵传递给 CUDA 内核函数
- 一台设备有多个CUDA上下文-有意义吗
- OPENCV :不同方法的 CUDA 上下文初始化
- CUDA流和上下文