clEnqueueMigrateMemObjects の使用 - 2020.1 Japanese

Vitis 統合ソフトウェア プラットフォームの資料: アプリケーション アクセラレーション開発 (UG1393)

Document ID
UG1393
Release Date
2020-08-20
Version
2020.1 Japanese
重要: エンベデッド プラットフォームの場合、CL_MEM_USE_HOST_PTRclEnqueueMigrateMemObjects を適用できません。エンベデッド プラットフォーム ユーザーは、clEnqueueMapBuffer の使用 で説明するように clEnqueueMapBuffer を使用する必要があります。

OpenCL フレームワークには、ホストとデバイス間でデータを転送するための API が多く含まれます。通常は、clEnqueueWriteBuffer および clEnqueueReadBuffer などのデータ移動 API でメモリ オブジェクトがキューに追加された後に暗示的にデバイスへ移動されますが、そのタイミングは決められないので、ホスト アプリケーションがメモリ オブジェクトの移動とデータで実行された計算を同期しにくくなります。

ザイリンクスでは、パフォーマンスを向上するために、clEnqueueWriteBuffer または clEnqueueReadBuffer の代わりに clEnqueueMigrateMemObjects を使用することをお勧めしています。メモリ移動が依存コマンドよりも前に明示的に実行されるようにできます。これにより、ホスト アプリケーションが通常のコマンド キューのスケジュールを使用して次の別のコマンドの準備ができるように、前もってメモリ オブジェクトの関連付けを変更できます。また、メモリ オブジェクトが必要となる前にその配置とその他の関連しない演算をオーバーラップさせて、発生する可能性のある転送レイテンシを隠したり、削減することもできます。clEnqueueMigrateMemObjects と関連するイベントが complete とマークされると、メモリ オブジェクトが問題なく移行できたことがホスト プログラムに伝わります。

cl_mem オブジェクトには、ホスト側ポインターとデバイス側ポインターの主に 2 つのポインターがあります。デバイス側ポインターは、カーネルが動作を開始する前に、デバイス側のメモリに暗示的に割り当てられる (たとえば、デバイスのグローバル メモリ内の特定位置に割り当てられる) ので、バッファーがデバイスに含まれるようになりますが、clEnqueueMigrateMemObjects を使用すると、この割り当てとデータ転送が前もって、カーネル実行よりもかなり前に発生するようになります。こうすることで、カーネルがまだ前のデータ セットを処理している間に次のトランザクションのデータ転送を実行して、連続するカーネル実行のデータ転送レイテンシを隠すことができるので、ホストが同じカーネルを何度も実行する場合に、「ソフトウェア パイプライン」をイネーブルにするのに特に役立ちます。

ヒント: また、clEnqueueMigrateMemObjects には、複数のメモリ オブジェクトを 1 つの API 呼び出しに移動できるという利点もあります。これにより、メモリ オブジェクトが複数ある場合のデータ転送のスケジューリングおよび関数呼び出しのオーバーヘッドが削減します。

次のコードは、clEnqueueMigrateMemObjects を使用したところを示しています。

int host_mem_ptr[MAX_LENGTH]; // host memory for input vector
      
// Fill the memory input
for(int i=0; i<MAX_LENGTH; i++) {
  host_mem_ptr[i] = <... >   
}

cl_mem dev_mem_ptr = clCreateBuffer(context,  
    				 CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR,
    				 sizeof(int) * number_of_words, host_mem_ptr, NULL); 

clSetKernelArg(kernel, 0, sizeof(cl_mem), &dev_mem_ptr); 

err = clEnqueueMigrateMemObjects(commands, 1, dev_mem_ptr, 0, 0, 
	  NULL, NULL);