Cuda 点积中寄存器使用的优化

Cuda 点积中寄存器使用的优化,cuda,ptx,Cuda,Ptx,我正在开发一个核函数,它包含一些向量运算,比如标量和向量积。内核使用大量寄存器,因此占用率非常低。我正试图减少已用寄存器的数量,以提高占用率 例如,考虑以下执行两个浮动3之间的标量积的\uuu设备\uuuuuu函数: __device__ float dot(float3 in1, float3 in2) { return in1.x * in2.x + in1.y * in2.y + in1.z * in2.z; } 如果我使用生成.ptx文件 nvcc -ptx -gencode arch

我正在开发一个核函数,它包含一些向量运算,比如标量和向量积。内核使用大量寄存器,因此占用率非常低。我正试图减少已用寄存器的数量,以提高占用率

例如,考虑以下执行两个浮动3之间的标量积的
\uuu设备\uuuuuu
函数:

__device__ float dot(float3 in1, float3 in2) { return in1.x * in2.x + in1.y * in2.y + in1.z * in2.z; }
如果我使用生成
.ptx
文件

nvcc -ptx -gencode arch=compute_52,code=sm_52 -rdc=true simpleDot2.cu
(文件
simpleDot2.cu
仅包含
\uuuu设备\uuuu
函数的定义),我基本上获得

    // .globl   _Z3dot6float3S_
.visible .func  (.param .b32 func_retval0) _Z3dot6float3S_(
    .param .align 4 .b8 _Z3dot6float3S__param_0[12],
    .param .align 4 .b8 _Z3dot6float3S__param_1[12]
)
{
    .reg .f32   %f<10>;


    ld.param.f32    %f1, [_Z3dot6float3S__param_0+8];
    ld.param.f32    %f2, [_Z3dot6float3S__param_0];
    ld.param.f32    %f3, [_Z3dot6float3S__param_0+4];
    ld.param.f32    %f4, [_Z3dot6float3S__param_1+8];
    ld.param.f32    %f5, [_Z3dot6float3S__param_1];
    ld.param.f32    %f6, [_Z3dot6float3S__param_1+4];
    mul.f32     %f7, %f3, %f6;
    fma.rn.f32  %f8, %f2, %f5, %f7;
    fma.rn.f32  %f9, %f1, %f4, %f8;
    st.param.f32    [func_retval0+0], %f9;
    ret;
}
/.globl\u Z3dot6float3S_
.visible.func(.param.b32 func_retval0)_Z3dot6float3S_(
.param.align 4.b8_Z3dot6float3S__param_0[12],
.param.align 4.b8_Z3dot6float3S__param_1[12]
)
{
.reg.f32%f;
ld.param.f32%f1,[\u Z3dot6float3S\u param\u 0+8];
ld.param.f32%f2,[uz3dot6float3s\uuuu param\u0];
ld.param.f32%f3,[\u Z3dot6float3S\u param\u 0+4];
ld.param.f32%f4,[\uz3dot6float3s\uuuu param\u1+8];
ld.param.f32%f5,[uz3dot6float3s\uuuuu param\u1];
ld.param.f32%f6,[\u Z3dot6float3S\u param\u 1+4];
多个f32%f7、%f3、%f6;
fma.rn.f32%f8、%f2、%f5、%f7;
fma.rn.f32%f9%f1%f4%f8;
标准参数f32[func_retval0+0],%f9;
ret;
}
.ptx
代码中,似乎使用了许多
9
寄存器,这些寄存器可能可以降低。我知道
.ptx
代码不是GPU执行的最终代码

问题

是否有机会重新安排
.ptx
代码中的寄存器使用,例如回收寄存器
f1
-
f6
,以减少占用寄存器的总数


非常感谢您的帮助。

TL;DR到一级,否

PTX
是一种虚拟ISA和编译器中间表示形式。PTX代码中使用的寄存器是虚拟寄存器,与GPU的物理寄存器没有固定的关系。CUDA工具链生成的PTX代码遵循(静态单一赋值)约定。这意味着每个虚拟寄存器只写入一次。不同的表述:当一条指令产生一个结果时,它被分配到一个新的寄存器。这意味着较长的内核可能会使用数千个寄存器

在CUDA工具链中,PTX代码由
ptxas
组件编译为机器代码(SASS)。因此,尽管名称不同,这不是一个汇编程序,而是一个优化编译器,可以执行循环展开、CSE(公共子表达式消除)等操作。最重要的是,
ptxas
负责寄存器分配和指令调度,以及特定GPU体系结构的所有优化

因此,对寄存器使用问题的任何检查都需要关注机器代码,可以使用
cuobjdump--dump sass
提取机器代码。此外,程序员对使用的寄存器数量的影响非常有限,因为
ptxas
在确定寄存器分配时使用了大量的启发式方法,特别是在寄存器使用与性能之间进行权衡:提前调度负载往往会通过延长寿命范围来增加寄存器压力,在CSE期间创建临时变量或创建回路强度降低的感应变量也是如此

现代版本的CUDA,目标计算能力为3和更高,通常在确定这些权衡时做出很好的选择,程序员很少需要考虑登记压力。目前尚不清楚是什么促使提问者提出这方面的问题

CUDA中用于控制最大寄存器使用量的有文档记录的机制是
-maxrregcount
nvcc的命令行标志,它适用于整个编译单元,以及允许在每个内核基础上进行控制的
\uuuuuuu启动边界\uuuuuu
属性。有关详细信息,请参阅CUDA文档。除此之外,还可以通过选择
-Xptxas-O{1 | 2 | 3}
(默认值为
-O3
)的
pxtas
优化级别,或者通过重新安排源代码,或者通过使用易于简化生成代码的编译器标志,例如
-use\u fast\u math
,来影响寄存器的使用


当然,这种间接方法可能会产生许多其他通常不可预测的效果,并且所获得的任何理想结果都将是“脆弱的”,例如,通过更换新版本的工具链,很容易被破坏。

TL;DR到一级,否

PTX
是一种虚拟ISA和编译器中间表示形式。PTX代码中使用的寄存器是虚拟寄存器,与GPU的物理寄存器没有固定的关系。CUDA工具链生成的PTX代码遵循(静态单一赋值)约定。这意味着每个虚拟寄存器只写入一次。不同的表述:当一条指令产生一个结果时,它被分配到一个新的寄存器。这意味着较长的内核可能会使用数千个寄存器

在CUDA工具链中,PTX代码由
ptxas
组件编译为机器代码(SASS)。因此,尽管名称不同,这不是一个汇编程序,而是一个优化编译器,可以执行循环展开、CSE(公共子表达式消除)等操作。最重要的是,
ptxas
负责寄存器分配和指令调度,以及特定GPU体系结构的所有优化

因此,对寄存器使用问题的任何检查都需要关注机器代码,可以使用
cuobjdump--dump sass
提取机器代码。此外,程序员对使用的寄存器数量的影响非常有限,因为
ptxas
在确定寄存器分配时使用了许多启发式方法,特别是