生成コードでの for
ループの自動並列化
並列 for
ループの反復はターゲット ハードウェアの複数のコアで同時に実行できます。コードのセクションを並列化すると、生成コードの実行速度が大幅に改善される場合があります。parfor ループによる実行速度の改善を参照してください。
MATLAB® コードから C/C++ コードを生成する際に、並列 for
ループを自動的に生成できます。自動並列化は、手動操作なしでシーケンシャル コードをマルチスレッド コードに変換するコンパイラ変換です。
for
ループの自動並列化では、C/C++ ターゲットに対して次のビルド タイプがサポートされます。
MEX
スタティック ライブラリ
ダイナミック リンク ライブラリ
実行可能ファイル
MATLAB Coder アプリを使用した for
ループの並列化
for
ループの自動並列化を有効にするには、MATLAB Coder™ アプリの [コード生成] ステップで、[詳細設定]、[速度]、[自動並列化を有効にする] を選択します。
コマンド ラインでの for
ループの並列化
コマンド ライン インターフェイスを使用して for
ループの並列化を有効にできます。関数 autoparExample
について考えます。
function x = autoparExample(x) %#codegen for i = 10:numel(x) x(i) = sqrt(x(i)); end end
並列 for
ループを自動的に生成するには、次のコマンドを実行します。
cfg = coder.config('lib'); cfg.EnableAutoParallelization = 1; x = rand(1,2000); codegen -config cfg autoparExample -args {x} -report
Code generation successful: View report
生成されたコードとコード洞察の検査
コード生成レポートを開いて検査します。
生成コード
for
ループの上に生成されている Open Multiprocessing (OpenMP) プラグマを確認します。
void autoparExample(double x[2000])
{
int i;
if (!isInitialized_autoparExample) {
autoparExample_initialize();
}
#pragma omp parallel for num_threads(omp_get_max_threads()) private(i)
for (i = 0; i < 1991; i++) {
x[i + 9] = sqrt(x[i + 9]);
}
}
ループの横にある緑色で強調表示されたガターは、コードの並列化される部分を示しています。
コード洞察
[コード洞察] タブの [自動並列化の問題] で、生成されたコードで並列化されなかった for
ループに関する詳細情報を確認できます。
たとえば、特定のコード洞察を確認するには、前のセクションで定義した関数 autoparExample
のコードを再生成します。入力引数に指定するサイズを小さくします。
cfg = coder.config('lib'); cfg.EnableAutoParallelization = 1; x = rand(1,1000); codegen -config cfg autoparExample -args {x} -report
入力引数のサイズが自動並列化のしきい値よりも小さいため、生成されたコードには並列 for
ループは含まれません。コードの並列化されていない部分に関する詳細情報を確認するには、レポートを開いて [コードの洞察]、[自動並列化の問題] をクリックします。
for
ループの自動並列化の無効化
特定のループについて逐次実行の方が優れたパフォーマンスが得られる場合は、そのループの自動並列化を無効にできます。特定の for
ループを並列化しないようにするには、MATLAB コードでそのループの直前に coder.loop.parallelize('never')
プラグマを配置します。このプラグマは、EnableAutoParallelization
設定をオーバーライドします。また、このプラグマは MATLAB コードで明示的に定義されている for
ループのみをサポートします。明示的なループと暗黙的なループの詳細については、次のセクションを参照してください。
たとえば、コード ジェネレーターは次のループを並列化しません。
% Pragma to disable automatic parallelization of for-loops coder.loop.parallelize('never'); for i = 1:n y(i) = y(i)*sin(i); end
coder.loop.parallelize
を参照してください。
暗黙的な for
ループの並列化
前のセクションで使用したサンプル関数 autoparExample
には明示的な for
ループが含まれています。しかし、MATLAB コードには、作成したコードに明示的に表示されない暗黙的な for
ループを含めることもできます。たとえば、MATLAB 関数 mtimes
は 2 つの行列を乗算するため、行列の要素に対してループ反復を暗黙的に実行する必要があります。
自動並列化では MATLAB コード内で暗黙的なループがサポートされます。たとえば、以下の関数 autoparExample_implicit
を考えます。
function y = autoparExample_implicit(y) %#codegen y = y * 17; % Generates implicit for loop end
次のコマンドを実行してコードを生成します。
cfg = coder.config('lib'); cfg.EnableAutoParallelization = 1; y = rand(1,2000); codegen -config cfg autoparExample_implicit -args {y} -report
レポートを開き、生成されたコードを検査します。生成されたコードには、乗算演算の並列 for
ループが含まれています。
void autoparExample_implicit(double y[2000])
{
int i;
if (!isInitialized_autoparExample_implicit) {
autoparExample_implicit_initialize();
}
#pragma omp parallel for num_threads(omp_get_max_threads()) private(i)
for (i = 0; i < 2000; i++) {
y[i] *= 17.0;
}
リダクション演算を実行する for
ループの並列化
リダクション演算を実行する for
ループを並列化するには、構成オプション [リダクションの最適化] を使用します。
このような for
ループの自動並列化を有効にするには、次のようにします。
MATLAB Coder アプリを開きます。
[コード生成] ページで、[詳細設定] をクリックします。
[速度] タブの [自動並列化を有効にする] チェック ボックスと [リダクションの最適化] チェック ボックスを選択します。
[リダクションの最適化] は、[ターゲット ハードウェアの命令セット拡張を活用] パラメーターをプロセッサでサポートされる命令セットに設定した場合も有効になります。
コマンド ライン インターフェイスを使用して構成オプション OptimizeReductions
を有効にするには、次のコマンドを実行します。
cfg = coder.config('lib');
cfg.EnableAutoParallelization = true;
cfg.OptimizeReductions = true;
たとえば、配列 in1
の要素の合計を sum
で計算してリダクション変数 out
を返す MATLAB 関数 arraySum
を記述します。
function out = arraySum(in1,a,b) sum = 0; c = zeros(numel(in1),1); for i2 = 1:numel(in1) if i2 > in1(i2) sum = sum + in1(i2); c(i2) = a(i2) + b(i2); end end out = sum + mean(c); end
MATLAB コマンド ラインで、次の codegen
コマンドを実行します。
arr = 1:1000; codegen arraySum -config cfg -args {arr,arr,arr} -report
Code generation successful: View report
[レポートの表示] をクリックしてコード生成レポートを開き、加算演算の並列化された for
ループを確認します。
sum = 0.0; #pragma omp parallel num_threads(omp_get_max_threads()) private(sumPrime, d) { sumPrime = 0.0; #pragma omp for nowait for (i2 = 0; i2 < 1000; i2++) { c[i2] = 0.0; d = in1[i2]; if ((double)i2 + 1.0 > d) { sumPrime += d; c[i2] = a[i2] + b[i2]; } } omp_set_nest_lock(&autoparExample_nestLockGlobal); { sum += sumPrime; } omp_unset_nest_lock(&autoparExample_nestLockGlobal); }
使用に関するメモと制限
空のループおよび
while
ループは自動的に並列化されないコード生成で自動並列化をサポートするのは、算術リダクション演算の加算 (+)、減算 (-)、乗算 (*) と論理演算子 AND (&)、OR ( | ) のみです。
参考
parfor
| coder.loop.parallelize
| coder.config
| coder.MexCodeConfig
| coder.CodeConfig
| coder.EmbeddedCodeConfig