1

各行の可変幅の 2D 配列を GPU にコピーする方法を検討しています。

int rows = 1000;
int cols;
int** host_matrix = malloc(sizeof(*int)*rows);
int *d_array;
int *length;

...

それぞれhost_matrix[i]の長さが異なる可能性がありますが、それは私が知っていることlength[i]であり、そこから問題が始まります。ダミーデータのコピーは避けたい。それを行うより良い方法はありますか?

このスレッドによると、それは賢明な方法ではありません。

cudaMalloc(d_array, rows*sizeof(int*));  
for(int i = 0 ; i < rows ; i++)    {  
    cudaMalloc((void **)&d_array[i], length[i] * sizeof(int)); 
}  

しかし、それ以外の方法が思い浮かびません。他にもっとスマートな方法はありますか?cudaMallocPitch と cudaMemCpy2D を使用して改善できますか??

4

2 に答える 2

5

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)に削減されます。

于 2012-09-18T20:33:11.213 に答える
0

すべてのデータを 1 つの配列に入れます。次に、行の長さを使用して別の配列を構成し、A[0] が行 0 の長さになるようにします。したがって、A[i] = length[i] 次に、カードに 2 つの配列を割り当て、memcopy を 2 回呼び出すだけで済みます。
もちろん、それは少し余分な作業ですが、パフォーマンスに関しては改善されると思います(もちろん、カード上のデータをどのように使用するかによって異なります)

于 2013-08-09T23:19:20.080 に答える