2011-05-19 99 views
4

我已經寫了一些代碼來嘗試交換用於FFT目的的2D矩陣的象限,它存儲在一個平面陣列中。CUDA設備到設備轉移昂貴

int leftover = W-dcW; 

    T *temp; 
    T *topHalf; 
cudaMalloc((void **)&temp, dcW * sizeof(T)); 

    //swap every row, left and right 
    for(int i = 0; i < H; i++) 
    { 
     cudaMemcpy(temp, &data[i*W], dcW*sizeof(T),cudaMemcpyDeviceToDevice); 
     cudaMemcpy(&data[i*W],&data[i*W+dcW], leftover*sizeof(T), cudaMemcpyDeviceToDevice); 
     cudaMemcpy(&data[i*W+leftover], temp, dcW*sizeof(T), cudaMemcpyDeviceToDevice); 
    } 

cudaMalloc((void **)&topHalf, dcH*W* sizeof(T)); 
    leftover = H-dcH; 
    cudaMemcpy(topHalf, data, dcH*W*sizeof(T), cudaMemcpyDeviceToDevice); 
    cudaMemcpy(data, &data[dcH*W], leftover*W*sizeof(T), cudaMemcpyDeviceToDevice); 
    cudaMemcpy(&data[leftover*W], topHalf, dcH*W*sizeof(T), cudaMemcpyDeviceToDevice); 

請注意,此代碼需要設備指針,並且DeviceToDevice傳輸。

爲什麼這似乎運行如此緩慢?這可以優化嗎?我使用普通的memcpy對主機進行了相同的操作,並且速度慢了約2倍。

任何想法?

+4

啓動cudaMemcpy代價高昂。您最好編寫一個從輸入讀取的內核,交換和寫入適當的位置,而不是將cudaMemcpy放在for循環中。 – 2011-05-20 01:20:27

+0

hrmmm..bummer。做一個主機memcpy和轉移到設備的比較呢? – Derek 2011-05-20 15:05:37

回答

6

我最終編寫了一個內核來完成交換。這的確是比設備到設備的memcpy操作變得更快

3

也許下面的解決方案來執行在CUDA的2D fftshift會感興趣:

#define IDX2R(i,j,N) (((i)*(N))+(j)) 

__global__ void fftshift_2D(double2 *data, int N1, int N2) 
{ 
    int i = threadIdx.y + blockDim.y * blockIdx.y; 
    int j = threadIdx.x + blockDim.x * blockIdx.x; 

    if (i < N1 && j < N2) { 
     double a = pow(-1.0, (i+j)&1); 

     data[IDX2R(i,j,N2)].x *= a; 
     data[IDX2R(i,j,N2)].y *= a; 
    } 
} 

它由矩陣相乘由棋盤轉化1 s和-1 s,這相當於乘以exp(-j*(n+m)*pi)並因此在共軛域中在兩個方向上移位。

您必須在應用CUFFT之前和之後調用此內核。

一個親是避免記憶移動/交換。

改進速度

繼在NVIDIA Forum接收的建議,改進的速度可通過改變指令

double a = pow(-1.0,(i+j)&1); 

來實現,以

double a = 1-2*((i+j)&1); 

避免使用慢速常規戰俘。

+0

實際上,在幾乎所有過濾應用中,通過將所有過濾器保留在包裹的fft空間中可以消除此步驟。 – Mikhail 2014-06-23 06:45:39