我正在阅读本文http://eprints.dcs.warwick.ac.uk/1694/1/miniMD_opencl.pdf关于使用OpenCl的迷你分子动力学应用。代码位于此处。
我对内核的实现方式感到困惑。我不明白的是这个
#if defined(SCALAR_KERNELS)
__kernel void f_clear(
__global float* f,
__const int nall) {
for (unsigned i = get_global_id(0)+1; i <= nall; i += get_global_size(0)) {
const int i4 = i << 2;
f[i4+0] = 0.0f;
f[i4+1] = 0.0f;
f[i4+2] = 0.0f;
f[i4+3] = 0.0f;
}
}
#elif defined(VECTOR_KERNELS)
__kernel __attribute__((vec_type_hint(float4)))
void f_clear(
__global float4* f,
__const int nall) {
const float4 zeroes = (float4) (0.0f, 0.0f, 0.0f, 0.0f);
for (unsigned i = get_global_id(0)+1; i <= nall; i += get_global_size(0)) {
f[i] = zeroes;
}
}
#endif
假设VECTOR_KERNELS
和SCALAR_KERNELS
对应GPU和MIC设备,但不确定
这与MIMD SIMD指令或多核和矢量编程有关吗?
现在使用矢量类型还有一个真正的好处吗?
最后,我真的无法弄清楚两个for循环的作用以及它们的目的
为什么不做f[get_global_id(0)]
?
谢谢,
埃里克。
答案 0 :(得分:3)
标量和向量只是在OpenCL中执行相同操作的不同方式。 但是向量是要走的路,因为编译器(CPU或GPU / FPGA)应该更好地优化它们。这样编译器可以自然地使用SIMD单元。所以,如果有可能并且更容易使用它们,请使用它们。
正如Austin所说,两个循环都清除了nall
的全局内存大小。
然而,查看代码是非常低效的。同一工作组中的工作项正在访问完全不同的全局内存区域,从而破坏了合并。 (正如你所说的那样)会好得多:
__kernel __attribute__((vec_type_hint(float4)))
void f_clear(
__global float4* f) {
f[get_global_id(0)] = (float4) (0.0f, 0.0f, 0.0f, 0.0f);
}
使用适当的全局大小(global_size = nall
)启动此内核,并让编译器决定本地工作组大小。
PS:如果我必须这样做,我更喜欢调用clEnqueueWriteBuffer并从CPU清理内存。因为它可以与其他内核执行并行完成。
答案 1 :(得分:1)
AMD,ATI和Intel等设备非常适合支持矢量类型。这些向量是SIMD,如果可能的话,使用它会更快。在支持OpenCL中的向量时,NVIDIA似乎并不是很好(至少是我测试过的所有内容)。
两个循环似乎都清除了一大块nall
的全局内存。