メインコンテンツ

スタック領域使用量の制御

コンパイラまたはハードウェアによって使用される最大スタック サイズを制御できます。スタックとは、プログラム実行用のローカル変数を格納するメモリのブロックです。スタック メモリはコード生成時に割り当てられます。通常、スタックの割り当てでは静的な割り当てよりも効率的にメモリが使用されます。

構成パラメーター [最大スタック使用量] の値はバイト単位で測定されます。ターゲット ハードウェア設定とコード内の可能な実行パスの情報に基づいて、この最大値で対応可能なスタック変数がコード ジェネレーターによって推定されます。この推定では、C/C++ コンパイラによるスタック サイズの変更は考慮されません。スタック メモリに収まらない変数は、スタックからあふれます。スタックからあふれた変数は、静的メモリに格納されるか、再呼び出し可能なコードを生成する場合はスピル構造体に格納されます。

スタック領域使用量を制御するために、次のことが可能です。

  • [最大スタック使用量] パラメーターの値を大きくすると、スタック メモリに割り当てられる変数の数が増えます。ターゲット ハードウェアに十分なスタック領域がある場合は、これによってスタックからあふれる変数の数が減ります。

  • [最大スタック使用量] パラメーターの値を小さくすると、スタック メモリに割り当てられる変数の数が減ります。ターゲット ハードウェアに十分なスタック領域がない場合は、これによってスタックからあふれる変数の数が増えます。

スタックに収まらない再帰関数内の変数は、静的メモリまたはスピル構造体に格納されません。再帰関数内の変数は、スタック使用量サイズを超えてもスタックからあふれません。同様に、コード生成では、coder.ceval の呼び出しにおけるカスタム コードのスタック使用量は考慮されません。

以下の場合に最大スタック使用量を設定します。

  • 組み込みターゲットなどで、スタック領域が制限されている場合。

  • C/C++ コンパイラで実行時スタック オーバーフローがレポートされる。

MATLAB Coder アプリを使用したスタック領域使用量の制御

  1. MATLAB® Coder™ ツールストリップで、[ビルド タイプ] を [MEX]、[スタティック ライブラリ]、[ダイナミック ライブラリ]、または [実行可能ファイル] に設定します。

  2. MATLAB Coder ツールストリップの [設定] タブをクリックします。

  3. [メモリ] タブで、[最大スタック使用量] を必要な値に設定します。

コマンド ラインでのスタック領域の使用量の制御

  1. 構成オブジェクトを作成するには、引数 libmexdll、または exe を指定して coder.config を使用します。以下に例を示します。

    cfg = coder.config("lib");
  2. StackUsageMax プロパティを求める値に設定します。

    cfg.StackUsageMax=400000;

あふれた変数のないコードの生成

スタック領域が十分であれば、生成コードにあふれた変数は必要ありません。

次の MATLAB 関数を考えてみます。

function y = fooNorm(x)
    b = cast(x,'uint32');
    y = sum(b);
end

十分なスタック領域があるシステムで、入力引数 x を 100 行 100 列の double の行列として指定して C コードを生成します。

in = ones(100,100);
cfg = coder.config('lib');
cfg.StackUsageMax = 400000;
 
codegen fooNorm -args {in} -config cfg -report

生成される C 関数 fooNorm は、変数 b_x[10000] をスタックで宣言します。

void fooNorm(const double x[10000], double y[100])
{
  unsigned int b_x[10000];
  ...
}
void main_fooNorm(void)
{
  double dv[10000];
  double y[100];
  argInit_100x100_real_T(dv);
  fooNorm(dv, y);
}

あふれた変数のあるコードの生成

次のコマンドを使用して、[最大スタック使用量] パラメーターの値を減らして同じ MATLAB 関数のコードを生成します。

in = ones(100,100);
cfg = coder.config('lib');
cfg.StackUsageMax = 400;
 
codegen fooNorm -args {in} -config cfg -report

b_x[10000] はスタックに収まらないため、生成コードにおいて静的変数として定義されます。

void fooNorm(const double x[10000], double y[100])
{
  static unsigned int b_x[10000];
  ...
}
void main_fooNorm(void)
{
  static double dv[10000];
  static double y[100];
  argInit_100x100_real_T(dv);
  fooNorm(dv, y);
}

あふれた変数のある再呼び出し可能なコードの生成

次のコマンドを使用して、スタック領域が十分でない状態で同じ MATLAB 関数 fooNorm再呼び出し可能なコードを生成します。

in = ones(100,100);
cfg = coder.config('lib');
cfg.StackUsageMax = 400;
cfg.MultiInstanceCode = true;
codegen fooNorm -args {in} -config cfg -report

生成される C コードは次のようになります。

void fooNorm(fooNormStackData *SD, const double x[10000], double y[100])
{
  int i;
  for (i = 0; i < 10000; i++) {
    double d;
    ...
}

fooNorm への入力は構造体 fooNormStackData です。再呼び出し可能なコードを生成すると、変数がスタックからあふれる場合に、スタックに収まらない変数を保持するスピル構造体が生成されます。

void main_fooNorm(void)
{
  static fooNormStackData fooNormStackDataGlobal;
  static double dv[10000];
  static double y[100];
  argInit_100x100_real_T(dv);
  fooNorm(&fooNormStackDataGlobal, dv, y);
}

構造体 fooNormStackData は次のように定義されます。

typedef struct {
  unsigned int x[10000];
} b_fooNorm;

typedef struct {
  b_fooNorm f0;
} fooNormStackData;

参考

トピック