CUDAでGPUにポインターの配列を割り当てる正しい方法は、次のようなものです。
int **hd_array, **d_array;
hd_array = (int **)malloc(nrows*sizeof(int*));
cudaMalloc(d_array, nrows*sizeof(int*));
for(int i = 0 ; i < nrows ; i++) {
cudaMalloc((void **)&hd_array[i], length[i] * sizeof(int));
}
cudaMemcpy(d_array, hd_array, nrows*sizeof(int*), cudaMemcpyHostToDevice);
(免責事項:ブラウザで記述され、コンパイルされておらず、テストされておらず、自己責任で使用してください)
アイデアは、最初にホストメモリ内のデバイスポインタの配列のコピーをアセンブルし、次にそれをデバイスにコピーすることです。1000行の仮定の場合、これは、デバイスのメモリ割り当てを設定し、データをデバイスにコピーするcudaMalloc
ためだけに、1001回の呼び出し、次に1001回の呼び出しを意味します。cudaMemcpy
それは莫大なオーバーヘッドペナルティであり、私はそれを試みることに対して助言します。パフォーマンスは本当にひどいものになります。
非常にギザギザのデータがあり、それをデバイスに保存する必要がある場合は、すべてのギザギザのデータの問題の母である大きな非構造化スパース行列を手がかりにして、代わりにデータのスパース行列形式の1つをコピーすることをお勧めします。モデルとして古典的な圧縮スパース行形式を使用すると、次のようなことができます。
int * data, * rows, * lengths;
cudaMalloc(rows, nrows*sizeof(int));
cudaMalloc(lengths, nrows*sizeof(int));
cudaMalloc(data, N*sizeof(int));
このスキームでは、すべてのデータを単一の線形メモリ割り当てに格納しますdata
。ジャグ配列のi番目の行はで始まり、data[rows[i]]
各行の長さはlength[i]
。です。nrows
つまり、現在のスキームではなく、デバイスに任意の量のデータを転送するために必要なメモリ割り当てとコピー操作は3つだけです。これにより、オーバーヘッドがO(N)からO(1)に削減されます。