【发布时间】:2018-10-18 00:37:09
【问题描述】:
我正在使用 CUDA 计算 out = C(b(A(in))),其中函数 A 和 C 是卷积,b 是逐元素函数。一个玩具例子是:
#define N 1000
__device__ float b(float d_in){return min(d_in + 10.0f, 100.0f);}
__global__ void bA(float *d_in, float *d_out){
const int x = threadIdx.x + blockIdx.x * blockDim.x;
if (x >= N) return;
// replicate boundary
int x_left = max(x-1, 0); int x_right = min(x+1, N-1);
d_out[x] = b( d_in[x_left] + d_in[x] + d_in[x_right] );
}
__global__ void C(float *d_in, float *d_out){
const int x = threadIdx.x + blockIdx.x * blockDim.x;
if (x >= N) return;
// replicate boundary
int x_left = max(x-1, 0); int x_right = min(x+1, N-1);
d_out[x] = d_in[x_left] + d_in[x] + d_in[x_right];
}
void myfunc(float *d_data, float *d_temp){
dim3 threads(256);
dim3 blocks( (N + threads.x - 1) / threads.x ); // divide up
// kernels that I would like to merge into one:
bA<<<blocks, threads>>>(d_data, d_temp);
C <<<blocks, threads>>>(d_temp, d_data);
}
这样的计算需要一个额外的变量d_temp,这是我不想要的。所以我想将这些内核合并为一个,即一个用于计算C(b(A(in)))的内核。
一个难点是,我怎样才能保存b(A(in))的临时结果,然后执行卷积函数C()?我曾尝试使用共享内存,但不知道如何将临时结果b(A(in)) 加载到共享内存。例如:
#define BLOCK_SIZE 32
__global__ void CbA(float *d_in, float *d_out){
const int x = threadIdx.x + blockIdx.x * blockDim.x;
if (x >= N) return;
// replicate boundary
int x_left = max(x-1, 0); int x_right = min(x+1, N-1);
// temp result for b(A(in))
float temp = b( d_in[x_left] + d_in[x] + d_in[x_right] );
// shared memory for convolution (stencil size of 3)
__shared__ float shmem[BLOCK_SIZE+2];
// load center part to shared memory
shmem[threadIdx.x+1] = temp;
// but how to load boundary parts from temp to shmem?
// ...
__syncthreads();
// perform function C()
// ...
}
非常感谢任何建议或提示。
【问题讨论】:
-
使用一个内核有什么好处?合并后的内核更复杂,分支更多,在大多数情况下,与 2 个不同的内核调用相比,您会损失性能。
-
@SRhm 此处显示的示例是我实际工作内核的简化,它位于 for 循环中。对于每次运行,需要多次读取和重新加载的多个临时数组(例如这里的
d_temp),所以我想做一些潜在的改进。是的,你是对的,合并后的内核可能会变得更糟,但我仍然想尝试一下,看看我是否可以进一步改进我的内核。
标签: cuda