8

私は OpenCL の初心者で、何かを理解するのに苦労しています。ホストとデバイス間のイメージの転送を改善したいと考えています。私は私をよりよく理解するために計画を立てました。

上: 私が今持っているもの | 下: HtD (ホストからデバイスへ) と DtH (デバイスからホストへ) はメモリ転送です。K1 と K2 はカーネルです。

マッピング メモリを使用することを考えましたが、最初の転送 (ホストからデバイスへ) は clSetKernelArg() コマンドで行われますね。または、入力画像をサブ画像に切り取り、マッピングを使用して出力画像を取得する必要がありますか?

ありがとう。

編集:詳細情報

K1 プロセス メモリ入力イメージ。K2 は、K1 からの出力イメージを処理します。

そこで、MemInput を K1 用にいくつかに分けて転送したいと思います。そして、K2 によって処理された MemOuput を読み取り、ホストに保存したいと考えています。

4

4 に答える 4

7

既にご覧になったように、ホストからデバイスへの転送は などを使用してclEnqueueWriteBuffer行います。

キーワード 'enqueue' を含むすべてのコマンドには、特別なプロパティがあります。コマンドは直接実行されませんが、 、 、 、ブロッキング モードでの使用などを使用してトリガーすると実行clFinishclFlushれますclEnqueueWaitForEventsclEnqueueWriteBuffer

これは、すべてのアクションが一度に発生し、イベント オブジェクトを使用して同期する必要があることを意味します。すべてが一度に発生する可能性があるため、次のようなことができます (各ポイントは同時に発生します)。

  1. 転送データA
  2. プロセスデータA & 転送データB
  3. データ B を処理 & データ C を転送 & データ A' を取得
  4. データ C を処理 & データ B' を取得
  5. データ取得 C'

覚えておいてください: Event-Object なしでタスクをキューに入れると、キューに入れられたすべての要素が同時に実行される可能性があります!

プロセス データ B が転送 B の前に発生しないようにするには、イベント オブジェクトを取得し、clEnqueueWriteBufferそれを待機するオブジェクトとして提供する必要があります。clEnqueueNDRangeKernel

cl_event evt;
clEnqueueWriteBuffer(... , bufferB , ... , ... , ... , bufferBdata , NULL , NULL , &evt);
clEnqueueNDRangeKernel(... , kernelB , ... , ... , ... , ... , 1 , &evt, NULL);

もちろん、NULL を指定する代わりに、各コマンドは特定のオブジェクトを待機し、新しいイベント オブジェクトを生成できます。最後の次のパラメーターは配列なので、複数のイベントをイベント待機できます。


編集: 以下のコメントを要約するには データの転送- どのコマンドがどこで機能しますか?

       CPU GPU 
                            BufA        BufB
配列[] = {...}
clCreateBuffer() ----->   [ ]               //GPU メモリに (空の) バッファを作成 *
clCreateBuffer() -----> [ ]     [ ]    //GPU メモリに (空の) バッファを作成 *
clWriteBuffer() -arr-> [ array ] [ ] //CPU から GPU にコピー
clCopyBuffer() [配列] -> [配列] //GPU から GPU にコピー
clReadBuffer() <-arr- [array] [array] //GPU から CPU にコピー

* パラメータを使用してデータを提供することにより、バッファを直接初期化host_ptrできます。

于 2012-09-12T13:48:58.833 に答える
3

多くの OpenCL プラットフォームは、順不同のコマンド キューをサポートしていません。ほとんどのベンダーが重複した DMA とコンピューティングを行う方法は、複数の (順序どおりの) コマンド キューを使用することです。イベントを使用して、依存関係が正しい順序で行われるようにすることができます。NVIDIA には、オーバーラップした DMA と計算を示すサンプル コードがあります (ただし、最適ではありませんが、彼らが言うよりもわずかに速くなる可能性があります)。

于 2012-10-15T00:13:02.503 に答える
2

適切な方法 (私が行っているように、完全に機能している) は、2 つのコマンド キューを作成することです。1 つは I/O 用で、もう 1 つは処理用です。両方が同じコンテキストにある必要があります。

イベントを使用して両方のキューのスケジュールを制御でき、操作は並行して実行されます (可能な場合)。デバイスが outoforderqueue をサポートしていなくても、実際に機能します。

たとえば、I/O キュー内の 100 個の画像すべてを GPU にエンキューして、それらのイベントを取得できます。次に、このイベントをカーネルのトリガーとして設定します。また、DtoH 転送はカーネル イベントによってトリガーされます。このすべてのジョブを一度にキューに入れても、それらは順番に並列 I/O で処理されます。

于 2013-01-16T23:02:42.523 に答える
2

コマンド キューを作成するときは、プロパティで順不同の実行を有効にする必要があります。参照: CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE、clCreateCommandQueue

これにより、タスクの小さなチェーンを設定し、それらを相互にリンクできます。これはすべてホスト上で行われます。

ホスト疑似コード:

for i in taskChainList
  enqueueWriteDataFromHost
  enqueueKernel(K1)
  enqueueKernel(K2)
  enqueueReadFromDevice
clfinish

タスクをキューに入れるときは、前の cl_event を各タスクの event_wait_list に入れます。上記の「enqueueWriteDataFromHost」は、別のイベントが始まるのを待つ必要はありません。

あるいは、

cl_event prevWriteEvent;
cl_event newWriteEvent;
for i in taskChainList
  enqueueWriteDataFromHost // pass *prevWriteEvent as the event_wait_list, and update with newWriteEvent that the enqueue function produces. Now each Write will wait on the one before it.
  enqueueKernel(K1)
  enqueueKernel(K2)
  enqueueReadFromDevice  //The reads shouldn't come back out of order, but they could (if the last block of processing were much faster then the 2nd-last for example)
clfinish
于 2012-09-12T18:45:39.100 に答える