2012-02-23 9 views
3

デバイスからホストにデータをコピーするときに問題が発生します。私のデータは、構造体に配置されている:デバイスからホストにデータをコピーするときに無効な引数エラーが発生する

typedef struct Array2D { 
    double* arr;   
    int rows;  
    int cols;  
} Array2D; 

arrは「フラット」配列です。 rowsおよびcolsは寸法を記載する。

次のコードは、私が戻ってホストにデータをコピーしようとしています方法を示しています。

h_output = (Array2D*) malloc(sizeof(Array2D)); 
cudaMemcpy(h_output, d_output, sizeof(Array2D), cudaMemcpyDeviceToHost); 
double* h_arr = (double*) malloc(h_output->cols*h_output->rows*sizeof(double)); 
cudaMemcpy(h_arr, h_output->arr, h_output->cols*h_output->rows*sizeof(double), cudaMemcpyDeviceToHost); 
h_output->arr = h_arr; 

はしかし、4行目の実行は、CUDAエラー11(無効な引数)で失敗します。なぜこれが起こっているのか分かりません。配列のサイズは正しいので、ホストからh_outputh_arrayの両方にアクセスすることができ、どちらも '本当の'アドレスを持っています。

EDIT 詳細(=複数のコード)の要求に遅れて応答するため申し訳ありません。

私は、ホスト上のデバイスポインタの値にアクセスしようとすると、ポインタd_output->arrがデバイスポインタであることをテストしました。予想どおり、d_output->arrが実際には有効なデバイスポインタであるという考えで私を去らせることは許されませんでした。

コードの目的は、4次のルンゲクッタ法を使用してチエールの微分方程式を解くことです。

EDIT2

class CalculationSpecification 
{ 

    /* FUNCTIONS OMITTED */ 

public: 
    __device__ void RK4_n(CalculationSpecification* cs, CalcData data, Array2D* d_output) 
    { 
     double* rk4data = (double*)malloc((data.pdata->endYear - data.pdata->startYear + 1)*data.pdata->states*sizeof(double)); 

     /* CALCULATION STUFF HAPPENS HERE */ 

     // We know that rows = 51, cols = 1 and that rk4data contains 51 values as it should. 
     // This was confirmed by using printf directly in this function. 
     d_output->arr = rk4data; 
     d_output->rows = data.pdata->endYear - data.pdata->startYear + 1; 
     d_output->cols = data.pdata->states; 
    } 
}; 


class PureEndowment : CalculationSpecification 
{ 
    /* FUNCTIONS OMITTED */ 

public: 
    __device__ void Compute(Array2D *result, CalcData data) 
    { 
     RK4_n(this, data, result); 
    } 
}; 


__global__ void kernel2(Array2D *d_output) 
{ 
    /* Other code that initializes 'cd'. */ 
    PureEndowment pe; 
    pe.Compute(d_output,cd); 
} 


void prepareOutputSet(Array2D* h_output, Array2D* d_output, int count) 
{ 
    h_output = (Array2D*) malloc(sizeof(Array2D)); 
    cudaMemcpy(h_output, d_output, sizeof(Array2D), cudaMemcpyDeviceToHost); // After this call I can read the correct values of row, col as well as the address of the pointer. 
    double* h_arr = (double*) malloc(h_output->cols*h_output->rows*sizeof(double)); 
    cudaMemcpy(h_arr, h_output->arr, h_output->cols*h_output->rows*sizeof(double), cudaMemcpyDeviceToHost) 
    h_output->arr = h_arr; 
} 

int main() 
{ 
    Array2D *h_output, *d_output; 
    cudaMalloc((void**)&d_output, sizeof(Array2D)); 

    kernel2<<<1,1>>>(d_output); 
    cudaDeviceSynchronize(); 

    prepareOutputSet(h_output, d_output, 1); 

    getchar(); 
    return 0; 
} 
はまた、私は今、デバイス上で実行されている d_output->arrの値が prepareOutputSetの最初の cudaMemcpy -call後 h_output->arrの値と同一であることをテストしています。

+1

エラーの原因としては、 'houtput-> arr'が有効なデバイスポインタではないことが考えられます。 'd_output'の内容をデバイスにどのように割り当ててコピーするかを示すためにコードを少し拡張できますか? – talonmies

+0

'd_output'とその内容は' malloc() 'を使ってデバイス上に割り当てられます。 'd_output-> arr'の内容を出力しようとしたときに実際のデータが入っていると確信して、期待される出力を得ました。 – ssnielsen

+0

'h_output' _とその内容を意味しますか? 'd_output'はあなたのサンプルコードには表示されないからです。 – pQB

答えて

2

これは(cudaMemcpyを使用してデバイス割り当てメモリをコピーする)CUDA 4.1の既知の制限です。修正は作業中であり、将来のバージョンのCUDAランタイムでリリースされる予定です。

+0

それを聞いてうれしいです。 – ssnielsen

+0

@harrism:同じエラーコードがあります。さらに調査すると、データをCPUにコピーするのに十分なRAMが残っていないことがわかりました。したがって、 'cudaMemcpy'は失敗していました。これはエラーコードの正当な理由ですか、私は間違った方法ですか? – Programmer

+0

これはここに記載されたものとは異なる問題です。 – harrism

-1

h_outputmalloc()を呼び出して割り当てられているようです。 cudaMemcpy()(行2)への最初の呼び出しでは、ホストポインタとしてh_outputが使用されています(これは正しいようです)。 cudaMemcpy()(行4)への2回目の呼び出しでは、デバイスポインタとしてh_output->arrが使用されています(正しくはないようです)。その4行目では、ホストメモリからホストメモリにコピーしているようです。したがって、cudaMemcpy()ではなく、まっすぐのmemcpy()を使用することをお勧めします。

少なくとも、これはあなたが提供したコードのようです。

+0

これはコードが実際に行っていることではありません。それは完璧にすべきですが、 'h_output-> arr'(拡張モジュールではソースメモリである' d_output-> arr')が有効なデバイスポインタを保持している場合に限ります。 – talonmies

+0

私は私が従うか分からない。 'h_output'は' malloc() 'で割り当てられます。その後、 'cudaMemcpy()'を使ってホストポインタとしてコピーします。それから '(cudaMemcpy()'への前回の呼び出しから 'h_output-> arr'をセットしないで)' c_put_ arr'を使って 'cudaMemcpy()'が再び呼び出されます。そして、あなたはその質問の周りにその効果についてコメントしているようです。 –

+0

'cudaMemcpy()'呼び出しの後、 'h_output'は' d_output'が指し示すデバイスメモリ構造体のコピーを効果的に指し示します。 'd_output-> arr'が有効なデバイスポインタであれば、コピーの後に' h_output-> arr'もあります。 – talonmies

0

あなたが見ているエラーは、h_output->arrが有効なデバイスポインタでないか、またはh_output->rowsまたはh_output->colsが何らかの理由で間違っていることが原因です。ソースメモリd_outputの内容がどのように設定されているかを説明するコードを表示しないことを選択したので、問題の根本原因が何であるかを確実に言うことはできません。私は唯一のコンピューティング能力の1を持っているので、ここではいくつかの自由を取るために持っていた

#include <cstdlib> 
#include <cstdio> 

inline void GPUassert(cudaError_t code, char * file, int line, bool Abort=true) 
{ 
    if (code != 0) { 
     fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code),file,line); 
     if (Abort) exit(code); 
    }  
} 

#define GPUerrchk(ans) { GPUassert((ans), __FILE__, __LINE__); } 

typedef float Real; 

typedef struct Array2D { 
    Real* arr;   
    int rows;  
    int cols;  
} Array2D; 

__global__ void kernel(const int m, const int n, Real *lval, Array2D *output) 
{ 
    lval[threadIdx.x] = 1.0f + threadIdx.x; 
    if (threadIdx.x == 0) { 
     output->arr = lval; 
     output->rows = m; 
     output->cols = n; 
    } 
} 

int main(void) 
{ 
    const int m=8, n=8, mn=m*n; 

    Array2D *d_output; 
    Real *d_arr; 
    GPUerrchk(cudaMalloc((void **)&d_arr,sizeof(Real)*size_t(mn))); 

    GPUerrchk(cudaMalloc((void **)&d_output, sizeof(Array2D))); 
    kernel<<<1,mn>>>(m,n,d_arr,d_output); 
    GPUerrchk(cudaPeekAtLastError()); 

    // This section of code is the same as the original question 
    Array2D *h_output = (Array2D*)malloc(sizeof(Array2D)); 
    GPUerrchk(cudaMemcpy(h_output, d_output, sizeof(Array2D), cudaMemcpyDeviceToHost)); 
    size_t sz = size_t(h_output->rows*h_output->cols)*sizeof(Real); 
    Real *h_arr = (Real*)malloc(sz); 
    GPUerrchk(cudaMemcpy(h_arr, h_output->arr, sz, cudaMemcpyDeviceToHost)); 

    for(int i=0; i<h_output->rows; i++) 
     for(int j=0; j<h_output->cols; j++) 
      fprintf(stdout,"(%d %d) %f\n", i, j, h_arr[j + i*h_output->rows]); 

    return 0; 
} 

はここにアクションで掲示コードを示す完全な、実行可能なデモがあり、ポイントを説明します。私の処分では2つのデバイスなので、デバイス側ではない mallocと倍精度なし。しかし、デバイスメモリから有効な Array2D構造体を取り出し、その内容を使用するホスト側のAPI呼び出しは事実上同じです。プログラムを実行すると、期待通りに動作します:

$ nvcc -Xptxas="-v" -arch=sm_12 Array2D.cu 
ptxas info : Compiling entry function '_Z6kerneliiPfP7Array2D' for 'sm_12' 
ptxas info : Used 2 registers, 16+16 bytes smem 

$ cuda-memcheck ./a.out 
========= CUDA-MEMCHECK 
(0 0) 1.000000 
(0 1) 2.000000 
(0 2) 3.000000 
(0 3) 4.000000 
(0 4) 5.000000 
(0 5) 6.000000 
(0 6) 7.000000 
(0 7) 8.000000 
(1 0) 9.000000 
(1 1) 10.000000 
(1 2) 11.000000 
(1 3) 12.000000 
(1 4) 13.000000 
(1 5) 14.000000 
(1 6) 15.000000 
(1 7) 16.000000 
(2 0) 17.000000 
(2 1) 18.000000 
(2 2) 19.000000 
(2 3) 20.000000 
(2 4) 21.000000 
(2 5) 22.000000 
(2 6) 23.000000 
(2 7) 24.000000 
(3 0) 25.000000 
(3 1) 26.000000 
(3 2) 27.000000 
(3 3) 28.000000 
(3 4) 29.000000 
(3 5) 30.000000 
(3 6) 31.000000 
(3 7) 32.000000 
(4 0) 33.000000 
(4 1) 34.000000 
(4 2) 35.000000 
(4 3) 36.000000 
(4 4) 37.000000 
(4 5) 38.000000 
(4 6) 39.000000 
(4 7) 40.000000 
(5 0) 41.000000 
(5 1) 42.000000 
(5 2) 43.000000 
(5 3) 44.000000 
(5 4) 45.000000 
(5 5) 46.000000 
(5 6) 47.000000 
(5 7) 48.000000 
(6 0) 49.000000 
(6 1) 50.000000 
(6 2) 51.000000 
(6 3) 52.000000 
(6 4) 53.000000 
(6 5) 54.000000 
(6 6) 55.000000 
(6 7) 56.000000 
(7 0) 57.000000 
(7 1) 58.000000 
(7 2) 59.000000 
(7 3) 60.000000 
(7 4) 61.000000 
(7 5) 62.000000 
(7 6) 63.000000 
(7 7) 64.000000 
========= ERROR SUMMARY: 0 errors 
+0

元の質問がより多くのコードで更新されました。うまくいけば、それは問題を明るみに出します。 – ssnielsen

+0

投稿した余分なコードは、この回答の結論を変更しません。問題のポインタが有効なデバイスポインタである場合、投稿した元のAPIコードが修正されていることを明確に示しています。実際の質問は、あなたのデバイスのmallocされたポインタが、ホストに返されるまでに無効である理由です。 – talonmies

0

は、私がmallocを使用して、デバイス上でそれを割り当てるのではなく、cudaMallocを使用して、ホスト上のポインタArray2D->arrを割り当ててみました。その後、コードは意図したとおりに動作します。

nVidiaのフォーラムのスレッド(http://forums.nvidia.com/index.php?showtopic=222659)に記載されている問題とよく似ていて、パヴァンはそのコメントにコメントで言及しています。

コードが正常に動作するため、これはおそらく今のところ問題を閉じると思います。しかし、デバイス上でmallocを使用するソリューションの提案があれば、投稿してください。

関連する問題