-1

CUDA で並列化しようとしているループがあります。次のようになります。

float *buf = new float[buf_size]; // buf_size <= 100
for (int j; j<N; j++){
    caluculate_with(buf);
}
delete [] buf;

ループの性質は、各反復の開始時にバッファ配列の値が問題にならないことです。そのため、ループ自体はごく簡単に並列化できます。

しかし、CUDA では、カーネルへの非同期呼び出しのために、はるかに大きなバッファーが必要になりました。

void __global__ loop_kernel(float *buf_gpu) {
    const int idx = index_gpu(blockIdx, blockDim, threadIdx);
    float *buf = buf_gpu + (idx*buf_size);
    caluculate_with(buf);
}
    ....
    float * buf_gpu;
    cudaMalloc(&buf_gpu,sizeof(float)*N*buf_size);
    loop_kernel<<<mesh,block>>>(buf_gpu);
    cudaFree(buf_gpu);
}

カーネルへの各呼び出しはバッファの独自のセグメントを取得するため、バッファ サイズはループ サイズ N に合わせてスケーリングされますが、これは明らかな問題です。(バッファ サイズ) の量のメモリを使用する代わりに、(バッファ サイズ * ループ サイズ) を割り当てる必要があります。私の GTX590 の GPU メモリ制限は、私が取り組んでいる問題の N の典型的な値に達しています)。

編集:私の他の試みについて詳しく説明します。buf_size はそれほど大きくないので、カーネルを次のように書き直してみました。

void __global__ loop_kernel() {
    float *buf = new float[buf_size];
    caluculate_with(buf);
    delete [] buf;
}
...
assert(cudaSuccess == cudaDeviceSetLimit(cudaLimitMallocHeapSize,8*1024*1024));
loop_kernel<<<mesh,block>>>();
assert(cudaSuccess == cudaDeviceSynchronize());

cudaDeviceSynchronize() アサーションは戻りステータス 4 で失敗します。それが何を意味するのかわかりません。

4

1 に答える 1

1

あなたは私たちに何も言わなかったcalculate_with()ので、それが並列化可能かどうかは明らかではありませんが、それは確かに調査する価値があるかもしれません.

ただし、1 つのアプローチは、バッファ サイズを GPU メモリで処理できるサイズに制限し、そのバッファ サイズに基づいてループ内でカーネルを呼び出すことです。

void __global__ loop1_kernel(float *buf_gpu) {
  const int idx = index_gpu(blockIdx, blockDim, threadIdx);
  float *buf = buf_gpu + (idx*buf_size);
  caluculate_with(buf);
}
....
float * buf_gpu;
cudaMalloc(&buf_gpu,sizeof(float)*num_buffs*buf_size);
for (int j=0; j<(N/num_buffs; j++){
  loop_kernel<<<mesh,block>>>(buf_gpu);
  cudaMemcpy(host_data, buf_gpu, (sizeof(float)*num_buffs*buf_size), cudaMemcpyDeviceToHost);
  }
cudaFree(buf_gpu);
}

明らかに、cudaMemcpy行は、カーネル操作から保存する必要がある実際に生成されたデータである必要があるだけです。

于 2013-09-02T16:31:20.843 に答える