为什么浮动的 OpenCL atomic_add 实现会产生不确定的结果?
Why does the OpenCL atomic_add implementation for float produce a non-deterministic outcome?
我需要在 OpenCL 的多个线程中将 float
添加到相同的全局内存地址。对于任何两个模拟 运行s,结果永远不会相同,并且对 atomic_add_f
函数的调用是此错误的来源。我正在使用带驱动程序 436.02 的 Nvidia Titan Xp GPU。
由于 OpenCL 不支持 atomic_add
和 float
,因此有 ways around 使用 atomic_cmpxchg
:
void atomic_add_f(volatile global float* addr, const float val) {
union {
uint u32;
float f32;
} next, expected, current;
current.f32 = *addr;
do {
next.f32 = (expected.f32=current.f32)+val; // ...*val for atomic_mul_f()
current.u32 = atomic_cmpxchg((volatile global uint*)addr, expected.u32, next.u32);
} while(current.u32!=expected.u32);
}
但是,此代码确实会产生不确定的结果。每个 运行 的结果略有不同,类似于存在竞争条件的情况。
我也试过这个版本
void atomic_add_f(volatile global float* addr, const float val) {
private float old, sum;
do {
old = *addr;
sum = old+val;
} while(atomic_cmpxchg((volatile global int*)addr, as_int(old), as_int(sum))!=as_int(old));
}
这也不能正常工作。提供的版本 here 也不起作用。
这是怎么回事,如何解决?
由于浮点运算的工作方式,(a + b) + c
和 a + (b + c)
不一定产生完全相同的结果。中间结果总是 t运行cated 或四舍五入。由于内核的不同工作项没有确定性的顺序运行,因此您的总和将不是确定性的。
维基百科 provides some examples 的浮点计算根据结合性不会产生相同的结果。
可能的解决方案:
- 不要使用浮点累加器。
- 将您的结果写入数组,并在单独的步骤中使用主机上的串行求和或 GPU 或加速器上的确定性缩减算法对数组求和。
请注意,OpenCL 不要求任何特定的舍入行为,因此即使您将累加更改为确定性的,算法的其余部分很可能不会在不同的 OpenCL 实现中产生一致的结果。如果您绝对必须在所有情况下为相同的输入获得相同的结果,请不要使用浮点运算,使用适当大小的整数。
我需要在 OpenCL 的多个线程中将 float
添加到相同的全局内存地址。对于任何两个模拟 运行s,结果永远不会相同,并且对 atomic_add_f
函数的调用是此错误的来源。我正在使用带驱动程序 436.02 的 Nvidia Titan Xp GPU。
由于 OpenCL 不支持 atomic_add
和 float
,因此有 ways around 使用 atomic_cmpxchg
:
void atomic_add_f(volatile global float* addr, const float val) {
union {
uint u32;
float f32;
} next, expected, current;
current.f32 = *addr;
do {
next.f32 = (expected.f32=current.f32)+val; // ...*val for atomic_mul_f()
current.u32 = atomic_cmpxchg((volatile global uint*)addr, expected.u32, next.u32);
} while(current.u32!=expected.u32);
}
但是,此代码确实会产生不确定的结果。每个 运行 的结果略有不同,类似于存在竞争条件的情况。
我也试过这个版本
void atomic_add_f(volatile global float* addr, const float val) {
private float old, sum;
do {
old = *addr;
sum = old+val;
} while(atomic_cmpxchg((volatile global int*)addr, as_int(old), as_int(sum))!=as_int(old));
}
这也不能正常工作。提供的版本 here 也不起作用。
这是怎么回事,如何解决?
由于浮点运算的工作方式,(a + b) + c
和 a + (b + c)
不一定产生完全相同的结果。中间结果总是 t运行cated 或四舍五入。由于内核的不同工作项没有确定性的顺序运行,因此您的总和将不是确定性的。
维基百科 provides some examples 的浮点计算根据结合性不会产生相同的结果。
可能的解决方案:
- 不要使用浮点累加器。
- 将您的结果写入数组,并在单独的步骤中使用主机上的串行求和或 GPU 或加速器上的确定性缩减算法对数组求和。
请注意,OpenCL 不要求任何特定的舍入行为,因此即使您将累加更改为确定性的,算法的其余部分很可能不会在不同的 OpenCL 实现中产生一致的结果。如果您绝对必须在所有情况下为相同的输入获得相同的结果,请不要使用浮点运算,使用适当大小的整数。