6

これらの 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:
}
  1. .local最初にローカルメモリ変数 ( )を宣言するのはなぜですか?
  2. 2 つのポインター (関数の引数として指定) がレジスターに格納されるのはなぜですか? それらのための特別なパラメータスペースはありませんか?
  3. おそらく、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 に減少するのでしょうか?

4

1 に答える 1

7

最初に指摘しておくべき点は、レジスターについて心配している場合は、PTX コードを見ないでください。何も教えてくれないからです。PTX は静的な単一代入形式を使用し、コンパイラによって出力されるコードには、実行可能なマシン コード エントリ ポイントを作成するために必要な「装飾」が含まれていません。

それはさておき、カーネル A を見てみましょう。

$ nvcc -arch=sm_20 -m64 -cubin -Xptxas=-v null.cu 
ptxas info    : 0 bytes gmem
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]

$ cuobjdump -sass null.cubin 

    code for sm_20
        Function : _Z8Kernel_Av
    /*0000*/     /*0x00005de428004404*/     MOV R1, c [0x1] [0x100];
    /*0008*/     /*0x00001de780000000*/     EXIT;
        .............................

あなたの2つのレジスタがあります。空のカーネルはゼロ命令を生成しません。

それを超えて、私はあなたが示したものを再現することはできません. 投稿されたカーネル C を見ると、次のようになります (CUDA 5 リリース コンパイラ)。

$ nvcc -arch=sm_20 -m64 -cubin -Xptxas=-v null.cu 
ptxas info    : 0 bytes gmem
ptxas info    : Compiling entry function '_Z8Kernel_CILh1EEvPhS0_' for 'sm_20'
ptxas info    : Function properties for _Z8Kernel_CILh1EEvPhS0_
    0 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Used 2 registers, 48 bytes cmem[0]


$ cuobjdump -sass null.cubin 

code for sm_20
    Function : _Z8Kernel_CILh1EEvPhS0_
/*0000*/     /*0x00005de428004404*/     MOV R1, c [0x1] [0x100];
/*0008*/     /*0x00001de780000000*/     EXIT;
    ........................................

すなわち。最初の 2 つのカーネルと同じ 2 レジスタ コード。

カーネル D についても同様です。

$ nvcc -arch=sm_20 -m64 -cubin -Xptxas=-v null.cu 
ptxas info    : 0 bytes gmem
ptxas info    : Compiling entry function '_Z8Kernel_DILh1EEvPhS0_' for 'sm_20'
ptxas info    : Function properties for _Z8Kernel_DILh1EEvPhS0_
    0 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Used 2 registers, 48 bytes cmem[0]

$ cuobjdump -sass null.cubin 
code for sm_20
    Function : _Z8Kernel_DILh1EEvPhS0_
/*0000*/     /*0x00005de428004404*/     MOV R1, c [0x1] [0x100];
/*0008*/     /*0x00001de780000000*/     EXIT;
    ........................................

繰り返しますが、2 つのレジスタです。

記録のために、私が使用している nvcc バージョンは次のとおりです。

$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2012 NVIDIA Corporation
Built on Fri_Sep_28_16:10:16_PDT_2012
Cuda compilation tools, release 5.0, V0.2.1221
于 2013-06-20T16:09:58.490 に答える