OpenCL API 実行モデルでは、データ並列とタスク並列のプログラミング モデルがサポートされます。OpenCL ホストは通常、異なるカーネルを複数回呼び出す必要があります。これらの呼び出しは、特定のシーケンスまたは順不同コマンド キューのいずれかでコマンド キューに入れられます。このあと、計算リソースとタスク データがどれだけ使用可能かによって、デバイス上での実行がスケジュールされます。
カーネル呼び出しは、clEnqueueTask
を使用してコマンド キューで実行されるようにキューに入ります。送信プロセスがホスト プロセッサで実行されます。送信元が、カーネル引数をデバイス上で実行されているアクセラレータに転送した後、カーネル実行を呼び出します。送信元は、下位レベルのザイリンクス ランタイム (XRT) ライブラリを使用して、カーネル引数を転送し、計算を開始するためのトリガー コマンドを発行します。アクセラレータへのコマンドおよび引数の送信のオーバーヘッドは、カーネルの引数セットの数によって 30 µs ~ 60 µs になります。このオーバーヘッドの影響は、カーネルを実行する必要のある回数と clEnqueueTask
への呼び出しを最低限に抑えると減らすことができます。理想的なのは、すべての計算が clEnqueueTask
の呼び出し 1 つで終了するようにすることです。
データをバッチ処理してカーネルを 1 回呼び出すと、clEnqueueTask
への呼び出しを最小限に抑えることができます。ループは元のインプリメンテーションにラップされ、複数のエンキュー呼び出しのオーバーヘッドを回避できます。また、多数の小さなデータ パケットではなく、少数の大きなデータ パケットを転送することで、ホストとアクセラレータ間のデータ転送パフォーマンスを向上させることもできます。カーネル実行のオーバーヘッド削減の詳細は、カーネル実行 を参照してください。
#define SIZE 256
extern "C" {
void add(int *a , int *b, int inc){
int buff_a[SIZE];
for(int i=0;i<size;i++)
{
buff_a[i] = a[i];
}
for(int i=0;i<size;i++)
{
b[i] = a[i]+inc;
}
}
}
num_batches
引数によっては、カーネルは 1 回の呼び出しで 256 のサイズの入力を複数処理し、複数の clEnqueueTask
呼び出しのオーバーヘッドを回避できます。ホスト アプリケーションは、データとバッファーを SIZE *
num_batches
のチャンク単位で割り当てるように変更し、メモリ割り当てとホスト グローバル メモリおよびデバイス メモリ間のデータ転送をバッチ処理します。#define SIZE 256
extern "C" {
void add(int *a , int *b, int inc, int num_batches){
int buff_a[SIZE];
for(int j=0;j<num_batches;j++)
{
for(int i=0;i<size;i++)
{
buff_a[i] = a[i];
}
for(int i=0;i<size;i++)
{
b[i] = a[i]+inc;
}
}
}
}