CPU运行速度比GPU快(OpenCL代码)

时间:2015-07-06 09:20:17

标签: c linux parallel-processing opencl gpgpu

我在OpenCL中编写了一个代码来查找前5000个素数。这是代码:

__kernel void dataParallel(__global int* A)
{

    A[0]=2;
    A[1]=3;
    A[2]=5;
    int pnp;//pnp=probable next prime
    int pprime;//previous prime
    int i,j;
    for(i=3;i<5000;i++)
    {
        j=0;
        pprime=A[i-1];
        pnp=pprime+2;
        while((j<i) && A[j]<=sqrt((float)pnp))
        {
            if(pnp%A[j]==0)
                {
                    pnp+=2;
                    j=0;
                }
            j++;

    }
    A[i]=pnp;

    }
}

然后我使用OpenCL分析找出了这个内核代码的执行时间。这是代码:

cl_event event;//link an event when launch a kernel
ret=clEnqueueTask(cmdqueue,kernel,0, NULL, &event);
clWaitForEvents(1, &event);//make sure kernel has finished
clFinish(cmdqueue);//make sure all enqueued tasks finished
//get the profiling data and calculate the kernel execution time

cl_ulong time_start, time_end;
double total_time;
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, sizeof(time_start), &time_start, NULL);
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, sizeof(time_end), &time_end, NULL);
//total_time = (cl_double)(time_end - time_start)*(cl_double)(1e-06);
printf("OpenCl Execution time is: %10.5f[ms] \n",(time_end - time_start)/1000000.0);

我在各种设备上运行这些代码,这就是我得到的:

Platform:Intel(R) OpenCL     
Device:Intel(R) Xeon(R) CPU           X5660  @ 2.80GHz  
OpenCl Execution time is:    3.54796[ms]   

Platform:AMD Accelerated Parallel Processing  
Device:Pitcairn (AMD FirePro W7000 GPU)  
OpenCl Execution time is:  194.18133[ms] 

Platform:AMD Accelerated Parallel Processing  
Device:Intel(R) Xeon(R) CPU           X5660  @ 2.80GHz  
OpenCl Execution time is:    3.58488[ms]

Platform:NVIDIA CUDA  
Device:Tesla C2075  
OpenCl Execution time is:  125.26886[ms]

但GPU不应该比CPU快吗?或者,我的代码/实现有什么问题吗? 请解释一下这种行为。

2 个答案:

答案 0 :(得分:7)

clEnqueueTask()所以基本上,你在GPU中运行了一个单独的“线程”(工作项)。 GPU在单线程性能方面永远不会击败CPU。

您需要转换代码,以便将每个主要计算划分为一个线程,然后运行5000多个工作项(理想情况下为数百万)。然后,GPU将击败CPU,因为它将并行运行所有这些并且CPU不能。

要使用多个工作项,请使用clEnqueueNDRangeKernel()

调用内核

答案 1 :(得分:0)

提供的代码是依赖于先前值的顺序算法。 如果您使用global_work_size&gt;运行它1,你只是一遍又一遍地执行相同的计算。 opencl实现应该按顺序计算小于N的素数,然后并行执行数字[N + 1; N * N]如果它们可以被任何这些素数整除,并且如果数字不是素数则用0填充筛子数组,如果数字是素数则填充1。 例如。 not my code, someone's homework, and i did not check if it really works

如果您需要超过N ^ 2个元素,请计算筛子阵列的前缀总和(独占扫描).AMD APP SDK包含此操作的示例。 这将为您提供复制到素数数组的素数的偏移量,您将能够填充它:

__kernel scatter(uint* numbers, uint* sieve_prefix_sum, uint* sieve, uint offset,  uint* prime_numbers) 
{ 
  if (sieve[get_global_id(0)]) 
   prime_numbers[offset + sieve_prefix_sum[get_global_id(0)] = numbers[get_global_id(0)];
 }

此算法的工作方式类似于树 - 您按顺序计算N个素数,然后在[N + 1,N * N]范围内计算K个块,然后重复并生成[N ^ 2,N]的下一组分支^ 4]等。