繁体   English   中英

CUDA内存(类型),仅用于内核调用(计算1.1或1.2)期间的设备计算

[英]CUDA memory (type) for device only calculation during kernel calls (compute 1.1 or 1.2)

我目前正在学习CUDA,我的算法必须根据一些输入数据进行一些繁重的计算。 这些计算是在一个循环中进行的,循环最多旋转1024个回合。 只要我每个内核具有少量线程(<100´000),一切都可以正常工作,但是如果我想利用更多线程,则内核将被Windows中断,因为它需要很长时间才能完成。

我的解决方案是将繁重的计算分成几个内核调用:

  1. 内核准备输入数据并计算前x轮(展开循环)。 每个输入只会调用一次。
  2. 工作内核,执行下一个x轮(展开循环)。 计算所有所需回合所需的次数将被调用。

在每个内核调用之间(一个调用,很多工作 ),我必须保存16个+长度字节的数据,这些数据将在下一个调用中使用(length是输入的长度,每个调用是固定的)。 内核将首先写入这些字节, 工作内核将读取它们,运行下一个计算,并以新结果写入原始数据。 我只需要设备上的那些数据,就不需要主机访问。 我必须为此使用哪种内存? 至少它必须是全局内存,因为它是内核调用期间唯一持久保存的可写内存,不是吗? 但是那又怎样呢? 您能否就如何正确使用内存(以及最佳性能)提供建议?

在“伪代码”中,它可能看起来像这样:

prepare memory to hold threads * (16 + length) bytes

for length = 1 to x step 1
  call mainKernel
  rounds = 1024 - rounds_done_in_main
  for rounds to 0 step rounds_done_in_work
    call workKernel
  end for
end for

cleanup memory

--------

template <unsigned char length> __global__ mainKernel() {
  unsigned char input[length];
  unsigned char output[16];
  const int tid = ...;

  devPrepareInput<length>(input);

  calc round 1: doSomething<length>(output, input)
  calc round 2: doSomething<length>(output, output + input) // '+' == append

  write data to memory based on tid // data == output + input
}

template <unsigned char length, remaining rounds> __global__ workKernel() {
  unsigned char *input;
  unsigned char *output;
  const int tid = ...;

  read data from memory based on tid
  ouput = data
  input = data+16

  if rounds >= 1
    calc round x  : doSomething<length>(output, output + input)
  if rounds >= 2
    calc round x+1: doSomething<length>(output, output + input) // '+' == append

  if rounds == x // x is the number of rounds in the last work call
    do final steps on output
  else
    write ouput + input to memory based on tid (for next call)
}

是的,您可以使用设备内存来执行此操作。 __device__声明的变量提供了缓冲区的静态声明,内核可以直接使用该缓冲区,而无需任何cudaMemcpy操作,也不需要将该指针显式传递给内核。 由于它具有应用程序生命周期,因此其中的数据将从一个内核调用一直保留到下一个内核调用。

#define NUM_THREADS 1024
#define DATA_PER_THREAD 16
__device__ int temp_data[NUM_THREADS*DATA_PER_THREAD];

__global__ my_kernel1(...){
  int my_data[DATA_PER_THREAD] = {0};
  int idx = threadIdx.x + blockDim.x * blockIdx.x;
  // perform calculations

  // write out temp data
  for (int i = 0; i < DATA_PER_THREAD; i++) temp_data[i + (idx * DATA_PER_THREAD)] = my_data[i];
  }

__global__ my_kernel2(...){
  int my_data[DATA_PER_THREAD];
  // read in temp data
  for (int i = 0; i < DATA_PER_THREAD; i++) my_data[i] = temp_data[i + (idx * DATA_PER_THREAD)];
  // perform calculations

  }

您可以通过多种方式根据内核中的使用模式对此进行优化。 my_data的数据传输my_data不是必需的。 显然,您的内核代码可以使用适当的索引直接访问temp_data代替my_data

如果您确实决定加载/存储它,则可以对数据进行交织,以便在for循环读取和写入数据期间进行合并访问。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM