Considérons ces 3 noyaux minimes et minimaux. Leur utilisation du registre est beaucoup plus élevé que ce que j'attends. Pourquoi?cuda - exemple minimal, utilisation élevée du registre
A:
__global__ void Kernel_A()
{
//empty
}
PTX correspondant:
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 correspondant:
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]
C:
template<uchar my_val>
__global__ void Kernel_C
(uchar *const device_prt_in,
uchar *const device_prt_out)
{
//empty
}
PTX correspondant:
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]
Question:
Pourquoi est-ce vide Les noyaux A et B utilisent 2 registres? CUDA utilise toujours un registre implicite, mais pourquoi 2 registres explicites sont-ils utilisés?
Le noyau C est encore plus frustrant. 10 registres? Mais il n'y a que 2 pointeurs. Cela donne 2 * 2 = 4 registres pour les pointeurs. Même s'il y a en plus 2 registres mystérieux (suggérés par Kernel A et Kernel B), cela donnerait 6 au total. Toujours beaucoup moins que 10!
Si vous êtes intéressé, voici le code ptx
pour le noyau A. Le code ptx
pour le noyau B est exactement la même, modulo les valeurs entières et les noms de variables.
.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:
}
Et pour le noyau 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:
}
- Pourquoi ne première Déclarez une variable mémoire locale (
.local
)? - Pourquoi les deux pointeurs (donnés comme arguments de fonction) sont-ils stockés dans des registres? N'y a-t-il pas un espace param spécifique pour eux?
- Les deux pointeurs d'argument de fonction appartiennent peut-être aux registres, ce qui explique les deux lignes
.reg .b64
. Mais quelle est la ligne.reg .s64
? Pourquoi est-ce là?
Il y a pire encore:
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;
}
donne
ptxas info : Used 6 registers, 48 bytes cmem[0]
manipulation L'argument (un pointeur) diminue de 10 à 6 registres?
J'ai enlevé la mise au point « -G » et « -g » des drapeaux du compilateur ... et puis je me suis le même résultat que vous pour le noyau C. – cmo
Je ne peux pas le croire. Est-ce vraiment ça? – cmo
Il semblerait que oui. Encore une fois, PTX ne vous dira pas ce que vous voulez savoir - la prise en charge du débogueur permet à l'assembleur d'émettre plus de code d'installation. C'est probablement d'où viennent les registres supplémentaires. – talonmies