如何为CUDA中的每个线程使用寄存器内存?
How to use register memory for each thread in CUDA?
我正在尝试翻转尺寸较大的数组。(例如 4096x8192)
起初,我尝试使用两个数组作为输入和输出,并且有效!
(我会说输入是原始的,输出是翻转数组)
但我认为如果每个线程都可以容纳输入元素,将会更容易且更高效。
那我就只能用一个数组了!
你们能否分享您的知识或介绍任何有助于解决此问题的文档?
谢谢,这是我的代码。
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#define ThreadPB 32 // optimal size
dim3 threadsPerBlock(ThreadPB, ThreadPB);
__global__ void initKernel(int *input, int nx, int ny)
{
int idx_x = blockDim.x * blockIdx.x + threadIdx.x;
int idx_y = blockDim.y * blockIdx.y + threadIdx.y;
int idx = idx_y * nx + idx_x;
if (idx_x < nx && idx_y < ny) {
input[idx] = idx_y;
}
}
__global__ void flipKernel(int *output, int *input, int nx, int ny)
{
int idx_x = blockDim.x * blockIdx.x + threadIdx.x;
int idx_y = blockDim.y * blockIdx.y + threadIdx.y;
int idx = idx_y * nx + idx_x;
// is it possible to use only one array?
if (idx_x < nx && idx_y < ny) {
output[(ny - idx_y - 1) * nx + idx_x] = input[idx_y * nx + idx_x];
}
}
int main()
{
// time check
cudaEvent_t start, stop, start_temp, stop_temp;
cudaEvent_t start_temp2, stop_temp2;
float elapsedTime, elapsedTime_temp, elapsedTime_temp2;
cudaEventCreate(&start); cudaEventCreate(&stop);
cudaEventCreate(&start_temp); cudaEventCreate(&stop_temp);
cudaEventCreate(&start_temp2); cudaEventCreate(&stop_temp2);
const int num_x = 4096;
const int num_y = 8192;
const int arraySize = num_x * num_y;
int *orig, *flip;
orig = (int *)malloc(sizeof(int) * arraySize);
flip = (int *)malloc(sizeof(int) * arraySize);
int *dev_orig = 0;
int *dev_flip = 0;
cudaMalloc((void**)&dev_orig, arraySize * sizeof(int));
cudaMalloc((void**)&dev_flip, arraySize * sizeof(int));
cudaMemcpy(dev_orig, orig, arraySize * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_flip, flip, arraySize * sizeof(int), cudaMemcpyHostToDevice);
dim3 blocksFlip((num_x + threadsPerBlock.x - 1) / threadsPerBlock.x, (num_y + threadsPerBlock.y - 1) / threadsPerBlock.y);
initKernel << <blocksFlip, threadsPerBlock >> > (dev_orig, num_x, num_y);
cudaEventRecord(start, 0);
flipKernel << <blocksFlip, threadsPerBlock >> > (dev_flip, dev_orig, num_x, num_y);
// time check end
cudaEventRecord(stop, 0); cudaEventSynchronize(stop); cudaEventElapsedTime(&elapsedTime, start, stop); printf("flip 1024x2048 처리 시간 = %f ms.\n", elapsedTime);
cudaMemcpy(orig, dev_orig, arraySize * sizeof(int), cudaMemcpyDeviceToHost);
cudaMemcpy(flip, dev_flip, arraySize * sizeof(int), cudaMemcpyDeviceToHost);
// check flip works
printf("FLIP this array { 0, 1, 2, 3, 4 , 5, 6, 7, 8, 9...} \n= { %d, %d, %d, %d, %d, %d, %d, %d, %d, %d...}\n",
flip[num_x * 0], flip[num_x * 1], flip[num_x * 2], flip[num_x * 3], flip[num_x * 4],
flip[num_x * 5], flip[num_x * 6], flip[num_x * 7], flip[num_x * 8], flip[num_x * 9]);
return 0;
}
对于数组中的偶数行,您应该可以这样做:
__global__ void flipKernel(int *input, int nx, int ny)
{
int idx_x = blockDim.x * blockIdx.x + threadIdx.x;
int idx_y = blockDim.y * blockIdx.y + threadIdx.y;
int idx = idx_y * nx + idx_x;
if (idx_x < nx && idx_y < ny/2) {
int output_temp = input[(ny - idx_y - 1) * nx + idx_x];
input[(ny - idx_y - 1) * nx + idx_x] = input[idx_y * nx + idx_x];
input[idx_y * nx + idx_x] = output_temp;
}
}
您只需要在 y 中的线程数减半(y 中的行数减半)的情况下启动该内核。每个线程正在更新矩阵中的两个值。
与其考虑“注册”之类的事情或想象 CUDA 是某种奇怪的语言,如果您具有 C 或 C++ 编程能力,我鼓励您考虑如何解决问题被设计为普通的 C 或 C++ 编程挑战。您的直觉通常在 CUDA 中非常有效。
上面套路的核心就是一个swap。您所说的“寄存器”只是 C 或 C++ 中的一个普通局部变量。在 C++ 中有一个 register
关键字,但它在 CUDA 中基本上没有任何作用,这里也不需要。
您可以处理奇数行,只需保持中间行不变,然后交换其余行即可。这只需要对索引计算稍作更改。
我正在尝试翻转尺寸较大的数组。(例如 4096x8192)
起初,我尝试使用两个数组作为输入和输出,并且有效!
(我会说输入是原始的,输出是翻转数组)
但我认为如果每个线程都可以容纳输入元素,将会更容易且更高效。 那我就只能用一个数组了!
你们能否分享您的知识或介绍任何有助于解决此问题的文档?
谢谢,这是我的代码。
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#define ThreadPB 32 // optimal size
dim3 threadsPerBlock(ThreadPB, ThreadPB);
__global__ void initKernel(int *input, int nx, int ny)
{
int idx_x = blockDim.x * blockIdx.x + threadIdx.x;
int idx_y = blockDim.y * blockIdx.y + threadIdx.y;
int idx = idx_y * nx + idx_x;
if (idx_x < nx && idx_y < ny) {
input[idx] = idx_y;
}
}
__global__ void flipKernel(int *output, int *input, int nx, int ny)
{
int idx_x = blockDim.x * blockIdx.x + threadIdx.x;
int idx_y = blockDim.y * blockIdx.y + threadIdx.y;
int idx = idx_y * nx + idx_x;
// is it possible to use only one array?
if (idx_x < nx && idx_y < ny) {
output[(ny - idx_y - 1) * nx + idx_x] = input[idx_y * nx + idx_x];
}
}
int main()
{
// time check
cudaEvent_t start, stop, start_temp, stop_temp;
cudaEvent_t start_temp2, stop_temp2;
float elapsedTime, elapsedTime_temp, elapsedTime_temp2;
cudaEventCreate(&start); cudaEventCreate(&stop);
cudaEventCreate(&start_temp); cudaEventCreate(&stop_temp);
cudaEventCreate(&start_temp2); cudaEventCreate(&stop_temp2);
const int num_x = 4096;
const int num_y = 8192;
const int arraySize = num_x * num_y;
int *orig, *flip;
orig = (int *)malloc(sizeof(int) * arraySize);
flip = (int *)malloc(sizeof(int) * arraySize);
int *dev_orig = 0;
int *dev_flip = 0;
cudaMalloc((void**)&dev_orig, arraySize * sizeof(int));
cudaMalloc((void**)&dev_flip, arraySize * sizeof(int));
cudaMemcpy(dev_orig, orig, arraySize * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_flip, flip, arraySize * sizeof(int), cudaMemcpyHostToDevice);
dim3 blocksFlip((num_x + threadsPerBlock.x - 1) / threadsPerBlock.x, (num_y + threadsPerBlock.y - 1) / threadsPerBlock.y);
initKernel << <blocksFlip, threadsPerBlock >> > (dev_orig, num_x, num_y);
cudaEventRecord(start, 0);
flipKernel << <blocksFlip, threadsPerBlock >> > (dev_flip, dev_orig, num_x, num_y);
// time check end
cudaEventRecord(stop, 0); cudaEventSynchronize(stop); cudaEventElapsedTime(&elapsedTime, start, stop); printf("flip 1024x2048 처리 시간 = %f ms.\n", elapsedTime);
cudaMemcpy(orig, dev_orig, arraySize * sizeof(int), cudaMemcpyDeviceToHost);
cudaMemcpy(flip, dev_flip, arraySize * sizeof(int), cudaMemcpyDeviceToHost);
// check flip works
printf("FLIP this array { 0, 1, 2, 3, 4 , 5, 6, 7, 8, 9...} \n= { %d, %d, %d, %d, %d, %d, %d, %d, %d, %d...}\n",
flip[num_x * 0], flip[num_x * 1], flip[num_x * 2], flip[num_x * 3], flip[num_x * 4],
flip[num_x * 5], flip[num_x * 6], flip[num_x * 7], flip[num_x * 8], flip[num_x * 9]);
return 0;
}
对于数组中的偶数行,您应该可以这样做:
__global__ void flipKernel(int *input, int nx, int ny)
{
int idx_x = blockDim.x * blockIdx.x + threadIdx.x;
int idx_y = blockDim.y * blockIdx.y + threadIdx.y;
int idx = idx_y * nx + idx_x;
if (idx_x < nx && idx_y < ny/2) {
int output_temp = input[(ny - idx_y - 1) * nx + idx_x];
input[(ny - idx_y - 1) * nx + idx_x] = input[idx_y * nx + idx_x];
input[idx_y * nx + idx_x] = output_temp;
}
}
您只需要在 y 中的线程数减半(y 中的行数减半)的情况下启动该内核。每个线程正在更新矩阵中的两个值。
与其考虑“注册”之类的事情或想象 CUDA 是某种奇怪的语言,如果您具有 C 或 C++ 编程能力,我鼓励您考虑如何解决问题被设计为普通的 C 或 C++ 编程挑战。您的直觉通常在 CUDA 中非常有效。
上面套路的核心就是一个swap。您所说的“寄存器”只是 C 或 C++ 中的一个普通局部变量。在 C++ 中有一个 register
关键字,但它在 CUDA 中基本上没有任何作用,这里也不需要。
您可以处理奇数行,只需保持中间行不变,然后交换其余行即可。这只需要对索引计算稍作更改。