【发布时间】:2013-01-11 03:23:15
【问题描述】:
在尝试使用带有 OpenCV 的 GPU 加速简单算法时,我注意到在我的机器(Ubuntu 12.10、NVidia 9800GT、Cuda 4.2.9、g++ 4.7.2)上,GPU 版本实际上比 CPU 版本慢.我用下面的代码进行了测试。
#include <opencv2/opencv.hpp>
#include <opencv2/gpu/gpu.hpp>
#include <chrono>
#include <iostream>
int main()
{
using namespace cv;
using namespace std;
Mat img1(512, 512, CV_32FC3, Scalar(0.1f, 0.2f, 0.3f));
Mat img2(128, 128, CV_32FC3, Scalar(0.2f, 0.3f, 0.4f));
Mat img3(128, 128, CV_32FC3, Scalar(0.3f, 0.4f, 0.5f));
auto startCPU = chrono::high_resolution_clock::now();
double resultCPU(0.0);
cout << "CPU ... " << flush;
for (int y(0); y < img2.rows; ++y)
{
for (int x(0); x < img2.cols; ++x)
{
Mat roi(img1(Rect(x, y, img2.cols, img2.rows)));
Mat diff;
absdiff(roi, img2, diff);
Mat diffMult(diff.mul(img3));
Scalar diffSum(sum(diff));
double diffVal(diffSum[0] + diffSum[1] + diffSum[2]);
resultCPU += diffVal;
}
}
auto endCPU = chrono::high_resolution_clock::now();
auto elapsedCPU = endCPU - startCPU;
cout << "done. " << resultCPU << " - ticks: " << elapsedCPU.count() << endl;
gpu::GpuMat img1GPU(img1);
gpu::GpuMat img2GPU(img2);
gpu::GpuMat img3GPU(img3);
gpu::GpuMat diffGPU;
gpu::GpuMat diffMultGPU;
gpu::GpuMat sumBuf;
double resultGPU(0.0);
auto startGPU = chrono::high_resolution_clock::now();
cout << "GPU ... " << flush;
for (int y(0); y < img2GPU.rows; ++y)
{
for (int x(0); x < img2GPU.cols; ++x)
{
gpu::GpuMat roiGPU(img1GPU, Rect(x, y, img2GPU.cols, img2GPU.rows));
gpu::absdiff(roiGPU, img2GPU, diffGPU);
gpu::multiply(diffGPU, img3GPU, diffMultGPU);
Scalar diffSum(gpu::sum(diffMultGPU, sumBuf));
double diffVal(diffSum[0] + diffSum[1] + diffSum[2]);
resultGPU += diffVal;
}
}
auto endGPU = chrono::high_resolution_clock::now();
auto elapsedGPU = endGPU - startGPU;
cout << "done. " << resultGPU << " - ticks: " << elapsedGPU.count() << endl;
}
我的结果如下:
CPU ... done. 8.05306e+07 - ticks: 4028470
GPU ... done. 3.22122e+07 - ticks: 5459935
如果这有帮助:我的分析器(System Profiler 1.1.8)告诉我大部分时间都花在cudaDeviceSynchronize。
我在使用 OpenCV GPU 函数的方式上做错了什么,还是我的 GPU 太慢了?
【问题讨论】:
-
如果你调用
Scalar diffSum(gpu::sum(diffMultGPU, sumBuf));,我不完全确定 opencv 的行为方式,我认为它只会从标量元素生成 memcpy。因此,对于每个图像元素,您都需要从 gpu 到主机进行微小的复制操作。那会花费很多时间。 -
也许您可以编写一个迷你内核来代替这一行,它将
diffval和resultGPU保留在 gpu 上,而两个 for 循环仅在最后您将添加一个memcpy 从 cuda 到主机的最终结果。 -
在嵌套 for 循环之前为
Mat和GpuMat对象分配内存空间可能会提高 CPU 和 GPU 性能。 -
GPU 是如何变慢的? 3.22 小于 8.05
-
@KansaiRobot 3.22 和 8.05 不是持续时间,它们是校验和。 GPU 速度较慢,因为它需要 5459935(时间)滴答,但 CPU 只需要 4028470 滴答。