2012-05-13 2 views
0

JCUDA에서 작업하는 데 문제가 있습니다. CUFFT 라이브러리를 사용하여 1D FFT를 만드는 작업이 있지만 결과는 2가되어야합니다. 그래서 CUFFT_R2C 유형의 1D FFT를 만들기로했습니다. 다음에 책임지는 클래스 :JCuda. 이미 사용 된 포인터 재사용

public class FFTTransformer { 

    private Pointer inputDataPointer; 

    private Pointer outputDataPointer; 

    private int fftType; 

    private float[] inputData; 

    private float[] outputData; 

    private int batchSize = 1; 

    public FFTTransformer (int type, float[] inputData) { 
     this.fftType = type; 
     this.inputData = inputData; 
     inputDataPointer = new CUdeviceptr(); 

     JCuda.cudaMalloc(inputDataPointer, inputData.length * Sizeof.FLOAT); 
     JCuda.cudaMemcpy(inputDataPointer, Pointer.to(inputData), 
       inputData.length * Sizeof.FLOAT, cudaMemcpyKind.cudaMemcpyHostToDevice); 

     outputDataPointer = new CUdeviceptr(); 
     JCuda.cudaMalloc(outputDataPointer, (inputData.length + 2) * Sizeof.FLOAT); 

    } 

    public Pointer getInputDataPointer() { 
     return inputDataPointer; 
    } 

    public Pointer getOutputDataPointer() { 
     return outputDataPointer; 
    } 

    public int getFftType() { 
     return fftType; 
    } 

    public void setFftType(int fftType) { 
     this.fftType = fftType; 
    } 

    public float[] getInputData() { 
     return inputData; 
    } 

    public int getBatchSize() { 
     return batchSize; 
    } 

    public void setBatchSize(int batchSize) { 
     this.batchSize = batchSize; 
    } 

    public float[] getOutputData() { 
     return outputData; 
    } 

    private void R2CTransform() { 

     cufftHandle plan = new cufftHandle(); 

     JCufft.cufftPlan1d(plan, inputData.length, cufftType.CUFFT_R2C, batchSize); 

     JCufft.cufftExecR2C(plan, inputDataPointer, outputDataPointer); 

     JCufft.cufftDestroy(plan); 
    } 

    private void C2CTransform(){ 

     cufftHandle plan = new cufftHandle(); 

     JCufft.cufftPlan1d(plan, inputData.length, cufftType.CUFFT_C2C, batchSize); 

     JCufft.cufftExecC2C(plan, inputDataPointer, outputDataPointer, fftType); 

     JCufft.cufftDestroy(plan); 
    } 

    public void transform(){ 
     if (fftType == JCufft.CUFFT_FORWARD) { 
      R2CTransform(); 
     } else { 
      C2CTransform(); 
     } 
    } 

    public float[] getFFTResult() { 
     outputData = new float[inputData.length + 2]; 
     JCuda.cudaMemcpy(Pointer.to(outputData), outputDataPointer, 
       outputData.length * Sizeof.FLOAT, cudaMemcpyKind.cudaMemcpyDeviceToHost); 
     return outputData; 
    } 

    public void releaseGPUResources(){ 
     JCuda.cudaFree(inputDataPointer); 
     JCuda.cudaFree(outputDataPointer); 
    } 

    public static void main(String... args) { 
     float[] inputData = new float[65536]; 
     for(int i = 0; i < inputData.length; i++) { 
      inputData[i] = (float) Math.sin(i); 
     } 
     FFTTransformer transformer = new FFTTransformer(JCufft.CUFFT_FORWARD, inputData); 
     transformer.transform(); 
     float[] result = transformer.getFFTResult(); 

     HilbertSpectrumTicksKernelInvoker.multiplyOn2(transformer.getOutputDataPointer(), inputData.length+2); 

     transformer.releaseGPUResources(); 
    } 
} 

책임있는 방법은 쿠다 커널 기능을 사용합니다. Java 메소드 코드 :

public static void multiplyOn2(Pointer inputDataPointer, int dataSize){ 

     // Enable exceptions and omit all subsequent error checks 
     JCudaDriver.setExceptionsEnabled(true); 

     // Create the PTX file by calling the NVCC 
     String ptxFileName = null; 
     try { 
      ptxFileName = FileService.preparePtxFile("resources\\HilbertSpectrumTicksKernel.cu"); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     // Initialize the driver and create a context for the first device. 
     cuInit(0); 
     CUdevice device = new CUdevice(); 
     cuDeviceGet(device, 0); 
     CUcontext context = new CUcontext(); 
     cuCtxCreate(context, 0, device); 

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

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

     // Set up the kernel parameters: A pointer to an array 
     // of pointers which point to the actual values. 
     int N = (dataSize + 1)/2 + 1; 
     int pair = (dataSize + 1) % 2 > 0 ? 1 : -1; 

     Pointer kernelParameters = Pointer.to(Pointer.to(inputDataPointer), 
       Pointer.to(new int[] { dataSize }), 
       Pointer.to(new int[] { N }), Pointer.to(new int[] { pair })); 

     // Call the kernel function. 
     int blockSizeX = 128; 
     int gridSizeX = (int) Math.ceil((double) dataSize/blockSizeX); 
     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 
     ); 
     cuCtxSynchronize(); 

     // Allocate host output memory and copy the device output 
     // to the host. 
     float freq[] = new float[dataSize]; 
     cuMemcpyDtoH(Pointer.to(freq), (CUdeviceptr)inputDataPointer, dataSize 
       * Sizeof.FLOAT); 

그리고 커널 함수는 다음과 같습니다

extern "C" 

__global__ void calcSpectrumSamples(float* complexData, int dataSize, int N, int pair) { 

    int i = threadIdx.x + blockIdx.x * blockDim.x; 

    if(i >= dataSize) return; 

    complexData[i] = complexData[i] * 2; 
} 

하지만 난에 (장치 메모리) FFT의 결과를 가리키는 포인터를 전달하기 위해 노력하고있어 때 multiplyOn2 메서드를 호출하면 cuCtxSynchronize() 호출에서 예외가 발생합니다. 예외 :

Exception in thread "main" jcuda.CudaException: CUDA_ERROR_UNKNOWN 
    at jcuda.driver.JCudaDriver.checkResult(JCudaDriver.java:263) 
    at jcuda.driver.JCudaDriver.cuCtxSynchronize(JCudaDriver.java:1709) 
    at com.ifntung.cufft.HilbertSpectrumTicksKernelInvoker.multiplyOn2(HilbertSpectrumTicksKernelInvoker.java:73) 
    at com.ifntung.cufft.FFTTransformer.main(FFTTransformer.java:123) 

저는 Visual Studion C++를 사용하여 동일한 작업을 수행하려고했으나 아무런 문제가 없습니다. 저 좀 도와 주 시겠어요.

P. 이 prolem을 해결할 수는 있지만 장치 메모리에서 호스트 메모리로 데이터를 복사 한 다음 새 cuda 함수를 호출하기 전에 매번 새로운 포인터를 작성하여 복사해야하므로 프로그램 실행 속도가 느려집니다.

답변

1

정확히 어디에서 오류가 발생합니까?

Cuda 오류는 이전 오류 일 수도 있습니다.

왜 Pointer.to (inputDataPointer)를 사용합니까? 이미 해당 장치 포인터가 있습니다. 이제 장치 포인터를 장치에 전달합니까?

Pointer kernelParameters = Pointer.to(Pointer.to(inputDataPointer), 

"this"한정자 또는 다른 표시를 사용하여 인스턴스 변수를 검색하는 것이 좋습니다. 나는 싫어하고 코드를 살펴보기를 거절합니다. 특히 메소드에서 변수가 읽는 것으로 디버깅하려고 시도한 범위를 볼 수없는 경우 예제와 같이 중첩되어 있습니다.
나는 항상이 변수가 어디에서 오는 지 스스로에게 묻고 싶지 않습니다.

SO의 질문에있는 복잡한 코드가 제대로 포맷되지 않으면 읽지 않습니다.