我正在编写一个包含cuda内核的程序。我发现如果你使用#define OPERATOR *
一个线程将使用11个寄存器,但我将使用#define OPERATOR /
(除法运算符)一个线程将使用52个寄存器!怎么了?我必须
减少寄存器号(我想设置maxregcount)!当我在cuda内核中使用devision运算符时,如何减少寄存器的数量?
#include <stdio.h>
#include <stdlib.h>
#define GRID_SIZE 1
#define BLOCK_SIZE 1
#define OPERATOR /
__global__ void kernel(double* array){
for (int curEl=0;curEl<BLOCK_SIZE;++curEl){
array[curEl]=array[curEl] OPERATOR 10;
}
}
int main(void) {
double *devPtr=NULL,*data=(double*)malloc(sizeof(double)*BLOCK_SIZE);
cudaFuncAttributes cudaFuncAttr;
cudaFuncGetAttributes(&cudaFuncAttr,kernel);
for (int curElem=0;curElem<BLOCK_SIZE;++curElem){
data[curElem]=curElem;
}
cudaMalloc(&devPtr,sizeof(double)*BLOCK_SIZE);
cudaMemcpy(devPtr,data,sizeof(double)*BLOCK_SIZE,cudaMemcpyHostToDevice);
kernel<<<1,BLOCK_SIZE>>>(devPtr);
printf("1 thread needs %d regs\n",cudaFuncAttr.numRegs);
return 0;
}
答案 0 :(得分:5)
在内核计算中从双精度乘法切换到双精度除法时寄存器使用的增加是由于双精度乘法是内置硬件指令,而双精度除法是大小称为软件子程序(即,各种函数调用)。通过使用cuobjdump --dump-sass
检查生成的机器代码(SASS)可以轻松验证这一点。
双精度除法(实际上所有除法,包括单精度除法和整数除法)由内联代码或被调用的子程序模拟的原因是由于GPU硬件没有直接支持除法操作,以保持各个计算核心(&#34; CUDA核心&#34;)尽可能简单和尽可能小,这最终会导致给定大小芯片的更高峰值性能。根据GFLOPS /瓦特指标,它还可能提高核心的效率。
对于版本构建,引入双精度除法引起的寄存器使用的典型增加是大约26个寄存器。需要这些附加寄存器来在除法计算中存储中间变量,其中每个双精度临时变量需要两个32位寄存器。
正如Marco13在上面的评论中指出的那样,可以通过乘以倒数来手动替换除法。但是,这在大多数情况下会导致轻微的数值差异,这就是CUDA编译器不会自动应用此转换的原因。
一般来说,注册使用可以通过-maxrregcount
nvcc compiler flag使用编译单元粒度控制,也可以使用__launch_bounds__
function attribute按功能粒度控制。但是,强制较低的寄存器使用低于编译器确定的低于几个寄存器的频率会导致寄存器溢出生成的代码,这通常会对内核性能产生负面影响。