OpenCL - 本地内存

时间:2016-11-13 15:31:21

标签: c memory kernel opencl

我确实理解一般的全局和本地内存之间的区别。 但我使用本地内存时遇到问题。

1)通过将全局内存变量转换为本地内存变量需要考虑什么?

2)我如何使用local-barriers?

也许有人可以用一个小例子来帮助我。

我尝试使用本地内存进行jacobi计算,但结果只得到0。也许有人可以给我一个建议。

工作解决方案:

  @Override
  public int compareTo(Rational o) {
    float mine = (float) getNumerator() / getDenominator();
    float other = (float) o.getNumerator() / o.getDenominator();
    return Float.compare(mine, other);
  }

感谢。

1 个答案:

答案 0 :(得分:5)

  • 1)查询CL_DEVICE_LOCAL_MEM_SIZE值,最小为16kB,并为不同的硬件递增。如果您的局部变量适合这种情况,并且如果它们被多次重复使用,您应该在使用前将它们放在本地内存中。即使你不这样做,在访问gpu的全局内存时自动使用L2缓存对于核心的使用仍然是有效的。

    如果全局 - 本地副本占用了大量时间,则可以在核心计算时执行异步工作组复制。

    另一个重要的部分是,更多的空闲本地内存空间意味着每个内核有更多的并发线程。如果gpu每个计算单元有64个核心,则在使用所有本地内存时只能运行64个线程。当它有更多空间时,如果没有其他限制,可以同时运行128,192,... 2560个线程。

    分析器可以显示瓶颈,因此您可以认为值得一试。

    例如,使用嵌套循环的朴素矩阵 - 矩阵乘法依赖于高速缓存l1 l2,但是submatices可以适合本地内存。也许48x48个浮点数可以放在中档显卡计算单元中,并且可以在被下一个子矩阵替换之前用于整个计算N次。

    CL_DEVICE_LOCAL_MEM_TYPE查询可以返回LOCAL或GLOBAL,如果它是GLOBAL,也表示不建议使用本地内存。

    最后,任何内存空间分配(除了__private)大小必须在编译时知道(对于设备,而不是主机),因为它必须知道可以发出多少波前来实现最大性能(和/或可能是其他编译器优化) 。这就是为什么opencl 1.2不允许递归函数的原因。但是你可以复制一个函数并重命名n次以获得伪递归。

  • 2)障碍是工作组中所有工作组线程的会合点。类似于循环障碍,他们都停在那里,等待所有,直到继续。如果它是本地屏障,则所有工作组线程在离开该点之前完成任何本地内存操作。如果你想给一个本地数组提供一些数字1,2,3,4 ..你不能确定所有线程是否写入这些数字或者已经写过,直到通过本地屏障,那么它是肯定的该数组将具有已写入的最终值。

    所有工作组线程必须达到相同的障碍。如果无法访问它,内核卡住或者您收到错误。

__local int localArray[64]; // not each thread. For all threads. 
                            // per compute unit.

if(localThreadId!=0)               
    localArray[localThreadId]=localThreadId; // 64 values written in O(1)
// not sure if 2nd thread done writing, just like last thread

if(localThreadId==0) // 1st core of each compute unit loads from VRAM
    localArray[localThreadId]=globalArray[globalThreadId];

barrier(CLK_LOCAL_MEM_FENCE); // probably all threads wait 1st thread
                              // (maybe even 1st SIMD or 
                              // could be even whole 1st wavefront!)
// here all threads written their own id to local array. safe to read.
// except first element which is a variable from global memory
// lets add that value to all other values
if(localThreadId!=0)
   localArrray[localThreadId]+=localArray[0];

工作示例(本地工作组大小= 64):

输入:0,1,2,3,4,0,0,0,0,0,0,..

    __kernel void vecAdd(__global float* x )
    {
       int id = get_global_id(0);
       int idL = get_local_id(0);
       __local float loc[64];
       loc[idL]=x[id];
       barrier (CLK_LOCAL_MEM_FENCE);
       float distance_square_sum=0;
       for(int i=0;i<64;i++)
       { 
            float diff=loc[idL]-loc[i];
            float diff_squared=diff*diff;
            distance_square_sum+=diff_squared;
       }       
       x[id]=distance_square_sum;

    }

输出:30,74,246,546,974,30,30,30 ......