更改CUDA中多个单元格的值

时间:2013-02-10 09:12:08

标签: cuda pycuda

它必须是一个简单的,但我找不到答案。我正在编写一个程序,它必须计算细胞自动机的状态,并且为了感觉CUDA是如何工作的,我试着先写一个非常简单的程序。它需要一个矩阵,并且每个线程必须在其单元格中以及在该单元格的上方和下方的单元格中递增值。所以,如果我给它以下矩阵:

[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]

我希望得到以下结果:

[2 2 2 2 2 2 2]
[3 3 3 3 3 3 3]
[3 3 3 3 3 3 3]
[3 3 3 3 3 3 3]
[3 3 3 3 3 3 3]
[3 3 3 3 3 3 3]
[2 2 2 2 2 2 2]  

第一行的值为2,因为它上面没有一行可以再增加第一行的值。并且以类似的方式,最后一行的值为2 但我得到的矩阵看起来像这样:

[2 2 2 2 2 2 2]
[3 3 3 3 3 3 3]
[3 3 3 3 3 3 3]
[3 3 3 3 2 2 2]
[2 2 2 2 2 2 2]
[2 2 2 2 3 3 3]
[2 2 2 2 2 2 2]  

我无法理解为什么第4排,第5排和第6排的值为2 - 必须有3,而不是2。 这是我的代码:

import numpy
import pycuda.autoinit
import pycuda.driver as cuda

from pycuda.compiler import SourceModule

w = 7

mod = SourceModule("""
        __global__ void diffusion(  int* result, int width, int height) {

            int xIndex = blockDim.x * blockIdx.x + threadIdx.x;
            int yIndex = blockDim.y * blockIdx.y + threadIdx.y;

            int flatIndex = xIndex + width * yIndex;
            int topIndex = xIndex + width * (yIndex - 1);
            int bottomIndex = xIndex + width * (yIndex + 1);

            int inc = 1;

            result[flatIndex] += inc;

            result[bottomIndex] += inc;

            result[topIndex] += inc;
        }

        """)

diff_func   = mod.get_function("diffusion")


def diffusion(res):

    height, width = numpy.int32(len(res)), numpy.int32(len(res[0]))

    diff_func(
        cuda.InOut(res),
        width,
        height,
        block=(w,w,1)
        )

def run(res, step):

    diffusion(res)
    print res

res   = numpy.array([[0 \
                        for _ in xrange(0, w)]\
                        for _ in xrange(0, w)], dtype='int32')

run(res, 0)  

另一个有趣的事情:如果我评论以下其中一行:

result[bottomIndex] += inc;
result[topIndex] += inc;  

一切都按预期工作,没有任何意外的值。看起来在某些情况下,CUDA无法使用一个线程中三个相邻单元格的值。

1 个答案:

答案 0 :(得分:2)

您拥有所谓的内存竞争:多个独立线程正在尝试同时更新内存中的相同值。 CUDA内存模型没有定义当两个线程同时尝试更新同一内存位置时会发生什么。

解决方案要么是使用原子内存操作(请参阅CUDA编程指南以获取更多信息),要么使用不同的方法来更新相邻单元格(例如,为网格着色并在单独的网格中更新像彩色单元格一样) 。