美文网首页
CUDA笔记(一)线程与数据量的关系

CUDA笔记(一)线程与数据量的关系

作者: Yao_0 | 来源:发表于2020-07-22 16:11 被阅读0次

数据集比网格大

或出于选择,为了要创建具有超高性能的执行配置,或出于需要,一个网格中的线程数量可能会小于数据集的大小。请思考一下包含 1000 个元素的数组和包含 250 个线程的网格(此处使用极小的规模以便于说明)。此网格中的每个线程将需使用 4 次。如要实现此操作,一种常用方法便是在核函数中使用跨网格循环

在跨网格循环中,每个线程将在网格内使用 threadIdx + blockIdx*blockDim 计算自身唯一的索引,并对数组内该索引的元素执行相应运算,然后将网格中的线程数添加到索引并重复此操作,直至超出数组范围。例如,对于包含 500 个元素的数组和包含 250 个线程的网格,网格中索引为 20 的线程将执行如下操作:

  • 对包含 500 个元素的数组的元素 20 执行相应运算
  • 将其索引增加 250,使网格的大小达到 270
  • 对包含 500 个元素的数组的元素 270 执行相应运算
  • 将其索引增加 250,使网格的大小达到 520
  • 由于 520 现已超出数组范围,因此线程将停止工作

CUDA 提供一个可给出网格中线程块数的特殊变量:gridDim.x。然后计算网格中的总线程数,即网格中的线程块数乘以每个线程块中的线程数:gridDim.x * blockDim.x。带着这样的想法来看看以下核函数中网格跨度循环的详细示例:

__global void kernel(int *a, int N)
{
  int indexWithinTheGrid = threadIdx.x + blockIdx.x * blockDim.x;   
//blockIdx.x  (0,1,3) blockDim.x(250)
  int gridStride = gridDim.x * blockDim.x;

  for (int i = indexWithinTheGrid; i < N; i += gridStride)
  {
    // do work on a[i];
  }
}
/*1000个数据使用 32×255个线程跑两次*/
void doubleElements(int *a, int N)
{

  /*
   * Use a grid-stride loop so each thread does work
   * on more than one element in the array.
   */

  //         0-31          255            0-255
  int idx = blockIdx.x * blockDim.x + threadIdx.x; 
  //              32           255 
  int stride = gridDim.x * blockDim.x; 

  for (int i = idx; i < N; i += stride)
  {
    a[i] *= 2;
  }
}

bool checkElementsAreDoubled(int *a, int N)
{
  int i;
  for (i = 0; i < N; ++i)
  {
    if (a[i] != i*2) return false;
  }
  return true;
}

int main()
{
  int N = 10000;
  int *a;

  size_t size = N * sizeof(int);
  cudaMallocManaged(&a, size);

  init(a, N);

  size_t threads_per_block = 256;
  size_t number_of_blocks = 32;

  doubleElements<<<number_of_blocks, threads_per_block>>>(a, N);
  cudaDeviceSynchronize();

  bool areDoubled = checkElementsAreDoubled(a, N);
  printf("All elements were doubled? %s\n", areDoubled ? "TRUE" : "FALSE");

  cudaFree(a);
}

不同线程时间对比

__global__
void addVectorsInto(float *result, float *a, float *b, int N)
{
  int index = threadIdx.x + blockIdx.x * blockDim.x;
  int stride = blockDim.x * gridDim.x;

  for(int i = index; i < N; i += stride)
  {
    result[i] = a[i] + b[i];
  }
}

  addVectorsInto<<<numberOfBlocks, threadsPerBlock>>>(c, a, b, N);

n 2<<24
threadsPerBlock numberOfBlocks nanoseconds
256 1 136793984
256 16 117175743
256 32 117047986
128 1 148998083
128 16 148271881
128 32 126887351

相关文章

网友评论

      本文标题:CUDA笔记(一)线程与数据量的关系

      本文链接:https://www.haomeiwen.com/subject/nbajnctx.html