Cuda/cudafy 3d 索引
Cuda/cudafy 3d indexing
试图了解 cuda,在没有掌握类似的 Whosebug 问题后,我决定测试一个示例(我正在使用 cudafy.net for c#,但底层的 cuda 应该是可解析的)
我想做以下事情。向内核发送一个4x4x4的矩阵,按照这个逻辑得到一个4x4x4的输出:
if(input[x,y,z] == 1)
output[x+1, y, z]++;
if(input[x,y,z] == 2)
output[x-1, y, z]++;
我研究了下面的cudafy例子
public const int N = 1 * 1024;
//Omissions
gpu.Launch(128, 1, function, dev_a, dev_b, dev_c);
内核:
[Cudafy]
public static void add_0(GThread thread, int[] a, int[] b, int[] c)
{
int tid = thread.blockIdx.x; // (tid 0 -> 127, from my understanding)
while (tid < N)
{
c[tid] = a[tid] + b[tid];
tid += thread.gridDim.x;
}
}
然后尝试将其转为3d。我无法获得正确的索引。说我有以下内容。 (这里的三个数组只是为了测试索引)
int size = 4;
int[] dev_delta = gpu.Allocate<int>(size * size * size);
int[] dev_space = gpu.Allocate<int>(size * size * size);
int[] dev_result = gpu.Allocate<int>(size * size * size);
gpu.Launch(new dim3(4, 4, 4), 1, "testIndex", dev_delta, dev_space, dev_result);
和内核:
[Cudafy]
public static void testIndex(GThread thread, int[] delta, int[] space, int[] result)
{
int x = thread.blockIdx.x;
int y = thread.blockIdx.y;
int z = thread.blockIdx.z;
delta[x]++;
space[y]++;
result[z]++;
}
我天真地期待以下内容:
delta = {4,4,4,4,0,0,0,0,0, ... 0,0}
space = {4,4,4,4,0,0,0,0,0, ... 0,0}
result = {4,4,4,4,0,0,0,0,0 ... 0,0}
但我得到:
delta = {1,1,1,1,0,0,0,0,0, ... 0,0}
space = {1,1,1,1,0,0,0,0,0, ... 0,0}
result = {1,0,0,0,0,0,0,0,0 ... 0,0}
这对我来说毫无意义,显然我错过了一些东西。
问题:
我要启动多少线程?
你如何处理 'indexing' 我的 3 维示例问题(启动 4x4x4 线程并获取 flat3DArray[x * sizeY * sizeZ + y * sizeZ + z] 的变量)?
你如何处理 'indexing' 我的二维示例问题? (启动 4x4 线程,然后让每个线程处理长度为 4 的深度列)
我发现这可能是相关的如果这就是我的问题,我仍然很感激纯 cuda 的答案来整理我的大脑
我要启动多少线程?
每个块启动 1 个线程,因此由于未使用 Z 参数,因此总共有 16 个线程。为了获得更好的性能,我建议还使用线程(至少 128,并且是 32 的倍数)。
你如何处理 'indexing' 我的 3 维示例问题(启动 4x4x4 线程并获取 flat3DArray[x * sizeY * sizeZ + y *尺寸 Z + z])?
gpu.Launch
方法的第二个参数用于线程。因此,x
、y
和 z
可能分别是 threadIdx.x
、threadIdx.y
和 threadIdx.z
。但您可能还想使用许多块,因此 threadIdx.x + blockDim.x * blockIdx.x
可能是一个很好的峰值。
您提供的 link 解释了为什么您的 Z 尺寸不相关。 CUDAfy.Net 公开进一步调用 cuda 运行时 CUDA/C API 调用的启动函数。将参数从 dot net 传递到本机环境时,CUDAfy.Net 似乎只是忽略了 Z 参数,将其保留为 1。 (这很可能是因为 CUDA 的早期版本不支持不同于 one 的 Z 参数)。
解释不是纯 cuda,因为 CUDA 现在支持不同于 1 的 Z 值,但是在 CUDAfy.Net 实现中,您的参数被简单地忽略了。
试图了解 cuda,在没有掌握类似的 Whosebug 问题后,我决定测试一个示例(我正在使用 cudafy.net for c#,但底层的 cuda 应该是可解析的)
我想做以下事情。向内核发送一个4x4x4的矩阵,按照这个逻辑得到一个4x4x4的输出:
if(input[x,y,z] == 1)
output[x+1, y, z]++;
if(input[x,y,z] == 2)
output[x-1, y, z]++;
我研究了下面的cudafy例子
public const int N = 1 * 1024;
//Omissions
gpu.Launch(128, 1, function, dev_a, dev_b, dev_c);
内核:
[Cudafy]
public static void add_0(GThread thread, int[] a, int[] b, int[] c)
{
int tid = thread.blockIdx.x; // (tid 0 -> 127, from my understanding)
while (tid < N)
{
c[tid] = a[tid] + b[tid];
tid += thread.gridDim.x;
}
}
然后尝试将其转为3d。我无法获得正确的索引。说我有以下内容。 (这里的三个数组只是为了测试索引)
int size = 4;
int[] dev_delta = gpu.Allocate<int>(size * size * size);
int[] dev_space = gpu.Allocate<int>(size * size * size);
int[] dev_result = gpu.Allocate<int>(size * size * size);
gpu.Launch(new dim3(4, 4, 4), 1, "testIndex", dev_delta, dev_space, dev_result);
和内核:
[Cudafy]
public static void testIndex(GThread thread, int[] delta, int[] space, int[] result)
{
int x = thread.blockIdx.x;
int y = thread.blockIdx.y;
int z = thread.blockIdx.z;
delta[x]++;
space[y]++;
result[z]++;
}
我天真地期待以下内容:
delta = {4,4,4,4,0,0,0,0,0, ... 0,0}
space = {4,4,4,4,0,0,0,0,0, ... 0,0}
result = {4,4,4,4,0,0,0,0,0 ... 0,0}
但我得到:
delta = {1,1,1,1,0,0,0,0,0, ... 0,0}
space = {1,1,1,1,0,0,0,0,0, ... 0,0}
result = {1,0,0,0,0,0,0,0,0 ... 0,0}
这对我来说毫无意义,显然我错过了一些东西。
问题:
我要启动多少线程?
你如何处理 'indexing' 我的 3 维示例问题(启动 4x4x4 线程并获取 flat3DArray[x * sizeY * sizeZ + y * sizeZ + z] 的变量)?
你如何处理 'indexing' 我的二维示例问题? (启动 4x4 线程,然后让每个线程处理长度为 4 的深度列)
我发现这可能是相关的
我要启动多少线程? 每个块启动 1 个线程,因此由于未使用 Z 参数,因此总共有 16 个线程。为了获得更好的性能,我建议还使用线程(至少 128,并且是 32 的倍数)。
你如何处理 'indexing' 我的 3 维示例问题(启动 4x4x4 线程并获取 flat3DArray[x * sizeY * sizeZ + y *尺寸 Z + z])?
gpu.Launch
方法的第二个参数用于线程。因此,x
、y
和 z
可能分别是 threadIdx.x
、threadIdx.y
和 threadIdx.z
。但您可能还想使用许多块,因此 threadIdx.x + blockDim.x * blockIdx.x
可能是一个很好的峰值。
您提供的 link