이것은 CUDA 5.0에서 소개 된 별도의 컴파일 기능을 사용하여 수행 할 수 있습니다. 필자는 "전체"프로그램 컴파일 모드 나 툴킷 버전에서 CUDA 5.0 이전 또는 3.1 이전의 PTX 개정판에서이를 수행 할 수있는 방법이 있다고 생각하지 않습니다.
아마도 작업 예제로이를 수행하는 방법을 설명하는 것이 가장 쉽습니다. 이제 귀하의 예와 유사 포인터를 증가하기위한 간단한 PTX 기능을 시작하자 :
.version 3.1
.target sm_30
.address_size 32
.visible .func inc_ptr(.param .b32 ptr, .param .b32 inc)
{
.reg .s32 %r<6>;
ld.param.u32 %r1, [ptr];
ld.param.u32 %r2, [inc];
ld.u32 %r3, [%r1];
ld.u32 %r4, [%r3];
add.s32 %r5, %r4, %r2;
st.u32 [%r3], %r5;
ret;
}
이 ptxas
를 사용하여 재배치 장치 개체로 컴파일 한 후 fatbinary 컨테이너 파일에 포함 할 수 있습니다. 후자의 단계는 매우 중요합니다. 디폴트 ptxas
출력은 재배치 가능 elf
오브젝트 일 뿐이며, 생성 된 fatbinary 컨테이너는 없습니다. nvcc가 실행되는 장치 코드 연결 단계 (적어도 CUDA 5에서)는 모든 장치 코드가 fatbinary 컨테이너에 존재할 것으로 예상됩니다. 그렇지 않으면 링키지가 실패합니다. 결과는 다음과 같습니다.
$ ptxas -arch=sm_30 -c -o inc_ptr.gpu.o inc_ptr.ptx
$ fatbinary -arch=sm_30 -create inc_ptr.fatbin -elf inc_ptr.gpu.o
$ cuobjdump -sass inc_ptr.fatbin
Fatbin elf code:
================
arch = sm_30
code version = [1,6]
producer = <unknown>
host = mac
compile_size = 32bit
code for sm_30
Function : inc_ptr
/*0008*/ /*0x0040dc8580000000*/ LD R3, [R4];
/*0010*/ /*0x00301c8580000000*/ LD R0, [R3];
/*0018*/ /*0x14001c0348000000*/ IADD R0, R0, R5;
/*0020*/ /*0x00301c8590000000*/ ST [R3], R0;
/*0028*/ /*0x00001de790000000*/ RET;
/*0030*/ /*0x00001de440000000*/ NOP CC.T;
/*0038*/ /*0x00001de440000000*/ NOP CC.T;
/*0040*/ /*0xe0001de74003ffff*/ BRA 0x40;
/*0048*/ /*0x00001de440000000*/ NOP CC.T;
/*0050*/ /*0x00001de440000000*/ NOP CC.T;
/*0058*/ /*0x00001de440000000*/ NOP CC.T;
/*0060*/ /*0x00001de440000000*/ NOP CC.T;
/*0068*/ /*0x00001de440000000*/ NOP CC.T;
/*0070*/ /*0x00001de440000000*/ NOP CC.T;
/*0078*/ /*0x00001de440000000*/ NOP CC.T;
........................
조립 된 PTX의 마이크로 코드가 포함되어 있음을 볼 수 있습니다. 장치 기능 fatbin 준비, 당신은 CUDA C 코드 같은 것을 할 수 있습니다 : 당신이 통제 맹 글링 기호를 얻을로
별도의 편집 모드에서
extern "C" __device__ void inc_ptr(int* &ptr, const int inc);
__global__
void memsetkernel(int *inout, const int val, const int N)
{
int stride = blockDim.x * gridDim.x;
int *p = inout;
inc_ptr(p, threadIdx.x + blockDim.x*blockIdx.x);
for(; p < inout+N; inc_ptr(p, stride)) *p = val;
}
int main(void)
{
const int n=10;
int *p;
cudaMalloc((void**)&p, sizeof(int)*size_t(n));
memsetkernel<<<1,32>>>(p, 5, n);
return 0;
}
장치 코드 툴체인은 긴합니다 (extern
선언을 존중합니다), 장치 기능 fatbinary는 최종 객체를 생성하는 다른 장치와 호스트 코드와 링크 할 수 있습니다
이
$ nvcc -arch=sm_30 -Xptxas="-v" -dlink -o memset.out inc_ptr.fatbin memset_kernel.cu
ptxas info : 0 bytes gmem
ptxas info : Compiling entry function '_Z12memsetkernelPiii' for 'sm_30'
ptxas info : Function properties for _Z12memsetkernelPiii
8 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info : Used 20 registers, 332 bytes cmem[0]
$ cuobjdump -sass memset.out
Fatbin elf code:
================
arch = sm_30
code version = [1,6]
producer = <unknown>
host = mac
compile_size = 32bit
identifier = inc_ptr.fatbin memset_kernel.cu
code for sm_30
Function : _Z12memsetkernelPiii
/*0008*/ /*0x10005de428004001*/ MOV R1, c [0x0] [0x44];
/*0010*/ /*0x20105d034800c000*/ IADD R1, R1, -0x8;
/*0018*/ /*0x00019de428004005*/ MOV R6, c [0x0] [0x140];
/*0020*/ /*0x10101c034800c000*/ IADD R0, R1, 0x4;
/*0028*/ /*0x8400dc042c000000*/ S2R R3, SR_Tid_X;
/*0030*/ /*0x90041c0348004000*/ IADD R16, R0, c [0x0] [0x24];
/*0038*/ /*0x94001c042c000000*/ S2R R0, SR_CTAid_X;
/*0048*/ /*0xd0009de428004000*/ MOV R2, c [0x0] [0x34];
/*0050*/ /*0x91045d0348004000*/ IADD R17, R16, -c [0x0] [0x24];
/*0058*/ /*0x40011de428000000*/ MOV R4, R16;
/*0060*/ /*0xa0015ca320064000*/ IMAD R5, R0, c [0x0] [0x28], R3;
/*0068*/ /*0x01119c85c8000000*/ STL [R17], R6;
/*0070*/ /*0xa0209ca350004000*/ IMUL R2, R2, c [0x0] [0x28];
/*0078*/ /*0x0001000710000000*/ JCAL 0x0;
/*0088*/ /*0x0110dc85c0000000*/ LDL R3, [R17];
/*0090*/ /*0x20001de428004005*/ MOV R0, c [0x0] [0x148];
/*0098*/ /*0x00049c4340004005*/ ISCADD R18, R0, c [0x0] [0x140], 0x2;
/*00a0*/ /*0x4831dc031b0e0000*/ ISETP.GE.U32.AND P0, pt, R3, R18, pt;
/*00a8*/ /*0x000001e780000000*/ @P0 EXIT;
/*00b0*/ /*0x1004dde428004005*/ MOV R19, c [0x0] [0x144];
/*00b8*/ /*0x0034dc8590000000*/ ST [R3], R19;
/*00c8*/ /*0x40011de428000000*/ MOV R4, R16;
/*00d0*/ /*0x08015de428000000*/ MOV R5, R2;
/*00d8*/ /*0x0001000710000000*/ JCAL 0x0;
/*00e0*/ /*0x0110dc85c0000000*/ LDL R3, [R17];
/*00e8*/ /*0x4831dc03188e0000*/ ISETP.LT.U32.AND P0, pt, R3, R18, pt;
/*00f0*/ /*0x000001e74003ffff*/ @P0 BRA 0xb8;
/*00f8*/ /*0x00001de780000000*/ EXIT;
/*0100*/ /*0xe0001de74003ffff*/ BRA 0x100;
/*0108*/ /*0x00001de440000000*/ NOP CC.T;
/*0110*/ /*0x00001de440000000*/ NOP CC.T;
/*0118*/ /*0x00001de440000000*/ NOP CC.T;
/*0120*/ /*0x00001de440000000*/ NOP CC.T;
/*0128*/ /*0x00001de440000000*/ NOP CC.T;
/*0130*/ /*0x00001de440000000*/ NOP CC.T;
/*0138*/ /*0x00001de440000000*/ NOP CC.T;
.....................................
Function : inc_ptr
/*0008*/ /*0x0040dc8580000000*/ LD R3, [R4];
/*0010*/ /*0x00301c8580000000*/ LD R0, [R3];
/*0018*/ /*0x14001c0348000000*/ IADD R0, R0, R5;
/*0020*/ /*0x00301c8590000000*/ ST [R3], R0;
/*0028*/ /*0x00001de790000000*/ RET;
/*0030*/ /*0x00001de440000000*/ NOP CC.T;
/*0038*/ /*0x00001de440000000*/ NOP CC.T;
/*0040*/ /*0xe0001de74003ffff*/ BRA 0x40;
/*0048*/ /*0x00001de440000000*/ NOP CC.T;
/*0050*/ /*0x00001de440000000*/ NOP CC.T;
/*0058*/ /*0x00001de440000000*/ NOP CC.T;
/*0060*/ /*0x00001de440000000*/ NOP CC.T;
/*0068*/ /*0x00001de440000000*/ NOP CC.T;
/*0070*/ /*0x00001de440000000*/ NOP CC.T;
/*0078*/ /*0x00001de440000000*/ NOP CC.T;
........................
이를 달성하기 위해 툴체인과 함께 연주 할 수있는 다른 트릭이있을 수도 있지만,이 방법은 확실히 작동합니다.
불행히도, 나는 그것이 가능하지 않을 수도 있다고 생각합니다. 문제는 CUDA C가 장치 코드 용 링커를 가지고 있지 않다는 것입니다. 따라서 한 커널에서 실행되는 모든 내용은 동일한 .cu 파일에 있어야합니다. IMO, NVIDIA가 인라인 PTX 구문에 대한 열악한 작업을했기 때문에 나는 틀렸다고 생각합니다. –
@RogerDahl 그래, 그게 내가 두려워했던거야. 그러나 CUDA 5 (http://developer.download.nvidia.com/assets/cuda/files/CUDADownloads/GPU_Library_Object_Linking.pdf)에 장치 코드 링커가 올 수있는 것처럼 보입니다. CUDA 5 Preview에서 어떻게하는지 알지 못했습니다. – fursund