nVidia上的OpenCL NDRange维度订单错误?
我知道OpenCL现在相当空闲,尤其是NVidia的CUDA实现。也就是说,我认为我在Nvidia中发现了一个重要的bug,我想看看是否有其他人也注意到了这一点。使用Linux <强>平台版本OpenCL 1.2 CUDA 1.1.0,C++绑定< /强>我一直有NDRANGE顺序的各种问题,最后我有一个简单的内核可以明确地再现问题:nVidia上的OpenCL NDRange维度订单错误?,opencl,nvidia,Opencl,Nvidia,我知道OpenCL现在相当空闲,尤其是NVidia的CUDA实现。也就是说,我认为我在Nvidia中发现了一个重要的bug,我想看看是否有其他人也注意到了这一点。使用Linux 平台版本OpenCL 1.2 CUDA 1.1.0,C++绑定< /强>我一直有NDRANGE顺序的各种问题,最后我有一个简单的内核可以明确地再现问题: void kernel test() { printf("G0:%d G1:%d G2:%d L0:%d L1:%d L2:%d\n",
void kernel test()
{
printf("G0:%d G1:%d G2:%d L0:%d L1:%d L2:%d\n",
get_global_id(0),
get_global_id(1),
get_global_id(2),
get_local_id(0),
get_local_id(1),
get_local_id(2));
}
如果我用3个维度将这个内核排队:全局(4,3,2)和局部(1,1,1):
它在AMD/Intel上随机正确输出以下内容(为清晰起见,随机输出排序):
这遵循规范。但如果我使用NVidia I计划具有相同维度的完全相同的内核,则会产生以下输出:
G0:0 G1:0 G2:0 L0:0 L1:0 L2:0
G0:0 G1:0 G2:0 L0:0 L1:1 L2:0
G0:0 G1:0 G2:1 L0:0 L1:0 L2:0
G0:0 G1:0 G2:1 L0:0 L1:1 L2:0
G0:0 G1:0 G2:2 L0:0 L1:0 L2:0
G0:0 G1:0 G2:2 L0:0 L1:1 L2:0
G0:1 G1:0 G2:0 L0:0 L1:0 L2:0
G0:1 G1:0 G2:0 L0:0 L1:1 L2:0
G0:1 G1:0 G2:1 L0:0 L1:0 L2:0
G0:1 G1:0 G2:1 L0:0 L1:1 L2:0
G0:1 G1:0 G2:2 L0:0 L1:0 L2:0
G0:1 G1:0 G2:2 L0:0 L1:1 L2:0
G0:2 G1:0 G2:0 L0:0 L1:0 L2:0
G0:2 G1:0 G2:0 L0:0 L1:1 L2:0
G0:2 G1:0 G2:1 L0:0 L1:0 L2:0
G0:2 G1:0 G2:1 L0:0 L1:1 L2:0
G0:2 G1:0 G2:2 L0:0 L1:0 L2:0
G0:2 G1:0 G2:2 L0:0 L1:1 L2:0
G0:3 G1:0 G2:0 L0:0 L1:0 L2:0
G0:3 G1:0 G2:0 L0:0 L1:1 L2:0
G0:3 G1:0 G2:1 L0:0 L1:0 L2:0
G0:3 G1:0 G2:1 L0:0 L1:1 L2:0
G0:3 G1:0 G2:2 L0:0 L1:0 L2:0
G0:3 G1:0 G2:2 L0:0 L1:1 L2:0
void kernel test()
{
printf("G0:%d G1:%d G2:%d L0:%d L1:%d L2:%d\n",
get_global_id(0),
get_global_id(1),
get_global_id(2),
get_local_id(0),
get_local_id(1),
get_local_id(2));
}
tl;dr:原因几乎可以肯定是由于printf
中缺少同步
首先,我观察到了与您相同的行为:在AMD上,输出似乎是正确的。在NVIDIA上,这似乎是令人恼火的错误。所以我很好奇,扩展了内核,也打印了
get\u local\u size
:
void kernel test()
{
printf("G0:%d G1:%d G2:%d L0:%d L1:%d L2:%d S0:%d S1:%d S2:%d\n",
get_global_id(0),
get_global_id(1),
get_global_id(2),
get_local_id(0),
get_local_id(1),
get_local_id(2),
get_local_size(0),
get_local_size(1),
get_local_size(2));
}
现在,get\u local\u id
当然必须小于大小,否则大多数内核都会崩溃。在AMD上,输出良好且干净:
platform AMD Accelerated Parallel Processing
device Spectre
G0:0 G1:0 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:1 G1:0 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:2 G1:0 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:3 G1:0 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:0 G1:1 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:1 G1:1 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:2 G1:1 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:3 G1:1 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:0 G1:2 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:1 G1:2 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:2 G1:2 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:3 G1:2 G2:0 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:0 G1:0 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:1 G1:0 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:2 G1:0 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:3 G1:0 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:0 G1:1 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:1 G1:1 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:2 G1:1 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:3 G1:1 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:0 G1:2 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:1 G1:2 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:2 G1:2 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
G0:3 G1:2 G2:1 L0:0 L1:0 L2:0 S0:1 S1:1 S2:1
在NVIDIA上,输出为
platform NVIDIA CUDA
device GeForce GTX 970
G0:3 G1:0 G2:2 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:3 G1:0 G2:1 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:3 G1:0 G2:0 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:0 G1:0 G2:2 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:0 G1:0 G2:1 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:2 G1:0 G2:0 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:2 G1:0 G2:1 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:2 G1:0 G2:2 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:1 G1:0 G2:1 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:3 G1:0 G2:0 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:1 G1:0 G2:0 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:3 G1:0 G2:1 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:0 G1:0 G2:2 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:1 G1:0 G2:2 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:3 G1:0 G2:2 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:0 G1:0 G2:1 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:2 G1:0 G2:1 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:0 G1:0 G2:0 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:2 G1:0 G2:0 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:0 G1:0 G2:0 L0:0 L1:0 L2:0 S0:0 S1:0 S2:0
G0:2 G1:0 G2:2 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:1 G1:0 G2:2 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:1 G1:0 G2:1 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
G0:1 G1:0 G2:0 L0:0 L1:1 L2:0 S0:0 S1:0 S2:0
现在,不可能是正确的:本地工作大小始终为0
经过一些进一步的测试(例如,使用2D内核和不同的数字),输出通常看起来毫无意义。所以我尝试了这个内核:
void kernel test()
{
printf("G0:%d\n", get_global_id(0));
printf("G1:%d\n", get_global_id(1));
printf("G2:%d\n", get_global_id(2));
printf("L0:%d\n", get_local_id(0));
printf("L1:%d\n", get_local_id(1));
printf("L2:%d\n", get_local_id(2));
printf("S0:%d\n", get_local_size(0));
printf("S1:%d\n", get_local_size(1));
printf("S2:%d\n", get_local_size(2));
}
在NVIDIA上,输出为
platform NVIDIA CUDA
device GeForce GTX 970
G0:1
G0:1
G0:1
G0:2
G0:2
G0:2
G0:2
G0:2
G0:3
G0:2
G0:3
G0:3
G0:0
G0:3
G0:3
G0:0
G0:0
G0:3
G0:0
G0:0
G0:0
G0:1
G0:1
G0:1
G1:2
G1:2
G1:0
G1:0
G1:1
G1:2
G1:2
G1:1
G1:1
G1:1
G1:0
G1:0
G1:2
G1:1
G1:0
G1:0
G1:2
G1:1
G1:1
G1:0
G1:2
G1:2
G1:0
G1:1
G2:0
G2:0
G2:1
G2:1
G2:0
G2:0
G2:1
G2:0
G2:0
G2:0
G2:0
G2:0
G2:1
G2:1
G2:0
G2:1
G2:1
G2:1
G2:1
G2:0
G2:1
G2:0
G2:1
G2:1
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L2:0
L1:0
L1:0
L1:0
L1:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
S0:1
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S1:1
S0:1
S0:1
S0:1
S0:1
S0:1
S1:1
S0:1
S0:1
S0:1
S0:1
S0:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S2:1
S1:1
S1:1
S1:1
S2:1
S1:1
S1:1
S1:1
S1:1
S1:1
S2:1
S1:1
S1:1
S2:1
S2:1
S1:1
S1:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
关键点是:每个人的输出都是正确的!。问题似乎是将所有内容放入一个printf
中会弄乱一些内部缓冲区
当然,这是一个遗憾。它基本上不可能将printf
用于内核内部合理使用的唯一目的,即用于调试
旁白:此时规范仍然有点难以解释——至少在决定观察到的行为是“正确”还是“错误”时是如此。从: 如果同时从多个工作项执行printf,则无法保证对书面数据进行排序。例如,全局id为(0,0,1)的工作项的输出与全局id为(0,0,4)的工作项的输出混合显示是有效的,依此类推
还包含一些免责声明,并讨论了一些可能被覆盖的缓冲区,但将其(在规范的技术级别上)映射到OpenCL行为是很困难的…非常有帮助,感谢复制。我会在一点时间内亲自尝试验证。是的,你是对的。我以为我在没有printf的情况下复制了这种行为,但我的测试本身并不准确。你的同步是正确的。谢谢更正:这是与printf的同步问题。
platform NVIDIA CUDA
device GeForce GTX 970
G0:1
G0:1
G0:1
G0:2
G0:2
G0:2
G0:2
G0:2
G0:3
G0:2
G0:3
G0:3
G0:0
G0:3
G0:3
G0:0
G0:0
G0:3
G0:0
G0:0
G0:0
G0:1
G0:1
G0:1
G1:2
G1:2
G1:0
G1:0
G1:1
G1:2
G1:2
G1:1
G1:1
G1:1
G1:0
G1:0
G1:2
G1:1
G1:0
G1:0
G1:2
G1:1
G1:1
G1:0
G1:2
G1:2
G1:0
G1:1
G2:0
G2:0
G2:1
G2:1
G2:0
G2:0
G2:1
G2:0
G2:0
G2:0
G2:0
G2:0
G2:1
G2:1
G2:0
G2:1
G2:1
G2:1
G2:1
G2:0
G2:1
G2:0
G2:1
G2:1
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L0:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L1:0
L2:0
L1:0
L1:0
L1:0
L1:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
S0:1
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
L2:0
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S0:1
S1:1
S0:1
S0:1
S0:1
S0:1
S0:1
S1:1
S0:1
S0:1
S0:1
S0:1
S0:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S1:1
S2:1
S1:1
S1:1
S1:1
S2:1
S1:1
S1:1
S1:1
S1:1
S1:1
S2:1
S1:1
S1:1
S2:1
S2:1
S1:1
S1:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1
S2:1