首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OpenCL中LDS内存的性能问题

OpenCL中LDS内存的性能问题
EN

Stack Overflow用户
提问于 2014-01-20 18:05:32
回答 2查看 837关注 0票数 0

我有一个性能问题,当使用LDS内存与AMD Radeon HD 6850。

我有两个核作为N粒子模拟的一部分。每个工作单元必须根据与其他粒子的相对位置来计算作用在相应粒子上的力。有问题的内核是:

代码语言:javascript
复制
#define UNROLL_FACTOR 8
//Vernet velocity part kernel
__kernel void kernel_velocity(const float deltaTime,
                            __global const float4 *pos,
                           __global float4 *vel,
                           __global float4 *accel,
                           __local float4 *pblock,
                           const float bound)
{
    const int gid = get_global_id(0); //global id of work item
    const int id = get_local_id(0); //local id of work item within work group

    const int s_wg = get_local_size(0); //work group size
    const int n_wg = get_num_groups(0); //number of work groups

    const float4 myPos = pos[gid];
    const float4 myVel = vel[gid];
    const float4 dt = (float4)(deltaTime, deltaTime, 0.0f, 0.0f);
    float4 acc = (float4)0.0f;

    for (int jw = 0; jw < n_wg; ++jw)
    {
        pblock[id] = pos[jw * s_wg + id]; //cache a particle position; position in array: workgroup no. * size of workgroup + local id
        barrier (CLK_LOCAL_MEM_FENCE); //wait for others in the work group

        for (int i = 0; i < s_wg; )
        {
            #pragma unroll UNROLL_FACTOR
            for (int j = 0; j < UNROLL_FACTOR; ++j, ++i)
            {
                float4 r = myPos - pblock[i];

                float rSizeSquareInv = native_recip (r.x*r.x + r.y*r.y + 0.0001f);
                float rSizeSquareInvDouble = rSizeSquareInv * rSizeSquareInv;
                float rSizeSquareInvQuadr = rSizeSquareInvDouble * rSizeSquareInvDouble;
                float rSizeSquareInvHept = rSizeSquareInvQuadr * rSizeSquareInvDouble * rSizeSquareInv;

                acc += r * (2.0f * rSizeSquareInvHept - rSizeSquareInvQuadr);
            }
        }   
        barrier(CLK_LOCAL_MEM_FENCE);
    }
    acc *= 24.0f / myPos.w;

    //update velocity only
    float4 newVel = myVel + 0.5f * dt * (accel[gid] + acc);

    //write to global memory
    vel[gid] = newVel;
    accel[gid] = acc;
}

仿真结果运行良好,但问题在于如何利用本地内存缓存粒子位置,以减少全局内存的大量读取。实际上如果线路

float4 r = myPos - pblock[i];

被取代

float4 r = myPos - pos[jw * s_wg + i];

内核运行得更快。我不太明白这一点,因为从全球阅读应该比从本地阅读慢得多。

而且,当线

float4 r = myPos - pblock[i];

被完全移除,所有后续发生的r都被myPos - pblock[i]所取代,速度和以前一样,就好像根本没有这条线一样。这一点我没有得到更多,因为访问私有内存在r应该是最快的,但编译器在某种程度上“优化”了这一行。

全球工作规模为4608,本地工作规模为192。它在Ubuntu12.04中与AMD应用SDKV2.9和催化剂驱动程序13.12一起运行。

有人能帮我吗?这是我的错还是GPU /驱动程序/.的问题?或者是一种特征?:-)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-01-22 19:44:22

经过进一步的挖掘,结果发现代码导致了一些LDS银行冲突。原因是对于AMD来说,有32个4字节长的银行,但是float4覆盖了16个字节,因此半波前访问相同银行中的不同地址。解决方案是将x坐标和y坐标分别生成__local float*,并分别读取它们,并以数组索引的适当偏移作为(id + i) % s_wg。尽管如此,性能的总体收益是很小的,这很可能是@CaptainObvious提供的链接中所描述的总体延迟(那么我们必须增加全局工作规模来隐藏它们)。

票数 0
EN

Stack Overflow用户

发布于 2014-01-20 21:30:18

我要做个疯狂的猜测:

当使用float4 r = myPos - pos[jw * s_wg + i];时,编译器足够聪明地注意到,在pblock[id]初始化之后设置的屏障不再必要,并删除它。很可能所有这些障碍(在for循环中)都会影响您的性能,因此消除它们是非常明显的。

是的,但是全局访问花费了很多too...So,我猜场景缓存内存的背后被很好地利用了。还有一个事实是,您使用向量,事实上,and 6850的架构使用VLIW processors...maybe,这也有助于更好地利用缓存memories...maybe。

编辑:我刚刚发现了一个文章基准测试GPU/APU缓存和内存延迟。你的GPU在名单上。你可能会得到更多的答案(很抱歉没有读到--太累了)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21241107

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档