Cuda/cudafy 3d индексация
Пытаясь разобраться в cuda, после того, как я не понял подобные вопросы, связанные с stackru, я решил протестировать пример (я использую cudafy.net для 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}
Это не имеет смысла для меня, ясно, что я что-то упустил.
Вопросы:
Сколько тем я запускаю?
Как вы относитесь к "индексации" моего примера задачи в 3 измерениях (начиная с потоков 4x4x4 и получая переменные для flat3DArray[x * sizeY * sizeZ + y * sizeZ + z])?
Как вы относитесь к "индексации" моего примера задачи в двух измерениях? (Начиная с потоков 4х4, а затем пусть каждый поток обрабатывает столбец глубины длины 4)
Я обнаружил, что это может быть актуально. Почему в ядре CUDA z всегда равен нулю, если это то, что меня портит, я все равно был бы признателен за чистые ответы, чтобы разобраться в моем мозгу.
1 ответ
Сколько тем я запускаю? Вы запускаете 1 поток на блок, следовательно, всего 16, поскольку параметр Z не используется. Для лучшей производительности я бы рекомендовал также использовать потоки (не менее 128 и не более 32).
Как вы относитесь к "индексации" моего примера задачи в 3 измерениях (начиная с потоков 4x4x4 и получая переменные для flat3DArray[x * sizeY * sizeZ + y * sizeZ + z])? Второй параметр gpu.Launch
Метод для потоков. x
, y
а также z
следовательно, может быть threadIdx.x
, threadIdx.y
а также threadIdx.z
соответственно. Но вы также можете использовать много блоков, таким образом, threadIdx.x + blockDim.x * blockIdx.x
может быть хорошим пиком.
Ссылка, которую вы предоставили здесь, объясняет, почему ваше измерение Z не имеет значения. CUDAfy.Net предоставляет функцию запуска, которая дополнительно вызывает вызов API CUDA/C времени выполнения cuda. При передаче параметров из точечной сети в собственное окружение кажется, что CUDAfy.Net просто игнорирует аргумент Z, оставляя его одному. (это, скорее всего, связано с тем, что ранние версии CUDA не поддерживали параметр Z, отличный от одного). Это не просто объяснение, потому что CUDA теперь поддерживает значение Z, отличное от единицы, но ваш параметр просто игнорируется в реализации CUDAfy.Net.