Main Content

生成コードでの for ループの自動並列化

並列 for ループの反復はターゲット ハードウェアの複数のコアで同時に実行できます。コードのセクションを並列化すると、生成コードの実行速度が大幅に改善される場合があります。parfor ループによる実行速度の改善を参照してください。

MATLAB® コードから C/C++ コードを生成する際に、並列 for ループを自動的に生成できます。自動並列化は、手動操作なしでシーケンシャル コードをマルチスレッド コードに変換するコンパイラ変換です。

for ループの自動並列化では、C/C++ ターゲットに対して次のビルド タイプがサポートされます。

  • MEX

  • スタティック ライブラリ

  • ダイナミック リンク ライブラリ

  • 実行可能ファイル

MATLAB Coder アプリを使用した for ループの並列化

for ループの自動並列化を有効にするには、MATLAB Coder™ アプリの [コード生成] ステップで、[詳細設定]、[速度]、[自動並列化を有効にする] を選択します。

GUI for Enable Automatic Parallelization

コマンド ラインでの 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]);
  }
}

ループの横にある緑色で強調表示されたガターは、コードの並列化される部分を示しています。

Highlighted parallel for loops

コード洞察

[コード洞察] タブの [自動並列化の問題] で、生成されたコードで並列化されなかった for ループに関する詳細情報を確認できます。

たとえば、特定のコード洞察を確認するには、前のセクションで定義した関数 autoparExample のコードを再生成します。入力引数に指定するサイズを小さくします。

cfg = coder.config('lib');
cfg.EnableAutoParallelization = 1;
x = rand(1,1000);
codegen -config cfg autoparExample -args {x} -report

入力引数のサイズが自動並列化のしきい値よりも小さいため、生成されたコードには並列 for ループは含まれません。コードの並列化されていない部分に関する詳細情報を確認するには、レポートを開いて [コードの洞察]、[自動並列化の問題] をクリックします。

Code insights about non-parallelized part of the code

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 ループの自動並列化を有効にするには、次のようにします。

  1. MATLAB Coder アプリを開きます。

  2. [コード生成] ページで、[詳細設定] をクリックします。

  3. [速度] タブの [自動並列化を有効にする] チェック ボックスと [リダクションの最適化] チェック ボックスを選択します。

MATLAB Coder snapshot of Optimize reductions

[リダクションの最適化] は、[ターゲット ハードウェアの命令セット拡張を活用] パラメーターをプロセッサでサポートされる命令セットに設定した場合も有効になります。

コマンド ライン インターフェイスを使用して構成オプション 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);
  }

使用に関するメモと制限

参考

| | | | |

関連するトピック