1

我正在尝试计算在 Conway 的 GOL 运行中对 pxq 矩阵进行 n 次迭代的转换次数。例如,给定 1 次迭代,初始状态为 1 个闪烁(如下所示)。将有 5 次过渡(2 人出生,1 人存活,2 人死于人口不足)。我已经完成了这项工作,但我想将此逻辑转换为使用 CUDA 运行。以下是我要移植到 CUDA 的内容。

替代文字 代码:

    static void gol() // call this iterations x's
    {
        int[] tempGrid = new int[rows * cols]; // grid holds init conditions
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                tempGrid[i * cols + j] = grid[i * cols + j];
            }
        }

        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                int numNeighbors = neighbors(i, j); // finds # of neighbors

                if (grid[i * cols + j] == 1 && numNeighbors > 3)
                {
                    tempGrid[i * cols + j] = 0;
                    overcrowding++;
                }
                else if (grid[i * cols + j] == 1 && numNeighbors < 2)
                {
                    tempGrid[i * cols + j] = 0;
                    underpopulation++;
                }
                else if (grid[i * cols + j] == 1 && numNeighbors > 1)
                {
                    tempGrid[i * cols + j] = 1;
                    survival++;
                }
                else if (grid[i * cols + j] == 0 && numNeighbors == 3)
                {
                    tempGrid[i * cols + j] = 1;
                    birth++;
                }
            }
        }

        grid = tempGrid;
    }
4

2 回答 2

4

您的主要减速将是主内存访问。因此,我建议您根据可用的硬件选择较大的线程块大小。256 (16x16) 是跨硬件兼容性的不错选择。这些线程块中的每一个都将计算电路板稍小的部分的结果——如果您使用 16x16,它们将计算电路板的 14x14 部分的结果,因为有一个元素边框。(使用 16x16 块来计算 14x14 块而不是 16x16 块的原因是为了内存读取合并。)

将板分成(比如说)14x14 块;那是您的网格(以您认为合适的方式组织,但很可能类似于board_width / 14, board_height / 14.

在内核中,让每个线程将其元素加载到共享内存中。然后同步线程。然后让中间的 14x14 元素计算新值(使用存储在共享内存中的值)并将其写回全局内存。共享内存的使用有助于最大限度地减少全局读取和写入。这也是让你的线程块大小尽可能大的原因——边缘和角落是“浪费的”全局内存访问,因为在那里获取的值只会被使用 1 或 3 次,而不是 9 次。

于 2010-12-14T15:39:59.680 回答
0

这是您可以继续的一种方法:

  1. 每个线程对网格的 1 个元素进行计算
  2. 每个线程首先将主网格中的一个元素加载到共享内存中
  3. 线程块边缘的线程也需要加载边界元素
  4. 然后每个线程可以根据共享内存的内容进行生存计算
  5. 然后每个线程将它们的结果写回主存
于 2010-12-14T13:33:13.153 回答