为什么Opencv GPU代码比CPU慢?

Dav*_*ing 12 c++ opencv gpu

我正在使用笔记本电脑的opencv242 + VS2010.
我试图对OpenCV中的GPU块进行一些简单测试,但它表明GPU比CPU代码慢100倍.在这段代码中,我只是将彩色图像转换为灰度图像,使用cvtColor的功能

这是我的代码,PART1是CPU代码(测试cpu RGB2GRAY),PART2是GPU上传图像,PART3是GPU RGB2GRAY,PART4是CPU RGB2GRAY.有三件事让我如此疑惑:

1在我的代码中,part1是0.3ms,而part4(与part1完全相同)是40ms!
2将图像上传到GPU的part2是6000ms !!!
3 Part3(GPU代码)是11ms,对于这个简单的图像来说速度太慢了!

    #include "StdAfx.h"
    #include <iostream>
    #include "opencv2/opencv.hpp"
    #include "opencv2/gpu/gpu.hpp"
    #include "opencv2/gpu/gpumat.hpp"
    #include "opencv2/core/core.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <cuda.h>
    #include <cuda_runtime_api.h>
    #include <ctime>
    #include <windows.h>

    using namespace std;
    using namespace cv;
    using namespace cv::gpu;

    int main()
    {
        LARGE_INTEGER freq;
        LONGLONG QPart1,QPart6;
        double dfMinus, dfFreq, dfTim;
        QueryPerformanceFrequency(&freq);
        dfFreq = (double)freq.QuadPart;

        cout<<getCudaEnabledDeviceCount()<<endl;
        Mat img_src = imread("d:\\CUDA\\train.png", 1);

        // PART1 CPU code~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // From color image to grayscale image.
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;
        Mat img_gray;
        cvtColor(img_src,img_gray,CV_BGR2GRAY);
        QueryPerformanceCounter(&freq);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("CPU RGB2GRAY running time is %.2f ms\n\n",dfTim);

        // PART2 GPU upload image~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        GpuMat gimg_src;
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;
        gimg_src.upload(img_src);
        QueryPerformanceCounter(&freq);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("Read image running time is %.2f ms\n\n",dfTim);

        GpuMat dst1;
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;

        /*dst.upload(src_host);*/
        dst1.upload(imread("d:\\CUDA\\train.png", 1));

        QueryPerformanceCounter(&freq);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("Read image running time 2 is %.2f ms\n\n",dfTim);

        // PART3~ GPU code~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // gpuimage From color image to grayscale image.
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;

        GpuMat gimg_gray;
        gpu::cvtColor(gimg_src,gimg_gray,CV_BGR2GRAY);

        QueryPerformanceCounter(&freq);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("GPU RGB2GRAY running time is %.2f ms\n\n",dfTim);

        // PART4~CPU code(again)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // gpuimage From color image to grayscale image.
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;
        Mat img_gray2;
        cvtColor(img_src,img_gray2,CV_BGR2GRAY);
        BOOL i_test=QueryPerformanceCounter(&freq);
        printf("%d \n",i_test);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("CPU RGB2GRAY running time is %.2f ms\n\n",dfTim);

        cvWaitKey();
        getchar();
        return 0;
    }
Run Code Online (Sandbox Code Playgroud)

Mar*_*ett 25

cvtColor没有做太多的工作,灰色你只需要平均三个数字.

CPU上的cvColor代码使用SSE2指令一次处理多达8个像素,如果你有TBB它使用所有内核/超线程,CPU运行速度是GPU时钟速度的10倍,最后你不必将数据复制到GPU上并返回.

  • 这也可能来自创建CUDA上下文需要时间的事实.我不知道你如何评估你的代码的时间. (2认同)

Tim*_*man 22

上面的大多数答案实际上都是错 它之所以慢了20000倍,当然不是因为"CPU时钟速度更快"而且"它必须将其复制到GPU"(接受的答案).这些都是因素,但是你说你省略了一个事实,即对于一个令人作呕的并行问题你有更多的计算能力.说20.000x的性能差异是因为后者只是如此荒谬可笑.作者在这里知道一些错误并不是直截了当的.解:

你的问题是CUDA需要初始化!它将始终为第一幅图像初始化,通常需要1-10秒,具体取决于木星和火星的对齐方式.现在尝试一下.计算两次,然后计算两者.在这种情况下,您可能会看到速度与magnutide相同,而不是20.000x,这太荒谬了.你能对这个初始化做些什么吗?不,不是我所知道的.这是一个障碍.

编辑:我刚刚重新阅读帖子.你说你在笔记本上运行.那些经常有破旧的GPU,而CPU则有一个公平的涡轮增压.

  • 这应该是公认的答案,因为它给出了观察到的性能问题的实际原因。@Tae 在 3 年前就已经指出了这一点,但在分析中并没有那么明确。 (3认同)

小智 6

尝试不止一次运行....

-----------摘自http://opencv.willowgarage.com/wiki/OpenCV%20GPU%20FAQ Perfomance

为什么第一次函数调用很慢?

那是因为初始化开销.在第一个GPU函数调用Cuda Runtime API被隐式初始化.在第一次使用时,还会为您的视频卡编译一些GPU代码(即时编译).因此,对于性能测量,有必要进行虚函数调用,然后才执行时间测试.

如果应用程序仅运行一次GPU代码至关重要,则可以使用在多次运行中持久的编译缓存.有关详细信息,请阅读nvcc文档(CUDA_DEVCODE_CACHE环境变量).