2014년 11월 5일 수요일

JCUDA 샘플 분석/빌드 하기 (부제:고난의 삽질)

CUDA에서는 GPU쪽에 실행할 명령을 보내야 합니다. 컴파일은 일반 컴파일러가 하는것은 아니고, NVCC컴파일러라는 툴이 하게 됩니다. CUDA를 설치하면 같이 설치하게 됩니다.

정리하자면,
*.cu 라는 파일이 있는데 이런 종류의 파일을 kernel 파일이라고하고,
해당 파일을 NVCC컴파일로 컴파일을 하면 PTX라는 파일이 생성됩니다.
PTX 파일을 JCUDA에서 Driver API를 이용해서 실행시키면 됩니다.
아래 내용을 보면 CUBIN이라는 binary파일도 있다고 합니다.
As a PTX file, which is a human-readable (but hardly human-understandable) file containing a specific form of "assembler" source code.
As a CUBIN file, which is a "CUDA binary" and contains the compiled code that can directly be loaded and executed by a specific GPU.

*.cu(kernel)파일을 만들때 JCUDA는 CUDA와 다른 부분이 있습니다.
함수앞에 extern "C" 를 반듯이 붙여줘야 합니다. (tutorial에 나오는 내용인데 java 에서 jni로 호출할때 C/C++로 빌드하면 mangled 때문에 이름이 이상해지기 때문입니다. extern "C"를 붙이면 함수 그대로 있게 됩니다.

아래는 tutorial site에 있는 예제입니다.

cu파일은 GPU에서 동작하는 kernel 파일입니다. 여러개의 thread 들이 동시에 동작하게 됩니다. 여기에 blockIdx.x blockDim.x threadIdx.x 이런 내용이 있는데 해당 내용은 다음에 포스팅 하도록 하겠습니다.
JCudaVectorAddKernel.cu

extern "C"
__global__ void add(int n, float *a, float *b, float *sum)
{
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i<n)
    {
        sum[i] = a[i] + b[i];
    }
}


Java 쪽 파일 ptx파일을 읽어서 load 합니다.

// Load the ptx file.
CUmodule module = new CUmodule();
cuModuleLoad(module, "JCudaVectorAddKernel.ptx");

// Obtain a function pointer to the kernel function.
CUfunction function = new CUfunction();
cuModuleGetFunction(function, module, "add");

커널 파라메터를 설정하고
// Set up the kernel parameters: A pointer to an array
// of pointers which point to the actual values.
Pointer kernelParameters = Pointer.to(
    Pointer.to(new int[]{numElements}), 
    Pointer.to(deviceInputA), 
    Pointer.to(deviceInputB), 
    Pointer.to(deviceOutput)
);

GPU 쪽 함수가 실행될수 있도록 호출합니다.
// Call the kernel function.
cuLaunchKernel(function, 
    gridSizeX,  1, 1,      // Grid dimension 
    blockSizeX, 1, 1,      // Block dimension
    0, null,               // Shared memory size and stream 
    kernelParameters, null // Kernel- and extra parameters
); 

여기까지 한번 테스트 해보았습니다.
소스는 http://www.jcuda.org/tutorial/TutorialIndex.html 여기에서 구할 수 있습니다.
cu파일을 project 최상위 폴더에 넣고 실행하였습니다.

아! ㅠㅠ 빌드에러가 납니다. MSVC가 없다고 에러가 나네요. 이런 젠장젠장젠장젠장젠장

Executingnvcc -m64 -ptx JCudaVectorAddKernel.cu -o JCudaVectorAddKernel.ptxnvcc process exitValue 1errorMessage:
outputMessage:nvcc fatal   : Cannot find compiler 'cl.exe' in PATH
Exception in thread "main" java.io.IOException: Could not create .ptx file:  at CUDAtest.preparePtxFile(CUDAtest.java:184) at CUDAtest.main(CUDAtest.java:35)

열심히 구글링 해봤는데
https://devtalk.nvidia.com/default/topic/398377/c-compiler-other-than-39-cl-exe-39-in-windows/
gcc를 깔면 된다는 말도 있고 끝이 애매하네요. 아래와 같은 말이 눈에 띄네요.

gcc is only supported for Mac & Linux. MSVC is the only supported compiler for Windows.

여기에 보니 window에서는 MSVC만 되는것 같네요. 여기에서 GG 치고 MSVC 설치하고 오겠습니다.

nvcc uses the following compilers for host code compilation:
On Linux platforms
The GNU compiler, gcc, and arm-linux-gnueabihf-g++ for cross compilation to the ARMv7 architecture
On Windows platforms
The Microsoft Visual Studio compiler, cl
Read more at: http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#ixzz3I6PTw7uh
Follow us: @GPUComputing on Twitter | NVIDIA on Facebook



무료 express 버전 MSVC 설치 장소 : http://www.visualstudio.com/ko-kr
express라는 말이 눈에띄는 2010버전을 설치하도록 하겠습니다. 2013 버전은 msdn id가 있어야 되네요.

Visual Studio 2010 Express

그래도 빌드가 안되네요.
아래와 같이 에러가 발생합니다.
nvcc -m64 -ptx JCudaVectorAddKernel.cu -o JCudaVectorAddKernel.ptx
nvcc fatal   : nvcc cannot find a supported version of Microsoft Visual Studio.
Only the versions 2010, 2012, and 2013 are supported

어렵게 어렵게 검색해서 찾은 내용입니다.
http://stackoverflow.com/questions/21103243/compiling-cuda-code-from-the-command-line

set CUDAFE_FLAGS=--sdk_dir "C:\Program Files (x86)\Windows Kits\8.0\"
"C:\_work\API\CUDA\bin\nvcc.exe" --use-local-env --cl-version 2012 -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\x86_amd64"        --keep-dir x64\Prod -maxrregcount=0  --machine 64
"C:\_work\API\CUDA\bin\nvcc.exe" --use-local-env --cl-version 2010 -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\cl.exe" --machine 32
아래 방식으로 하니까 ptx파일이 만들어집니다.

두둥... 그런데, 여전히 안됩니다.

Exception in thread "main" jcuda.CudaException: CUDA_ERROR_LAUNCH_FAILED at jcuda.driver.JCudaDriver.checkResult(JCudaDriver.java:288) at jcuda.driver.JCudaDriver.cuCtxSynchronize(JCudaDriver.java:1852) at CUDAtest.main(CUDAtest.java:96)


아 아 아 ....
좀 더 찾아보니 ptx파일이 32bit로 만들어져서 그렇다고 합니다. nvcc 옵션에 --machine 32 -> 64만 변경하면 될 줄 알았는데 빌드 에러가 나네요.
CUDA는 64bit를 설치했는데 Visual Studio 2010 Express 버전이 32bit용이라 64bit로 빌드가 안되네요.

자자. 정리가 안되는데

http://stackoverflow.com/questions/1865069/how-to-compile-a-64-bit-application-using-visual-c-2010-express
여기 검색해보니 아래에서 windows SDK를 받으면 64bit 버전이 깔린다고 합니다.
http://msdn.microsoft.com/en-us/windowsserver/bb980924.aspx

이것도 해봤는데 안되는군요....

다시 이전에 설치한 2010 express 버전을 지우고 2012버전을 설치하도록 하겠습니다. 2012버전은 32/64 bit모두 지원된다고 나와 있네요. 처음 2012 버전을 설치 안한 이유는 MS사 링크가 없어서 그랬는데 구글 검색하니 링크가 보이네요. 기존꺼 모두 제거하고 설치하겠습니다. 삽질의 연속이네요.

Visual Studio 2012 Express for Windows Desktop : 기존 개발
지원 운영 체제 : Windows 7 SP1(x86, x64), Windows 8(x86, x64), Windows Server 2008 R2 SP1(x64), Windows Server 2012(x64)

http://www.microsoft.com/ko-kr/download/details.aspx?id=34673

http://download.microsoft.com/download/5/0/3/503C6C1D-A1C3-4BC1-AC7B-DFDF1AC6A74C/VS2012_WDX_KOR.iso (623M)

모두 설치했습니다. 이제 CU 빌드만 남았습니다.
이클립스 실행하면 자동으로 nvcc에 의해 빌드하도록 코드가 되어 있는데 실제 해보면 동작하지 않습니다. 이유는 cl.exe가 path에 들어 있지 않기 때문입니다.
64비트용 cl은 C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\x86_amd64 여기에 있습니다.
그리고 그곳에 vcvarsx86_amd64.bat 이런 파일이 있는데 해당 파일이 환경 변수를 설정하는 batch 파일 입니다.

실행에 cmd를 치고 커맨드 프롬프트 창을 엽니다.
그리고 java 자신의 프로젝트 쪽으로 이동을 합니다.
그후 call 명령으로 배치파일을 끌어다 놓은뒤 실행합니다.


Microsoft Windows [Version 6.3.9600](c) 2013 Microsoft Corporation. All rights reserved.
C:\Users\2nd_user>cd D:\work\개인\ProgramMake\workspace\CUDAtest
C:\Users\2nd_user>d:
D:\work\개인\ProgramMake\workspace\CUDAtest>call "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\x86_amd64\vcvarsx86_amd64.bat"
D:\work\개인\ProgramMake\workspace\CUDAtest>nvcc.exe --use-local-env --cl-version 2012 -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\x86_amd64" -maxrregcount=0  --machine 64 -ptx JCudaVectorAddKernel.cu -o JCudaVectorAddKernel.ptx


이런식으로 하면 ptx파일이 정상적으로 생성됩니다.
ptx파일이 생성된 후 이클립스에서 테스트 프로그램을 실행시키면 아래와 같은 문구가 보이면 성공한 것입니다.

Test PASSED

고생했습니다.





댓글 없음:

댓글 쓰기