我确实理解一般的全局和本地内存之间的区别。 但我使用本地内存时遇到问题。
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);
}
感谢。
答案 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 ......