C++ 为什么Opencv GPU代码比CPU慢?

C++ 为什么Opencv GPU代码比CPU慢?,c++,opencv,gpu,C++,Opencv,Gpu,我正在笔记本电脑上使用opencv242+VS2010。 我试着在OpenCV中对GPU块做一些简单的测试,但是它显示GPU比CPU代码慢100倍。 在这段代码中,我只需将彩色图像转换为灰度图像,使用cvtColor 这是我的代码,第一部分是CPU代码(测试CPU RGB2GRAY),第二部分是上传图像到GPU,第三部分是GPU RGB2GRAY,第四部分是CPU RGB2GRAY。 有三件事让我很好奇: 在我的代码中,第1部分是0.3ms,而第4部分(与第1部分完全相同)是40ms 2将图像上

我正在笔记本电脑上使用opencv242+VS2010。
我试着在OpenCV中对GPU块做一些简单的测试,但是它显示GPU比CPU代码慢100倍。 在这段代码中,我只需将彩色图像转换为灰度图像,使用cvtColor

这是我的代码,第一部分是CPU代码(测试CPU RGB2GRAY),第二部分是上传图像到GPU,第三部分是GPU RGB2GRAY,第四部分是CPU RGB2GRAY。 有三件事让我很好奇:

在我的代码中,第1部分是0.3ms,而第4部分(与第1部分完全相同)是40ms
2将图像上传到GPU的第2部分是6000ms
第三部分(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;
    }
#包括“StdAfx.h”
#包括
#包括“opencv2/opencv.hpp”
#包括“opencv2/gpu/gpu.hpp”
#包括“opencv2/gpu/gpumat.hpp”
#包括“opencv2/core/core.hpp”
#包括“opencv2/highgui/highgui.hpp”
#包括
#包括
#包括
#包括
使用名称空间std;
使用名称空间cv;
使用名称空间cv::gpu;
int main()
{
大整数频率;
龙龙QPart1、QPart6;
双DF减号、dfFreq、dfTim;
QueryPerformanceFrequency(&freq);
dfFreq=(双)freq.QuadPart;

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


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

尝试多次运行

-----------摘自 表现

为什么第一个函数调用很慢

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

如果一个应用程序只运行一次GPU代码是至关重要的,那么可以使用一个在多次运行中保持不变的编译缓存。有关详细信息,请阅读nvcc文档(CUDA_DEVCODE_cache环境变量)。

您有什么GPU

检查计算机的兼容性,也许这就是原因

这意味着对于具有CC 1.3和2.0二进制图像的设备 准备运行。对于所有较新的平台,1.3的PTX代码都是JIT'ed的 对于具有CC 1.1和1.2的设备,1.1的PTX为 JIT’ed。对于使用CC 1.0的设备,没有可用的代码,并且 函数引发异常。对于需要JIT编译的平台 首先执行,运行速度较慢


cvtColour是一个小操作,在GPU上执行此操作所带来的任何性能提升都远远超过主机(CPU)和设备(GPU)之间的内存传输时间。将此内存传输的延迟降至最低是任何GPU计算的主要挑战。

上述大多数答案实际上都是错误的。其速度慢20.000倍的原因当然不是因为“CPU时钟速度更快”和“必须将其复制到GPU”(已接受的答案)。这些都是因素,但如果说你忽略了一个事实,即对于一个令人厌恶的并行问题,你的计算能力要高得多。说20.000倍的性能差异是因为后者是非常荒谬的。这里的作者知道有些事情是错的,这不是直截了当的。解决方案:

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


编辑:我刚刚重读了这篇文章。你说你在笔记本电脑上运行。那些笔记本电脑通常有破旧的GPU,CPU有一个普通的涡轮增压器。

这并不是说GPU一般都“慢”。但是,主机和设备之间的内存传输速度非常慢。只有当您可以将非常大、高度并行的计算卸载到设备上时,GPU计算才有意义。还应检查并传递未分配的GPU在GPU优化函数中是否有GPU内存分配。为避免这种情况,您应使用pro预先分配内存函数使用前按大小。感谢您的回答!!在这段代码中,我使用RGB2GRAY的CPU两次(相同的代码,一次在GPU代码之前,另一次在GPU代码之后)。这表明第二次比第一次慢得多。但它们是相同的代码!您能给我一些提示吗?这也可能是因为创建CUDA上下文需要时间。我不知道您如何评估代码的计时。这应该是公认的答案,因为它给出了观察到的性能的实际原因问题。@Tae在3年前就已经指出了这一点,但在分析中没有那么明确。