Có, tương đương với memcpy
hoạt động bên trong hạt nhân cuda. Nó được gọi là memcpy
. Như một ví dụ:
__global__ void kernel(int **in, int **out, int len, int N)
{
int idx = threadIdx.x + blockIdx.x*blockDim.x;
for(; idx<N; idx+=gridDim.x*blockDim.x)
memcpy(out[idx], in[idx], sizeof(int)*len);
}
mà biên dịch mà không có lỗi như thế này:
$ nvcc -Xptxas="-v" -arch=sm_20 -c memcpy.cu
ptxas info : Compiling entry function '_Z6kernelPPiS0_ii' for 'sm_20'
ptxas info : Function properties for _Z6kernelPPiS0_ii
0 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info : Used 11 registers, 48 bytes cmem[0]
và phát ra PTX:
.version 3.0
.target sm_20
.address_size 32
.file 1 "/tmp/tmpxft_00000407_00000000-9_memcpy.cpp3.i"
.file 2 "memcpy.cu"
.file 3 "/usr/local/cuda/nvvm/ci_include.h"
.entry _Z6kernelPPiS0_ii(
.param .u32 _Z6kernelPPiS0_ii_param_0,
.param .u32 _Z6kernelPPiS0_ii_param_1,
.param .u32 _Z6kernelPPiS0_ii_param_2,
.param .u32 _Z6kernelPPiS0_ii_param_3
)
{
.reg .pred %p<4>;
.reg .s32 %r<32>;
.reg .s16 %rc<2>;
ld.param.u32 %r15, [_Z6kernelPPiS0_ii_param_0];
ld.param.u32 %r16, [_Z6kernelPPiS0_ii_param_1];
ld.param.u32 %r2, [_Z6kernelPPiS0_ii_param_3];
cvta.to.global.u32 %r3, %r15;
cvta.to.global.u32 %r4, %r16;
.loc 2 4 1
mov.u32 %r5, %ntid.x;
mov.u32 %r17, %ctaid.x;
mov.u32 %r18, %tid.x;
mad.lo.s32 %r30, %r5, %r17, %r18;
.loc 2 6 1
setp.ge.s32 %p1, %r30, %r2;
@%p1 bra BB0_5;
ld.param.u32 %r26, [_Z6kernelPPiS0_ii_param_2];
shl.b32 %r7, %r26, 2;
.loc 2 6 54
mov.u32 %r19, %nctaid.x;
.loc 2 4 1
mov.u32 %r29, %ntid.x;
.loc 2 6 54
mul.lo.s32 %r8, %r29, %r19;
BB0_2:
.loc 2 7 1
shl.b32 %r21, %r30, 2;
add.s32 %r22, %r4, %r21;
ld.global.u32 %r11, [%r22];
add.s32 %r23, %r3, %r21;
ld.global.u32 %r10, [%r23];
mov.u32 %r31, 0;
BB0_3:
add.s32 %r24, %r10, %r31;
ld.u8 %rc1, [%r24];
add.s32 %r25, %r11, %r31;
st.u8 [%r25], %rc1;
add.s32 %r31, %r31, 1;
setp.lt.u32 %p2, %r31, %r7;
@%p2 bra BB0_3;
.loc 2 6 54
add.s32 %r30, %r8, %r30;
ld.param.u32 %r27, [_Z6kernelPPiS0_ii_param_3];
.loc 2 6 1
setp.lt.s32 %p3, %r30, %r27;
@%p3 bra BB0_2;
BB0_5:
.loc 2 9 2
ret;
}
Khối mã tại BB0_3
là một byte có kích thước memcpy
vòng lặp phát ra automagically bởi trình biên dịch. Nó có thể không phải là một ý tưởng tuyệt vời từ một quan điểm hiệu suất để sử dụng nó, nhưng nó được hỗ trợ đầy đủ (và đã được một thời gian dài trên tất cả các kiến trúc).
Sửa bốn năm sau để thêm rằng kể từ khi API runtime bên thiết bị đã được phát hành như là một phần của chu kỳ phát hành CUDA 6, nó cũng có thể trực tiếp gọi một cái gì đó giống như
cudaMemcpy(void *to, void *from, size, cudaMemcpyDeviceToDevice)
trong mã thiết bị cho tất cả các kiến trúc hỗ trợ nó (Khả năng tính toán 3.5 và phần cứng mới hơn).
Bạn đã viết "memcpy() không hoạt động bên trong hạt nhân", nhưng điều đó không đúng, hãy xem câu trả lời của tôi ... – talonmies
Cũng lưu ý rằng với CUDA 6.0, 'cudaMemcpy' được hỗ trợ trong mã thiết bị cho thiết bị bản sao trên thiết bị. – talonmies
@talonmies là nó cũng có thể sử dụng cudaMemcpy cho các bản sao từ thiết bị đến máy chủ không? – starrr