スタック使用量解析
このページでは、リンカを使用したスタック使用量解析の実行方法を説明します。
arm\src ディレクトリに、スタック使用量解析を実演したサンプルプロジェクトがあります。
スタック使用量解析の概要
適切な状況下では、リンカによってプログラムの開始から割り込み関数、タスクなどの順に、各コールグラフの最大スタック使用量が正確に計算されます(別の関数から呼び出されない各関数、つまりルート)。
スタック使用量解析を有効にすると、リンカマップファイルにスタック使用の項目が追加され、各コールグラフルートについてスタック深さの最大値になる特定のコールチェーンが一覧表示されます。
この解析は、アプリケーション内の各関数に正確なスタック使用情報がある場合にのみ正確となります。
一般的には、コンパイラは各C関数についてこの情報を生成しますが、間接的な呼び出し(関数ポインタを使用した呼び出し)がアプリケーション内にある場合、各呼び出しコール関数から呼び出しが可能な関数のリストを提供する必要があります。
スタック使用解析制御ファイルを使用する場合、スタック使用情報を持たないモジュール内の関数のスタック使用情報も提供できます。
リンカが計算したスタック使用量が割り当てたスタックエリアを超えないか確認するために、スタック使用量制御ファイルでcheck that ディレクティブを使用できます。
スタック使用量解析の実行
スタックの使用量解析の有効化:
注意
IDEで[プロジェクト]>[オプション]>[リンカ]>[アドバンスト]>[スタックの使用量解析を有効にする]を選択します。
リンカマップファイルの有効化:
注意
IDEで[プロジェクト]>[オプション]>[リンカ]>[リスト]>[リンカマップファイルの表示]を選択します。
危険
コマンドラインでは、リンカオプション
‑‑mapを使用します。プロジェクトをリンクします。
注: 特定の状況ではリンカはスタック使用量に関するワーニングを発します(ワーニングが発行される状況を参照)。
リンカマップファイルを確認します。これには各コールグラフルートのスタック使用量の概要が記載されたスタック使用量の章が含まれています。詳細については、解析結果 — マップファイルの内容を参照してください。
詳しくはコールグラフのログを解析してください(コールグラフログを参照)。
注: 解析には制限および不正確となる要因があります(制限を参照)。
より正確な結果を得るには、リンカでさらに多くの情報を指定しなければならないことがあります。追加のスタック使用量情報の指定を参照してください。
注意
IDEで[プロジェクト]>[オプション]>[リンカ]>[アドバンスト]>[スタックの使用量解析を有効にする]>[制御ファイル]を選択します。
スタックに十分なメモリを割り当てたかどうかの自動チェックを追加するには、リンカ設定ファイルの
check thatディレクティブを使用します。たとえば、MY_STACKというスタックブロックがある場合、次のように記述できます。check that size(block MY_STACK) >=maxstack("Program entry") + totalstack("interrupt") + 100;リンクする際、チェックに失敗するとリンカはエラーを発します。この例では、以下の合計が
MY_STACKblockのサイズを超過した場合にエラーが表示されます:カテゴリ
Program entry(メインプログラム)の最大スタック使用量。カテゴリ
interruptの個々の最大スタック使用量の合計(すべての割り込みルーチンが同時に空間を必要とすると想定した場合)。100バイトの安全マージン(解析で分からないスタック使用量を想定)。
check thatディレクティブおよびスタックについてを参照してください。
解析結果 — マップファイルの内容
スタック使用量の解析が有効な場合、リンカマップファイルにはスタック使用量の項目が含まれ、それに各コールグラフルートカテゴリにスタック使用量のサマリも含まれます。さらに、各コールグラフルートについて、最大スタック深度となるコールチェーンがリストされます。以下は、マップファイルにおけるスタック使用の章の一例です。
*****************************************************************
*** STACK USAGE
***
Call Graph Root Category Max Use Total Use
‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑ ‑‑‑‑‑‑- ‑‑‑‑‑‑‑‑-
interrupt 104 136
Program entry 168 168
Program entry
"__iar_program_start": 0x000085ac
Maximum call chain 168 bytes
"__iar_program_start" 0
"__cmain" 0
"main" 8
"printf" 24
"_PrintfTiny" 56
"_Prout" 16
"putchar" 16
"__write" 0
"__dwrite" 0
"__iar_sh_stdout" 24
"__iar_get_ttio" 24
"__iar_lookup_ttioh" 0
interrupt
"FaultHandler": 0x00008434
Maximum call chain 32 bytes
"FaultHandler" 32
interrupt
"IRQHandler": 0x00008424
Maximum call chain 104 bytes
"IRQHandler" 24
"do_something" in suexample.o [1] 80
サマリには、各カテゴリで最も深いコールチェーンの深度と、そのカテゴリで最も深いコールチェーンの深さの合計が含まれます。
各コールグラフのルートは、check thatディレクティブで便利な計算を有効化するために、コールグラフのルートカテゴリに属します。
制限
スタック使用情報が不足していたり正しくないことのほか、解析が不正確となる他の原因もあります。
リンカは、スタック使用情報を持たないオブジェクトモジュール内のすべての関数を識別できるとは限りません。特に、アセンブリ言語に記述されたオブジェクトモジュールや、IAR以外のツールにより生成されたオブジェクトモジュールで、これが問題になる場合があります。こうしたモジュールにスタック使用量情報を指定するには、スタック使用量制御ファイルを使用したり、アセンブリ言語モジュールの場合は、
CFIディレクティブによりアセンブラソースコードに注釈を付けてスタック使用量情報を付加することも可能です。スタック使用量分析のコールフレーム情報。を参照してください。フレームサイズの変更や関数呼び出しの実行にインラインアセンブラを使用する場合、これは解析には反映されません。
他のソース(プロセッサ、オペレーティングシステムなど)で消費される余分なエリア。
複数ファイルのコンパイル(
--mfc)が、関係するファイルでモジュールローカルの関数のプロパティを指定するときに、スタック使用量制御ファイルの使用に干渉することがあります。
注記
スタック使用量解析は一番悪い場合の結果を生成します。実際にはプログラムは設計上または偶然に最大コールチェーンに到達しない場合もあります。特に、C++での仮想関数呼び出しの一連の宛先には、実際にはコード内のそのポイントから呼び出すことができない関数の実装が含まれることがあります。
警告
スタック使用量解析は、実際の測定に対する補足でしかありません。結果が重要であれば、解析の結果を個別に検証する必要があります。
ワーニングが発行される状況
スタック使用量解析がリンカで有効な場合、次の状況ではワーニングが生成されます。
スタック使用量情報を持たない関数がある。
アプリケーション内に間接的な呼び出し元があり、呼び出される可能性がある関数のリストが提供されていない。
既知の間接的な呼び出しはないが、コールグラフルートで認識されていない呼び出されていない関数がある。
アプリケーションには再帰(コールグラフ内のサイクル)が含まれ、再帰の最大深度が指定されていないか、またはリンカが信頼できるスタック使用量の見積もりを計算できない形式になっている。
コールグラフルートとして制限された関数への呼び出しがある。
スタック使用量制御ファイルを使用して、スタック使用量情報を持たないモジュール内の関数に使用量情報を提供してる。また、そのモジュールが参照している関数で、スタック使用量制御ファイルで呼び出されるように記述されていないものがある。
コールグラフログ
スタック使用量解析の結果を理解しやすくするため、コールグラフのテキストによる単純な表現を生成するログ出力オプションがあります(--log call_graph)。
出力の例:
Program entry:
0 __iar_program_start [168]
0 __cmain [168]
0 __iar_data_init3 [16]
8 __iar_zero_init3 [8]
16 - [0]
8 __iar_copy_init3 [8]
16 - [0]
0 __low_level_init [0]
0 main [168]
8 printf [160]
32 _PrintfTiny [136]
88 _Prout [80]
104 putchar [64]
120 __write [48]
120 __dwrite [48]
120 __iar_sh_stdout [48]
144 __iar_get_ttio [24]
168 __iar_lookup_ttioh [0]
120 __iar_sh_write [24]
144 - [0]
88 __aeabi_uidiv [0]
88 __aeabi_idiv0 [0]
88 strlen [0]
0 exit [8]
0 _exit [8]
0 __exit [8]
0 __iar_close_ttio [8]
8 __iar_lookup_ttioh [0] ***
0 __exit [8] ***各行には次の情報が含まれます。
関数の呼び出しポイントにおけるスタック使用量
関数名、および関数呼び出しのないポイントにおける関数(通常はleaf関数)の使用量を示す、1つの '-' 。
そのポイントから最も深いコールチェーンのスタック使用量。そのポイントから最も深いコールチェーンのスタック使用量。そのような値が計算できないときは、代わりに
"[---]"が出力されます。"***"は、すでに表示された関数を示します。
コールグラフXML出力
また、リンカはXMLフォーマットでコールグラフファイルを生成します。このファイルには、アプリケーション内の各関数ごとに1つのノードと、その関数に特定のスタック使用および呼び出し情報が含まれます。処理後に使用するツールのための入力を意図しており、特に可読というわけではありません。
使用されるXMLフォーマットの詳細については、製品のインストールに含まれるcallGraph.txtファイルを参照してください。