処理時間の計測とプロファイリング

処理が周期内に収まらない、応答がときどき遅れるなどの症状は、推測だけで議論しても原因の特定には近づきません。組み込みシステムの性能問題は、計測してはじめて実態が見えます。

この記事では、何を計測対象に据えるかの決め方から、代表的な計測手法の使い分け、計測そのものに潜む誤差、そして計測を開発プロセスに定着させる方法まで説明します。

なお、この記事では、CPUクロックサイクルを数える機能を「サイクルカウンタ」、周辺回路のタイマを連続カウント動作させて時刻基準に用いるものを「フリーランタイマ」と呼びます。

何を計測するかを決める

手法を選ぶ前に、知りたい指標を明確にします。何を測るかが曖昧なまま計測を始めると、データは集まっても判断につながりません。

実行時間・周期・ジッタ・割り込みレイテンシ

一口に処理時間といっても、指標は複数あります。

この記事では、「実行時間」=処理がCPUを使用している時間、「応答時間」=起動要求から処理完了までの経過時間、「周期」=周期処理の起動時刻間隔、「ジッタ」=目標周期に対する起動時刻の偏差、「割り込みレイテンシ」=割り込み要求から処理開始までの遅延、と定義しています。

このうち割り込みレイテンシは、CPUのパイプライン構成、例外エントリ時のコンテキスト保存、割り込みマスク区間の長さなどに左右されます。さらに、割り込み優先度、割り込みネスト、メモリ待ち、バス競合などによっても変動します。

先にあげた指標は、それぞれ別の問題を映し出します。たとえばモータ制御では、平均的な実行時間が短くても周期のジッタが大きければ制御品質が落ちます。通信処理の場合は、割り込みレイテンシの大きさが取りこぼしの直接的な原因です。症状がどの計測項目の悪化として現れているのかを先に切り分けることで、計測するべき場所が定まります。

平均値か最悪値か

リアルタイム性が求められるシステムでは、平均実行時間だけでなく、締め切りに対して最悪実行時間または最悪応答時間を評価します。RTOSを用いる場合は、処理そのものの実行時間に加え、プリエンプション、割り込み、ロック待ち、優先度逆転などによる待ち時間も含めて評価します。締め切りを満たせるかは、観測された平均値ではなく、想定するすべての条件での最悪応答時間が締め切り以内に収まるかで決まるためです。

ただし、最悪値の把握は簡単ではありません。分岐条件やキャッシュの状態、割り込みの重なり方によって実行時間は変動し、テストで観測した最大値が真の最悪値である保証はないからです。

実務では、負荷や入力条件を意図的に厳しくして最悪に近い状況を作り、観測値に余裕を上乗せして評価します。より高い保証が求められる分野では、対象ハードウェアとソフトウェア構成をモデル化したWCET(Worst-Case Execution Time)の静的解析(静的タイミング解析)により、最悪実行時間の安全側の上界を評価する方法を検討します。

保証の成立には、ループ上限、外部関数、割り込み、キャッシュ、メモリ待ち、DMAなどを解析条件として適切に扱うことが必要です。また、静的解析と計測を組み合わせるハイブリッドな方法もあります。

計測手法の使い分け

指標が決まったら手法を選びます。精度、非侵入性、準備の手間はそれぞれトレードオフの関係にあるため、目的に応じて組み合わせるのが現実的です。

入出力ピンのトグル+オシロスコープ/ロジックアナライザ

GPIO端子とオシロスコープで処理時間を計測する図。MCUは処理開始でGPIO端子の出力をHighにし、処理終了でLowに戻す。オシロスコープの波形でHighの期間を測ると、その長さが処理時間になることを示している。

計測区間の入口で出力ピンをHighに、出口でLowにして、波形をオシロスコープやロジックアナライザで観測する方法です。

GPIOのトグルは実機で視覚的に確認しやすい手法です。周期の揺らぎや処理同士の重なりを波形として直感的に確認でき、複数のピンを使えば割り込みとメイン処理の前後関係も一目でわかります。

ただし、GPIOレジスタへのアクセス時間やピン変化までの遅延は、マイコンのバス構成、周辺回路、コンパイラ最適化などの影響を受けます。短い区間を計測する場合は、GPIO操作そのもののオーバーヘッドを別途確認し、必要に応じて補正します。それでも、実機で手軽に始められる第一の選択肢です。

コア内蔵サイクルカウンタによる高精度計測

プロセッサコアの中には、デバッグ用の機構としてサイクルカウンタが用意されているものがあり、CPUのクロックサイクルを数え続けています。

  • サイクルカウンタの有無、ビット幅、停止条件、利用に必要な初期設定は、CPUコアおよびマイコンの実装に依存します。使用前に、対象デバイスのリファレンスマニュアルで、サイクルカウンタの搭載有無、計数クロック、低消費電力モード中の動作、デバッグ機能の有効化条件を確認します。

区間の前後でこのサイクルカウンタを読んで差分を取れば、クロック単位の分解能で実行時間を計測できます。外部機材が不要で、短い関数の比較や最適化の効果確認に向いています。サイクルカウンタのビット幅には限りがあり(多くの32ビットマイコンでは32ビット幅)、長い区間ではオーバーフローを考慮することが不可欠です。

フリーランタイマでの区間計測

コア内蔵のサイクルカウンタを持たないマイコンでも、フリーランタイマを区間の入口と出口で読み、差分を取る方法が使えます。考え方はサイクルカウンタと同じで、分解能はフリーランタイマのクロックに依存します。

実装の定石として、フリーランタイマのビット幅と計測区間の長さからオーバーフローの発生を見積もっておきます。符号なし整数の減算を用いると、計測区間がカウンタ周期未満であり、かつオーバーフロー回数が高々1回である条件では、ラップアラウンドを考慮した差分を簡潔に求められます。計測区間がカウンタ周期以上になる可能性がある場合は、オーバーフロー割り込みによる上位桁の拡張、より長いビット幅のタイマ、または別の時刻基準を使用します。

コア内蔵トレース機構とタスク可視化ツールの活用

開発環境によっては、コア内蔵のトレース機構による出力や、タスクの実行状況を可視化するツールを利用できます。これらのツールにより、CPU使用率やタスクごとの実行時間に加え、待ちの発生箇所も把握できます。

リアルタイムOSを使うシステムでは、個々の関数よりもタスク間の干渉や優先度の設計がボトルネックになっているケースが少なくありません。そのため、システム全体を俯瞰できるこの種のツールが切り分けを速める鍵です。

一定間隔またはランダム化した間隔でプログラムカウンタを採取するサンプリングでは、CPU時間を多く消費している関数や処理箇所の割合を統計的に推定できます。一方、個々の呼び出しの実行時間や最大実行時間を直接求める用途には適さないため、必要に応じてイベントトレースや区間計測と併用します。

計測誤差と観測の落とし穴

計測用のコードを入れること自体が実行時間を変える点は、計測結果を読む際の前提として扱います。カウンタの読み出しやピン操作は軽い処理とはいえゼロではなく、短い区間ほど相対的な誤差が大きくなるためです。

また、1回の計測値だけで判断するのは失敗のもとになります。キャッシュの状態や割り込みの入り方で値は毎回変わるため、複数回計測して分布を見ること、平均だけでなく最大値を採取することが原則です。

最適化レベルによって、結果が大きく変わる点にも注意が必要です。リリースと同じビルド設定で計測しなければ、実運用の性能と乖離した値になるためです。計測対象の区間を割り込み禁止にして純粋な実行時間を計測する方法もありますが、禁止区間が長いと他の割り込みを取りこぼすため、区間は最小限にとどめます。純粋な実行時間を測るか、割り込みを含めた実環境での応答時間を測るかも、目的にあわせて使い分けます。

計測を継続的な品質管理に組み込む

計測は一度きりのイベントで終えず、開発の仕組みに組み込むことで価値が持続します。主要な処理に対しては、タイムバジェットと呼ばれる時間予算をあらかじめ割り当てておくと効果的です。これを設けたうえで、実測値が予算を超えたら警告を出すようにすれば、性能の劣化を仕様違反として扱えます。

さらに、実行時間の計測を自動化しておくと、機能追加やリファクタリングによる悪化をコミット単位で検知できます。CI(継続的インテグレーション)や回帰テストで性能を監視する際は、ビルド設定、クロック設定、計測回数、入力データ、温度などの計測条件を固定します。最大値、上位パーセンタイル、許容マージンを含む判定基準を定義し、偶発的な変動による誤検出を抑えます。

計測を開発プロセスに定着させる目的は、悪化した瞬間にその変更を特定できる体制を作ることにあります。

組み込みソフトの世界 トップへ戻る