性能解析

ソフトウェア工学における性能解析（せいのうかいせき）または性能分析（せいのうぶんせき）（）とは、動的プログラム解析の一種であり、プログラムの実行を通して情報を収集することでプログラムの性能を解析することを言う。逆にプログラムを実行せずに行う解析を静的コード解析と呼ぶ。性能解析の目的は、実行時間やメモリ使用量を最適化するためにプログラムのどの部分を改良すべきかを決定することである（ボトルネック、アムダールの法則参照）。
プロファイラの利用.
プロファイラ（）は性能解析ツールであり、プログラム実行時の各種情報を収集する。特に、関数呼び出しの頻度やそれにかかる時間を計測する。出力は記録したイベントの羅列（トレース）の場合と、観測したイベント群の統計的要約（プロファイル）の場合がある。プロファイラがデータを収集する技法は様々で、ハードウェアの割り込みを利用する技法、コードに命令を埋め込む技法、オペレーティングシステムのフックを利用する技法、性能カウンタを利用する技法などがある。プロファイラの使用はパフォーマンスエンジニアリングにおいて重要である。
プロファイルは統計的な総和としてソースコードの位置と関連付けてイベントを記録するため、データのサイズは対象となったコードのサイズにほぼ比例する。一方、トレースのサイズはプログラムの実行時間に比例したサイズとなってしまうため、実用的でないこともある。並列性のないプログラムでは、一般にプロファイルで十分だが、並列性のあるプログラムでの性能問題（メッセージ待ちや同期問題）については、イベントが時系列としてどういう順序で発生しているかが重要であるため、完全なトレースを必要とすることが多い。
歴史.
UNIXにおけるプロファイラを使った性能解析は、1979年、"prof" ツールが導入されたころまで遡る。prof は関数毎にかかった時間をリストアップするツールである。1982年、"gprof" によって完全なコールグラフによる解析へと進化した（"Gprof: a Call Graph Execution Profiler" ）。
1994年、ディジタル・イクイップメント・コーポレーションの Amitabh Srivastava と Alan Eustace は ATOM に関する論文を発表した 。ATOM はプログラムをプロファイラに変換するシステムである。つまり、コンパイル時に解析用の命令を挿入して、実行時にその命令によって解析データが出力される。解析対象のプログラム自身に変更を加える技法を "instrumentation"（計測化）とも呼ぶ。
2004年、これまでで最も影響の大きかった論文（ACM SIGPLAN の学会誌 Programming Language Design and Implementation 誌上）20本に Gprof の論文と ATOM の論文が選ばれた 。
データ収集法.
イベントベースのプロファイラ.
以下のプログラミング言語はイベントベースのプロファイラを持つ。
統計的プロファイラ.
プロファイラによってはサンプリングによって情報収集する。サンプリング型プロファイラは、オペレーティングシステムの割り込みを使って、対象プログラムのプログラムカウンタを一定間隔で調べる。サンプリング型のプロファイラは一般に精度が低いが、対象プログラムを通常とほぼ同じ速度で実行させることができる。
プロファイラによっては対象プログラムに情報を収集するための命令を追加するものもある。この場合、プログラムの性能が変化し、結果が不正確になったりするが、詳しい情報を収集することができる。
得られるデータは正確ではないが、統計的な近似になっている。一定間隔でサンプリングしてその時点で実行中だった関数がそのサンプリング間隔の間ずっと動作していたとして実行時間を収集していくのが一般的である。従って、サンプリング間隔が 0.01 秒であれば、実際にその関数が動作していた時間はほとんど 0 から 0.02 秒までありうる。その関数がサンプリングされる回数が多ければ多いほど誤差は小さくなっていく。例えば、サンプリング間隔 0.01 秒である関数の実行時間が 1 秒という結果が得られた場合、サンプリングされた回数 "n" は 100 回であり、誤差はその平方根、つまり 10回（= 0.1秒）と推定される 。性能解析において問題となるのは時間のかかる呼び出し回数の多い関数であるため、このような誤差はあまり問題とはならない。
よく使われる統計的プロファイラとしては、GNUプロジェクトの gprof、Oprofile、シリコングラフィックスの Pixie などがある。
実際の性能解析と性能強化.
逐次型プログラムに無限ループがある場合、問題を発見する最も単純な方法はデバッガを使って一時停止させ（無限ループしている箇所が不明なのでブレークポイントではない）、そのときのコールスタックを調査することである。コールスタック上には呼び出されている関数のアドレスが積まれている。どの関数が無限ループしているかは、シングルステップ実行させてコールスタックの変化を追っていけばわかる。
無限ループでなくとも同様の技法が活用できる。必要に応じて外側にループを追加することで時間のかかっている部分を数秒以上かかるように修正できる。そうしておいて、問題の箇所と思われるタイミングでデバッガによる一時停止を行い、コールスタックを確認する。これを繰り返していくことで何が問題なのか、どこを修正すればよいかが明確化される。
このような性能強化は、プログラムの誤動作を引き起こさないで単に遅くする種類のバグを修正する作業である。このようなバグをスラグ（slug = slowness bug）と呼ぶことがある。プログラムにはバグとスラグが含まれており、ソフトウェアテストによってバグは除去されるが、スラグは性能解析をしないと除去されない。
スラグにはいくつかの種類がある。意図的にプログラムの実行時間を長くするようなやり方は意図せずに行われることもある。最もよくあるスラグはループ内部で実行時間のほとんどを費やす「ホットスポット; hot spot」と言われる種類のものである。例えば、線型探索に時間がかかっている場合、それが二分探索で改善できるなら「ホットスポット」と言える。ホットスポットは必ずしもスラグとはいえないこともある。むしろ、ホットスポットとなっている関数をループ内で何度も呼び出す側の問題であることも多い。
また、別のスラグとして、ある問題に最適でない汎用的すぎるデータ構造を使っているために性能を低下させている場合がある。例えば、要素数が少ないなら、単純な配列による線型探索の方が複雑なハッシュテーブルなどよりも高速である。この種のスラグは、動的メモリ確保および解放に時間がかかっていることで判明することが多い。
別のスラグとして、データベースなどから有益な情報をまとめて収集する強力な関数を作成した場合があげられる。このような関数を何度も使うことで性能低下が発生する。このようなことが発生する要因として不適切なカプセル化が考えられる。
性能解析において、統計的プロファイラの精度はあまり重要ではない。典型的なスラグは実行時間の多くを消費している。従って、細部に拘っても性能は改善されない。また、実際の性能強化においては、スタックトレースなどの情報の方が重要である。