工作项缓存的全局内存

时间:2017-03-09 15:28:50

标签: opencl

由于本地内存限制,我需要使用全局内存作为工作项的缓存。

假设我有1000个工作组,每个工作组有64个工作项。每个项目都需要4K缓存。工作项完成后,缓存不需要保留。

我将分配一个单独的全局内存缓冲区并将4K片段分配给工作项。

(我的目标是AMD GPU)

我需要保证的最小尺寸是多少 工作项之间的任何并发问题?

由于AMD有< = 64 CU,我猜是

64 * 128 * 4000字节,并使用(全局工作项ID%(64 * 128)) 将缓存块分配给工作项。

1 个答案:

答案 0 :(得分:1)

如果每个缓存项(由global work item ID % (64*128)访问)是4000字节长的结构,并且如果实现不强制每个结构在4096字节上对齐,并且如果缓存行大小不是精确除数为4000,如果全局存储库的步长不是4000的精确除数,那么它不应该是一个问题。

使用codexl描述这个内核,(16k工作项需要0.5秒):

    __kernel void test(__global float * a)
    {
        int i=get_global_id(0)*4096;
        for(int j=0;j<4096;j++)
            a[i+j]*=2.0f;
    }

和一些输出:

  • mem units stalled%55
  • 缓存命中%45
  • mem unit busy%99
  • 估值繁忙%0.05

然后将内核更改为交错类型(在0.25秒内执行):

    __kernel void test(__global float * a)
    {
        int i=get_global_id(0);
        for(int j=0;j<4096;j++)
            a[i+j*4096*4]*=2.0f;
    }
  • mem units stalled%57
  • 缓存命中%47
  • mem unit busy%84
  • 估值繁忙%1.5

所以交错模式减少了对存储单元的压力,并且更频繁地点击缓存,并且ALU部件更频繁地被馈送并且更快地完成%50。

然后尝试了这个:

__kernel void test(__global float * a)
{
    int i=get_global_id(0)*4100;
    for(int j=0;j<4100;j++)
        a[i+j]*=2.0f;
}

这需要0.37s,比4096版快30%,但内存单元停顿时间更长(终点不对齐必然导致这会浪费一些不必要的数据提取周期)并且缓存命中率降低到%37。 / p>

测试GPU是R7-240

结构的最后一次测试:

typedef struct test_struct
{
   float test_field[4096];
}strr;
__kernel void test(__global strr * a)
{
    int i=get_global_id(0);
    for(int j=0;j<4096;j++)
    a[i].test_field[j]*=2.0f;
}

这在0.53秒内完成,并且在开始时具有与跨步内核类似的分析数据。

空内核在0.25秒内执行,因此它不会加载整个结构。只读取所需的元素。

用于交叉的以组为中心的全局访问的分析:

typedef struct test_struct
{
   float test_field[4096];
}strr;
__kernel void test(__global strr * a)
{
    int iLocal=get_local_id(0);
    int iGroup=get_group_id(0);
    for(int j=0;j<64;j++)
    a[iGroup].test_field[iLocal+j*64]*=2.0f;
}
再次

0.25秒,所以它尽可能快。

缓存命中:%44 存储单元忙:%82 内存单元停滞:%67 Valu忙:%0.9

所以它具有最佳条件,即使没有缓存。