Hãy xem xét 3 hạt nhỏ, tầm thường này. Việc sử dụng đăng ký của họ là nhiều hơn cao hơn tôi mong đợi. Tại sao?cuda - ví dụ tối thiểu, cách sử dụng đăng ký cao
A:
__global__ void Kernel_A()
{
//empty
}
PTX tương ứng:
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 tương ứng:
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 tương ứng:
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]
Câu hỏi:
Tại sao trống hạt nhân A và B sử dụng 2 thanh ghi? CUDA luôn sử dụng một thanh ghi tiềm ẩn, nhưng tại sao lại sử dụng thêm 2 thanh ghi rõ ràng?
Hạt nhân C thậm chí còn bực bội hơn. 10 thanh ghi? Nhưng chỉ có 2 con trỏ. Điều này cho phép 2 * 2 = 4 thanh ghi cho con trỏ. Ngay cả khi có thêm 2 thanh ghi bí ẩn (được gợi ý bởi Kernel A và Kernel B), điều này sẽ cho tổng cộng 6. Vẫn còn ít hơn 10!
Trong trường hợp bạn quan tâm, đây là mã ptx
cho Kernel A. Mã ptx
cho Kernel B là giống hệt nhau, modulo các giá trị số nguyên và tên biến.
.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:
}
Và đối với Kernel 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:
}
- Tại sao nó đầu tiên khai báo một biến cục bộ nhớ (
.local
)? - Tại sao hai con trỏ (được cho là đối số hàm) được lưu trữ trong sổ đăng ký? Không có một không gian đặc biệt cho họ?
- Có lẽ hai con trỏ đối số hàm thuộc về thanh ghi - giải thích hai dòng
.reg .b64
. Nhưng dòng.reg .s64
là gì? Tại sao nó lại ở đó?
Nó trở nên tệ hơn vẫn:
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;
}
cho
ptxas info : Used 6 registers, 48 bytes cmem[0]
Vì vậy, thao tác lập luận (một con trỏ) giảm 10-6 sổ đăng ký?
tôi loại bỏ các gỡ lỗi "G" và "-g" từ cờ biên dịch ... và sau đó tôi nhận được kết quả tương tự như bạn cho Kernel C. – cmo
Tôi không thể tin được. Đó có thực sự là nó? – cmo
Nó sẽ xuất hiện như vậy. Một lần nữa, PTX sẽ không cho bạn biết những gì bạn muốn biết - kết quả hỗ trợ trình sửa lỗi trong trình tạo mã phát ra nhiều mã thiết lập hơn. Đó có lẽ là nơi đăng ký bổ sung đến từ. – talonmies