Nvidia GPU で を呼び出すclEnqueueNDRange
と、プログラムは処理が完了するまで待機してから続行します。より正確には、同等の C++ バインディングを呼び出してCommandQueue::enqueueNDRange
いますが、これは違いはありません。これは、リモートの Nvidia ハードウェア (3 台の Tesla M2090) でのみ発生します。AMD GPU を搭載したオフィスのワークステーションでは、呼び出しはノンブロッキングで、すぐに戻ります。テストするローカルの Nvidia ハードウェアがありません。以前は使用していましたが、そのときも同様の動作を覚えていますが、少し曖昧です。
これにより、複数の GPU に作業を分散することが難しくなります。std::async
新しい C++11 仕様で/を使用して enqueueNDRange への呼び出しごとに新しいスレッドを開始しようとしましたstd::finish
が、それも機能していないようです - nvidia-smi で GPU 使用率を監視すると、メモリ使用量がGPU 0 が上がると、何らかの作業が行われ、次に GPU 0 のメモリが下がり、GPU 1 のメモリが増え、それが何らかの作業を行います。私の gcc バージョンは 4.7.0 です。
カーネルを開始する方法は次のとおりです。インクリメントは、目的のグローバル作業サイズをデバイス数で割ったもので、目的のローカル作業サイズの最も近い倍数に切り上げられます。
std::vector<cl::CommandQueue> queues;
/* Population of queues happens somewhere
cl::NDrange offset, increment, local;
std::vector<std::future<cl_int>> enqueueReturns;
int numDevices = queues.size();
/* Calculation of increment (local is gotten from the function parameters)*/
//Distribute the job among each of the devices in the context
for(int i = 0; i < numDevices; i++)
{
//Update the offset for the current device
offset = cl::NDRange(i*increment[0], i*increment[1], i*increment[2]);
//Start a new thread for each call to enqueueNDRangeKernel
enqueueReturns.push_back(std::async(
std::launch::async,
&cl::CommandQueue::enqueueNDRangeKernel,
&queues[i],
kernels[kernel],
offset,
increment,
local,
(const std::vector<cl::Event>*)NULL,
(cl::Event*)NULL));
//Without those last two casts, the program won't even compile
}
//Wait for all threads to join before returning
for(int i = 0; i < numDevices; i++)
{
execError = enqueueReturns[i].get();
if(execError != CL_SUCCESS)
std::cerr << "Informative error omitted due to length" << std::endl
}
カーネルは への呼び出しで確実に実行されているはずですstd::async
。小さなダミー関数を作成し、GDB でブレークポイントを設定して、std::async
呼び出された瞬間にステップインさせることができるからです。しかし、enqueueNDRangeKernel のラッパー関数を作成し、そこで実行し、実行後に print ステートメントを挿入すると、出力の間に時間がかかることがわかります。
PS Nvidia dev ゾーンがハッカーなどによってダウンしているため、そこに質問を投稿できませんでした。
編集:言及するのを忘れました-引数としてカーネルに渡しているバッファー(および、上記で言及した、GPU間で渡されるように見えるバッファー)は、CL_MEM_COPY_HOST_PTRを使用して宣言されています。同じ効果が発生して、CL_READ_WRITE_BUFFERを使用していました。