Это должно быть просто, хотя я не могу найти ответ. Я пишу программу, которая должна вычислять состояния клеточных автоматов, и чтобы понять, как работает 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 не может работать со значениями трех соседних ячеек в одном потоке.