カーネル解析
GPU コード生成では、CUDA® カーネルを作成するための基本となるメカニズムは for
ループを使用することです。MATLAB® コード内でのループの書き方は、作成されるカーネル数と、生成コードのパフォーマンスに大きく影響します。GPU コードを生成する場合、診断レポートをチェックし、ループ セグメントに Loop not parallelized
という注意が表示されているかどうかを確認します。コード内の MATLAB 関数への呼び出しにも、これらの注意が含まれる for
ループがある可能性があります。パフォーマンスを最大化するには、コード内の計算量の多いループ セグメントがカーネルにマッピングされ、並列に実行されていることを確認する必要があります。以降の推奨事項は、この目標を達成し、効率的な CUDA カーネルを生成するのに役立ちます。
カーネルに対する入れ子にされたループのマッピング
条件
入れ子にされた for
ループを含む関数について考えます。
function y = foo(x) ... for i1 = 1:N1 for i2 = 1:N2 for i3 = 1:N3 for i4 = 1:N4 ... end end end end
中間ループの 1 つである i3
を並列化できないとします。ループ解析を実行してカーネルを作成すると、GPU Coder™ では最も外側の並列ループ i1,i2
のみが考慮され、外側のループ次元 N1,N2
のカーネルが作成されます。ループ i3,i4
はカーネル本体内にあり、逐次的に実行されます。ただし、最も内部の i4
が大きい (反復である) 場合、最も内部のループ用にカーネルを作成することで、より優れたパフォーマンスが達成される可能性があります。
操作
次の 3 つの方法で、最も内部のループを並列化することができます。
コードを書き直し、最も内部のコード セグメントが、入れ子にされたループ内に入らないようにします。
外側のループの反復サイズが小さい場合、このループを関数
coder.unroll
に追加します。この関数は、各ループ反復でループ本体のコピーを作成することにより、for
ループを展開します。詳細については、coder.unroll
を参照してください。function y = foo(x) ... for i1 = coder.unroll(1:N1) ... end
外側のループ次元を動的な範囲にします。このようにすると、外側のループでの並列ループ解析は失敗しますが、内側のループでは成功します。
function y = foo(x,N1) ... for i1 = 1:N1 ... end
break を含む for ループ
条件
break を含むループはサポートされません。
while (i < N) ... ... if (cond2) ... ... break; end end
操作
ガード変数および条件を作成して break を削除します。
cond = true; while (i< N) if(cond) ... ... if(cond2) cond = false; end end end
依存性解析の並列ループ チェックの失敗
条件
カーネル抽出では並列ループの依存性解析が使用されます。ループの依存性解析で並列 for ループを検出できない場合があります。coder.gpu.kernel
は、GPU Coder で依存性解析をオーバーライドし、強制的にカーネルを作成できるようにします。注意点として、そのループが反復間で依存関係を持たない "for-all" ループであることを確認する必要があります。
操作
各 for ループに対して明示的に coder.gpu.kernel
プラグマを使用します。
配列の論理インデックス付け
条件
配列要素へのアクセスのために論理インデックスが使用されていない場合、GPU Coder ではカーネルが作成されない可能性があります。
i = (mag ~= 0); vx(i) = vx(i)./mag(i); vy(i) = vy(i)./mag(i);
操作
ループ本体を使用して適切な条件で保護することで、コードを書き換えます。
for i = 1:numel(mag) if (mag(i) ~= 0) vx(i) = vx(i)./mag(i); vy(i) = vy(i)./mag(i); end end
サポートされない関数
条件
サポートされない関数、コーダー プラグマ、ツールボックス関数などをループ内部で使用していると、カーネル化することができなくなります。
操作
純粋な MATLAB を使用して、サポートされない関数を書き換えてみます。
ループの交換
条件
ループの入れ子内で比較的小さいループが最も外側のループになっている場合、その入れ子に含まれているループの一部のみでカーネルが作成される可能性があります。アルゴリズムで許容される場合、常に最も外側の入れ子に最も大きなループを配置してください。
操作
より大きなループをより外側のループにしてループの入れ子を書き換えます。