加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – Cuda – OpenCL CPU比OpenCL或CUDA GPU版本快4倍

发布时间:2020-12-15 08:19:49 所属栏目:百科 来源:网络整理
导读:我一直在使用C#Cudafy(C# – CUDA或OpenCL翻译器)的波模拟器工作得很好,除了运行OpenCL CPU版本(英特尔驱动程序,15英寸MacBook Pro Retina i7 2.7GHz,GeForce 650M)这一事实(Kepler,384核心))大约是GPU版本的四倍. (无论我使用CL还是CUDA GPU后端,都会发生这
我一直在使用C#Cudafy(C# – > CUDA或OpenCL翻译器)的波模拟器工作得很好,除了运行OpenCL CPU版本(英特尔驱动程序,15英寸MacBook Pro Retina i7 2.7GHz,GeForce 650M)这一事实(Kepler,384核心))大约是GPU版本的四倍.

(无论我使用CL还是CUDA GPU后端,都会发生这种情况.OpenCL GPU和CUDA版本的执行几乎相同.)

为澄清一个样本问题:

> OpenCL CPU 1200 Hz
> OpenCL GPU 320 Hz
> CUDA GPU – ~330 Hz

我无法解释为什么CPU版本会比GPU更快.在这种情况下,在CPU和GPU上执行(在CL情况下)的内核代码是相同的.我在初始化期间选择CPU或GPU设备,但除此之外,一切都是相同的.

编辑

这是启动其中一个内核的C#代码. (其他人非常相似.)

public override void UpdateEz(Source source,float Time,float ca,float cb)
    {
        var blockSize = new dim3(1);
        var gridSize = new dim3(_gpuEz.Field.GetLength(0),_gpuEz.Field.GetLength(1));

        Gpu.Launch(gridSize,blockSize)
            .CudaUpdateEz(
                Time,ca,cb,source.Position.X,source.Position.Y,source.Value,_gpuHx.Field,_gpuHy.Field,_gpuEz.Field
            );

    }

而且,这是Cudafy生成的相关CUDA内核函数:

extern "C" __global__ void CudaUpdateEz(float time,float cb,int sourceX,int sourceY,float sourceValue,float* hx,int hxLen0,int hxLen1,float* hy,int hyLen0,int hyLen1,float* ez,int ezLen0,int ezLen1)
{
    int x = blockIdx.x;
    int y = blockIdx.y;
    if (x > 0 && x < ezLen0 - 1 && y > 0 && y < ezLen1 - 1)
    {
        ez[(x) * ezLen1 + ( y)] = ca * ez[(x) * ezLen1 + ( y)] + cb * (hy[(x) * hyLen1 + ( y)] - hy[(x - 1) * hyLen1 + ( y)]) - cb * (hx[(x) * hxLen1 + ( y)] - hx[(x) * hxLen1 + ( y - 1)]);
    }
    if (x == sourceX && y == sourceY)
    {
        ez[(x) * ezLen1 + ( y)] += sourceValue;
    }
}

为了完整起见,这里是用于生成CUDA的C#:

[Cudafy]
    public static void CudaUpdateEz(
        GThread thread,float time,float[,] hx,] hy,] ez
        )
    {
        var i = thread.blockIdx.x;
        var j = thread.blockIdx.y;

        if (i > 0 && i < ez.GetLength(0) - 1 && j > 0 && j < ez.GetLength(1) - 1)
            ez[i,j] =
                ca * ez[i,j]
                +
                cb * (hy[i,j] - hy[i - 1,j])
                -
                cb * (hx[i,j] - hx[i,j - 1])
                ;

        if (i == sourceX && j == sourceY)
            ez[i,j] += sourceValue;
    }

显然,这个内核中的if是坏的,但即使是最终的管道停顿也不应该导致如此极端的性能增量.

跳出来的另一件事是我正在使用一个蹩脚的网格/块分配方案 – 即,网格是要更新的数组的大小,每个块是一个线程.我确信这会对性能产生一些影响,但我看不出它会导致它在CPU上运行的CL代码速度的1/4.哎呀!

解决方法

回答这个问题,将其从未答复的清单中删除.

发布的代码表明内核启动指定了1(活动)线程的线程块.这不是编写快速GPU代码的方法,因为它会使大部分GPU功能空闲.

典型的线程块大小应该是每块至少128个线程,并且更高通常更好,32的倍数,高达每块512或1024的限制,具体取决于GPU.

GPU“喜欢”通过让许多并行工作“可用”来隐藏延迟.为每个块指定更多线程有助于实现此目标. (在网格中有相当多的线程块也可能有所帮助.)

此外,GPU以32个为一组执行线程.每个块只指定一个线程或32个非多个将在每个执行的线程块中留下一些空闲执行槽.每个块1个线程特别糟糕.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读