Time 优化Cuda内核时间执行

Time 优化Cuda内核时间执行,time,cuda,gpu,cpu,Time,Cuda,Gpu,Cpu,我是一名学习Cuda的学生,我想优化我的内核函数的执行时间。因此,我实现了一个计算两幅图片之间差异的短程序。所以我比较了C中经典CPU执行和CUDAC中GPU执行之间的执行时间 在这里,您可以找到我所说的代码: int *imgresult_data = (int *) malloc(width*height*sizeof(int)); int size = width*height; switch(computing_type) { case GPU: HANDLE_ER

我是一名学习Cuda的学生,我想优化我的内核函数的执行时间。因此,我实现了一个计算两幅图片之间差异的短程序。所以我比较了C中经典CPU执行和CUDAC中GPU执行之间的执行时间

在这里,您可以找到我所说的代码:

int *imgresult_data = (int *) malloc(width*height*sizeof(int));
int size = width*height;

switch(computing_type)
{

    case GPU:

    HANDLE_ERROR(cudaMalloc((void**)&dev_data1, size*sizeof(unsigned char)));
    HANDLE_ERROR(cudaMalloc((void**)&dev_data2, size*sizeof(unsigned char)));
    HANDLE_ERROR(cudaMalloc((void**)&dev_data_res, size*sizeof(int)));

    HANDLE_ERROR(cudaMemcpy(dev_data1, img1_data, size*sizeof(unsigned char), cudaMemcpyHostToDevice)); 
    HANDLE_ERROR(cudaMemcpy(dev_data2, img2_data, size*sizeof(unsigned char), cudaMemcpyHostToDevice));
    HANDLE_ERROR(cudaMemcpy(dev_data_res, imgresult_data, size*sizeof(int), cudaMemcpyHostToDevice));

    float time;
    cudaEvent_t start, stop;

    HANDLE_ERROR( cudaEventCreate(&start) );
    HANDLE_ERROR( cudaEventCreate(&stop) );
    HANDLE_ERROR( cudaEventRecord(start, 0) );

    for(int m = 0; m < nb_loops ; m++)
    {
        diff<<<height, width>>>(dev_data1, dev_data2, dev_data_res);
    }

    HANDLE_ERROR( cudaEventRecord(stop, 0) );
    HANDLE_ERROR( cudaEventSynchronize(stop) );
    HANDLE_ERROR( cudaEventElapsedTime(&time, start, stop) );

    HANDLE_ERROR(cudaMemcpy(imgresult_data, dev_data_res, size*sizeof(int), cudaMemcpyDeviceToHost));

    printf("Time to generate:  %4.4f ms \n", time/nb_loops);

    break;

    case CPU:

    clock_t begin = clock(), diff;

    for (int z=0; z<nb_loops; z++)
    {
        // Apply the difference between 2 images
        for (int i = 0; i < height; i++)
        {
            tmp = i*imgresult_pitch;
            for (int j = 0; j < width; j++)
            {
                imgresult_data[j + tmp] = (int) img2_data[j + tmp] - (int) img1_data[j + tmp];
            }
        }
    }
    diff = clock() - begin;

    float msec = diff*1000/CLOCKS_PER_SEC;
    msec = msec/nb_loops;
    printf("Time taken %4.4f milliseconds", msec);

    break;
}
这是我的内核函数:

__global__ void diff(unsigned char *data1 ,unsigned char *data2, int *data_res)
{
    int row = blockIdx.x;
    int col = threadIdx.x;
    int v = col + row*blockDim.x;

    if (row < MAX_H && col < MAX_W)
    {
        data_res[v] = (int) data2[v] - (int) data1[v];
    }
}
我得到了每一个的执行时间

CPU:13210ms GPU:03229ms 我想知道为什么GPU的结果没有它应该的那么低。我是Cuda的初学者,所以如果有一些经典错误,请综合考虑

编辑1: 谢谢你的反馈。我试图从内核中删除“if”条件,但它并没有深刻地改变我的程序执行时间

然而,在安装了Cuda profiler之后,它告诉我我的线程没有并发运行。我不明白为什么我会有这样的信息,但这似乎是真的,因为我只有一个5或6倍的应用程序与GPU比CPU快。这个比率应该更大,因为每个线程应该同时处理一个像素和所有其他像素。如果你知道我做错了什么,那就太好了


流程。

代码可能还有其他问题,但下面是我看到的。__全局__无效差异中的以下行被认为不是最佳的:

if (row < MAX_H && col < MAX_W)
{
    data_res[v] = (int) data2[v] - (int) data1[v];
}
内核中的条件运算符会导致扭曲发散。这意味着扭曲中的if和else部分是按顺序执行的,而不是并行执行的。此外,正如您可能已经意识到的,if仅在边界处计算为false。为避免发散和不必要的计算,请将图像分为两部分:

将使用diff内核的边界区域

显然,您需要修改调用内核的代码

另请注意:

GPU具有面向吞吐量的体系结构,但不像CPU那样面向延迟。这意味着CPU在处理少量数据时可能比CUDA更快。您是否尝试过使用大型数据集

CUDA Profiler是一个非常方便的工具,它会告诉您代码不是最优的


我不认为你测量时间是正确的,内存拷贝是GPU中一个耗时的步骤,在测量时间时你应该考虑到这一点

我看到了一些您可以测试的细节:

我假设你使用Max和Max作为常量,你可以考虑使用CUADAMEMCPyTyMyBOL.< 请记住使用uu syncthreads同步线程,这样在每次循环迭代之间就不会出现问题

CUDA与WAPS一起工作,因此块和每个块的线程数最好是8的倍数,但不超过每个块512个线程,除非您的硬件支持它。下面是一个每个块使用128个线程的示例:

请记住释放GPU中分配的内存并销毁创建的时间事件

在内核函数中,可以有一个变量int v=threadIdx.x+blockIdx.x*blockDim.x

除了执行时间外,您是否测试了结果是否正确?我认为在处理数组时,由于填充的原因,应该使用cudamallocpatch和cudaMemcpy2D


CUDA不是C,而是基于C++的,所以GPU结果比CPU结果快4X?你在期待什么?你在运行多少个循环?在向GPU复制或从GPU复制时会有很大的开销。1。编译器常量几乎总是比使用常量内存更好。2.内核中没有循环,在任何情况下使用同步线程3都没有意义。当前所有CUDA硬件CUDA 7.0和CUDA 7.5支持每个块1024个线程,每个块的线程数应该是32的倍数,而不是8的倍数。4.释放内存和销毁事件当然是一种好的做法,但这与这个问题无关。5.编译器将解决所有这些问题,并对其进行优化。6.在当前的cc2.0和更高的硬件上,倾斜分配很少显示出优势。