これらの 3 つの自明で最小限のカーネルについて考えてみましょう。レジスターの使用率は、私が予想するよりもはるかに高くなっています。なんで?
A:
__global__ void Kernel_A()
{
//empty
}
対応するptx:
ptxas info : Compiling entry function '_Z8Kernel_Av' for 'sm_20'
ptxas info : Function properties for _Z8Kernel_Av
0 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info : Used 2 registers, 32 bytes cmem[0]
B:
template<uchar effective_bank_width>
__global__ void Kernel_B()
{
//empty
}
template
__global__ void Kernel_B<1>();
対応するptx:
ptxas info : Compiling entry function '_Z8Kernel_BILh1EEvv' for 'sm_20'
ptxas info : Function properties for _Z8Kernel_BILh1EEvv
0 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info : Used 2 registers, 32 bytes cmem[0]
子:
template<uchar my_val>
__global__ void Kernel_C
(uchar *const device_prt_in,
uchar *const device_prt_out)
{
//empty
}
対応するptx:
ptxas info : Compiling entry function '_Z35 Kernel_CILh1EEvPhS0_' for 'sm_20'
ptxas info : Function properties for _Z35 Kernel_CILh1EEvPhS0_
16 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info : Used 10 registers, 48 bytes cmem[0]
質問:
空のカーネル A と B が 2 つのレジスタを使用するのはなぜですか? CUDA は常に 1 つの暗黙的なレジスタを使用しますが、2 つの追加の明示的なレジスタが使用されるのはなぜですか?
カーネル C はさらにイライラします。10台登録?しかし、ポインタは2つしかありません。これにより、ポインター用に 2*2 = 4 個のレジスターが得られます。さらに 2 つの謎のレジスター (カーネル A とカーネル B によって提案された) がある場合でも、合計で 6 つになります。 まだ10 をはるかに下回っています。
興味がある場合は、ptx
カーネル A のptx
コードを次に示します。カーネル B のコードは、整数値と変数名を法として、まったく同じです。
.visible .entry _Z8Kernel_Av(
)
{
.loc 5 19 1
func_begin0:
.loc 5 19 0
.loc 5 19 1
func_exec_begin0:
.loc 5 22 2
ret;
tmp0:
func_end0:
}
そしてカーネルCの場合...
.weak .entry _Z35Kernel_CILh1EEvPhS0_(
.param .u64 _Z35Kernel_CILh1EEvPhS0__param_0,
.param .u64 _Z35Kernel_CILh1EEvPhS0__param_1
)
{
.local .align 8 .b8 __local_depot2[16];
.reg .b64 %SP;
.reg .b64 %SPL;
.reg .s64 %rd<3>;
.loc 5 38 1
func_begin2:
.loc 5 38 0
.loc 5 38 1
mov.u64 %SPL, __local_depot2;
cvta.local.u64 %SP, %SPL;
ld.param.u64 %rd1, [_Z35Kernel_CILh1EEvPhS0__param_0];
ld.param.u64 %rd2, [_Z35Kernel_CILh1EEvPhS0__param_1];
st.u64 [%SP+0], %rd1;
st.u64 [%SP+8], %rd2;
func_exec_begin2:
.loc 5 836 2
tmp2:
ret;
tmp3:
func_end2:
}
.local
最初にローカルメモリ変数 ( )を宣言するのはなぜですか?- 2 つのポインター (関数の引数として指定) がレジスターに格納されるのはなぜですか? それらのための特別なパラメータスペースはありませんか?
- おそらく、2 つの関数引数ポインターはレジスターに属しています。これが 2 つの
.reg .b64
行を説明しています。しかし、.reg .s64
ラインは何ですか?なぜそこにあるのですか?
それはさらに悪化します:
D:
template<uchar my_val>
__global__ void Kernel_D
(uchar * device_prt_in,
uchar *const device_prt_out)
{
device_prt_in = device_prt_in + blockIdx.x*blockDim.x + threadIdx.x;
}
与える
ptxas info : Used 6 registers, 48 bytes cmem[0]
では、引数 (ポインター) を操作すると、レジスターが 10 から 6 に減少するのでしょうか?