我认为这是一个 GPU 问题而不是 C++ AP 问题,因此我对其进行了广泛的标记。
我有一个计算的实现,它将工作分成许多块来完成它们的工作,然后将结果添加到全局内存中的现有值中。首先,tile 中的每个线程都将它们的部分结果计算到 tile_static 内存中,每个线程都有一个要写入的索引。稍后,图块中的第一个线程会将所有部分结果汇总在一起,并将总和添加到全局内存中的某个位置。
瓦片(瓦片中的线程 0)有时会想要写入相同的位置,所以我添加了简单的锁定。
inline void lock(int *lockVariable) restrict(amp)
{
while (atomic_exchange(lockVariable, 1) != 0);
}
inline void unlock(int *lockVariable) restrict(amp)
{
*lockVariable = 0;
}
我传递给 lock 和 unlock 的 lock 变量位于一个全局整数数组中,每个争用内存位置一个整数,tile 将写入。
瓦片结果的实际写入,由瓦片中的第一个线程完成,是这样完成的
//now the FIRST thread in the tile will summ all the pulls into one
if (idx.local[0] == 0)
{
double_4 tileAcceleration = 0;
for (int i = 0; i < idx.tile_dim0; i++)
{
tileAcceleration += threadAccelerations[i];
}
lock(&locks[j]);
//now the FIRST thread in the tile will add this to the global result
acceleration[j] += tileAcceleration;
unlock(&locks[j]);
}
这大部分都可以,但并非总是如此。必须存在一些竞态条件,因为当相对于要写入的内存位置数量而言,tile 太多时(过多的锁争夺),有时它会无法正确添加 tile 结果。
似乎有时,虽然很少,锁定/解锁设置不能确保正确添加。
这可以通过将锁向上移动到求和前面来“修复”,因此从获得锁到 thread0 进行实际写入之前需要更长的时间。当我在总和中剩下五个元素时,我也可以通过锁定来“修复”它。两者都如下图
第一次修复,速度很慢(阻塞太久)
if (idx.local[0] == 0)
{
lock(&locks[j]); //get lock right away
double_4 tileAcceleration = 0;
for (int i = 0; i < idx.tile_dim0; i++)
{
tileAcceleration += threadAccelerations[i];
}
//now the FIRST thread in the tile will add this to the global result
acceleration[j] += tileAcceleration;
unlock(&locks[j]);
}
第二次修复,速度更快
if (idx.local[0] == 0)
{
lock(&locks[j]); //this is a "fix" but a slow one
double_4 tileAcceleration = 0;
for (int i = 0; i < idx.tile_dim0; i++)
{
tileAcceleration += threadAccelerations[i];
if (i == idx.tile_dim0 - 5) lock(&locks[j]); //lock when almost done
}
//now the FIRST thread in the tile will add this to the global result
acceleration[j] += tileAcceleration;
unlock(&locks[j]);
}
看看这些“修复”是如何工作的,很明显,一些内存写入在系统范围内的更新速度不够快。一个磁贴可以锁定一个位置,写入它并解锁。然后另一个图块获得锁,进行添加(但指的是旧的未更新数据)并解锁。
锁是一个 int,数据是一个 double_4,所以看起来锁的释放和更新速度足够快,以便其他图块在数据仍在传输中时看到。即使第一个写入的块还没有完全提交,另一个块可以看到锁是空闲的。因此,第二个图块从缓存中读取未更新的数据值并添加到它并写入...
有人可以帮我理解为什么当第一个磁贴写入时数据没有失效(在缓存中),有人可以帮我找到解决这个问题的正确方法吗?