【问题标题】:CPU runs faster than GPU (OpenCL code)CPU 运行速度比 GPU 快(OpenCL 代码)
【发布时间】:2015-09-23 08:58:45
【问题描述】:

我在 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 更快吗?或者,我的代码/实现有什么问题吗? 请解释这种行为。

【问题讨论】:

  • 我认为 GPU 应该完成他们的工作:处理图形化的东西(例如大量的浮点计算)以放弃主 CPU 的工作。您编写的简单代码在更快的 CPU 上运行速度更快。
  • GPU 只有在你能够获得大量并行性的情况下才会更快,即在大量内核上运行大量线程。对于单个执行线程,GPU 将是浪费时间。
  • 请阅读Why are we still using CPUs instead of GPUs?。对于所有类型的问题,GPU 并不比 CPU 快。
  • 每当您尝试使用 GPU 时。首先考虑如何并行化 dara 计算。如果您不能并行化算术运算。仅在 CPU 上工作

标签: c linux parallel-processing opencl gpgpu


【解决方案1】:

clEnqueueTask() 所以基本上,您在 GPU 中运行 1 个单个“线程”(工作项)。 GPU 永远不会在单线程性能上击败 CPU。

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

要使用多个工作项,请使用clEnqueueNDRangeKernel() 调用您的内核

【讨论】:

  • 但是,我将不得不更改我的代码,因为它使用以前的结果来计算新值。
  • 我使用了ret = clEnqueueNDRangeKernel(cmdqueue, kernel, 1, NULL,&amp;global_item_size, NULL, 0, NULL, &amp;event);,其中global_item_size=1000,但新的时间分别为:12.56104[ms]、12.56104[ms]、12.56104[ms] 和 12.56104[ms]
  • __kernel void dataParallel(__global int* A) { no=get_global_id(0); A[no]=new_prime;}
  • 好吧,当您以 1000 全局大小运行代码时,我无法准确告诉您代码中发生了什么。因为您的原始代码首先是不可并行化的。但我觉得奇怪的是所有案件都需要相同的金额。可能它根本没有运行,这只是设置时间。检查 API 中的任何错误。
  • 我修改了我的原始代码,它正在运行,因为我在每种情况下都得到了正确的输出
【解决方案2】:

提供的代码是依赖于先前值的顺序算法。 如果您使用 global_work_size > 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] 等

【讨论】:

    猜你喜欢
    • 2022-01-19
    • 1970-01-01
    • 2017-07-10
    • 2016-10-23
    • 2014-06-15
    • 2013-05-02
    • 1970-01-01
    • 2015-12-27
    相关资源
    最近更新 更多