使用 Cuda 添加指针数组.只有第一个值是正确的



我正在学习 CUDA 并行编程教程的介绍,但我很难获得有效的答案。

教程 -> http://www.nvidia.com/docs/IO/116711/sc11-cuda-c-basics.pdf

我的代码,发布在下面,类似于教程,编译和运行,但只有数组的第一个整数被正确计算。

似乎存在某种数据对齐问题,我只是不明白为什么。此外,我从未见过以这种方式对数组进行数学运算(添加时不带索引并依靠块大小来定义位边界(。
我明白为什么它会起作用,并且在教程中有效,所以我假设我忽略了一些东西。 有人可以指出我正确的方向吗?

#include <iostream>
#include <cstdlib>
#include <ctime>
__global__ void add(int* a, int* b, int* c) {
  *c = *a + *b;
} 
int main(){
  srand(time(NULL));
  int n = 100;
  int size = n * sizeof(int);
  int* inputA;
  int* inputB;
  int* output;
  int* d_inputA;
  int* d_inputB;
  int* d_output;
  inputA = (int*)malloc(size);  
  inputB = (int*)malloc(size);
  output = (int*)malloc(size);
  cudaMalloc((void**)&d_inputA, size);
  cudaMalloc((void**)&d_inputB, size);
  cudaMalloc((void**)&d_output, size);
  for(int i = 0; i < n; i++) {
    inputA[i] = rand() % 100 + 1;
    inputB[i] = rand() % 500 +1;
  }
  cudaMemcpy(d_inputA, inputA, size, cudaMemcpyHostToDevice);
  cudaMemcpy(d_inputB, inputB, size, cudaMemcpyHostToDevice);
  add<<<n,1>>>(d_inputA, d_inputB, d_output);
  cudaMemcpy(output, d_output, size, cudaMemcpyDeviceToHost);
  for(int i = 0; i < n; i++) {
  std::cout << i << ": "
    << inputA[i] << " + " << inputB[i] << " = "
    << output[i] << std::endl;
  }
  free(inputA);
  free(inputB);
  free(output);
  cudaFree(d_inputA);
  cudaFree(d_inputB);
  cudaFree(d_output); 
  return 0;
}

正如你写的那样,内核中的每个线程都将执行等效的

__global__ void add(int* a, int* b, int* c) {
  c[0] = a[0] + b[0];
} 

这应该很明显为什么只有数组的第一个元素具有正确的值。

如果像这样修改内核:

__global__ void add(int* a, int* b, int* c) {
  int idx = threadIdx.x + blockDim.x * blockIdx.x;
  c[idx] = a[idx] + b[idx];
} 

为了使 1D 网格中的每个线程计算一个唯一的索引,您应该发现内核执行了您所期望的操作。该索引是使用内置变量计算的,如果您在使用的介绍性材料中继续阅读(例如,从幻灯片 26 开始(,您会发现有关这些变量的讨论。

你的内核只读取和写入数组的第一个元素,所以这就是你在输出中得到的......

也许您错误地认为不同的线程会获得不同的指针 - 指向数组的连续元素?好吧,这不是 CUDA 的工作方式。每个线程都获得完全相同的参数,它们仅在线程和块标识符上有所不同:

__global__ void add(int* a, int* b, int* c) {
  int i = threadIdx.x + blockIdx.x * blockDim.x;
  c[i] = a[i] + b[i];
}

这应该在一般情况下这样做。在您的情况下,每个块有 1 个线程和 n 个块,因此您需要:

__global__ void add(int* a, int* b, int* c) {
  int i = blockDim.x;
  c[i] = a[i] + b[i];
}

。但尽量避免每个块的线程很少 - 这样你的性能会很糟糕。所以请不要使用上面的代码;相反,创建一个包含大块的网格。

相关内容

最新更新