SOLID未分類 関数トレース(連載16)

関数トレース(連載16)

(2023/10/2)

[連載16] 関数トレース

今回は、関数トレースについてご紹介します。
「ここに至るまでの経緯」を知るための機能です。

 

 

1.トレースとは

デバッガの機能の一つに、トレースの情報を取得する機能があります。
一般的に思いつくのは、ICEにトレースプローブを付ける方法です。
マイコンチップのトレース用端子とトレースアダプタを接続し、そこから分岐情報やバス情報等拾ってトレースを行います。

この場合、トレースの情報を抽出し出力するのは、ハードウェアによって行われるため、どのようなファームウェアに対してもトレースが取れます。
ブート回り、ベアメタルファームウェア、等、どんな場合にでもトレース用端子を接続しさえすればOK。

思えば、筆者も大変にお世話になりました。
評価ボードを大きくしたくないという理由でトレース用端子がテストピンにまったく出ていない場合でも、その端子を直接極細プローブで引っ掛けて無理矢理トレースを取ったりしていましたね。。。
昔のマイコンチップは端子間がもう少し大きかったなぁ。。。(遠い目)

おっと、昔を懐かしんでしまいました。
話を戻します。
ちなみに、端子を使わなくてよいトレース機能もあります。
デバイスの内部にあるトレースバッファに、情報をためていく方式です。
しかしながら、トレースバッファはあまり大きくはなく、欲しいデータを取ることが難しかったりします。

ここまでは、ハードウェア(端子やデバイス内蔵バッファ)によるトレース機能について、です。

ここからは、関数トレースという機能について。
先のハードウェアによるトレース機能でも、デバッガでフィルタリングし関数トレースを行う事は可能です。
ですがSOLIDでは
特別なハードウェア不要の関数トレース機能
を実現しています。
トレース端子もトレースプローブも不要なので、今すぐここで動かせます。

早速見ていきましょう!

 

 

2.準備

SOLID-IDEの関数トレース機能については、このURLに記載されています。

https://solid.kmckk.com/SOLID/doc/latest/user_guide/function_trace.html#user-guide-function-trace

ここに記載されている通りに、試してみます。

今回も前回に引き続き、Cortex-A9搭載ボード×PARTNER Jet2の組み合わせを使用します。
動作させるプログラムについても、今まで使用してきたサンプル「KZM-A9GT-demo-sample1」を使用します。

準備として、以下4点を行います。
・関数トレースを有効化するためにプロパティシートを変更
・関数トレース情報を蓄積するためのメモリ領域割り当て
・インストルメンテーション(Instrumentation:計装。計測のためのコード追加)有効化
・関数へのパッチ適用

「関数へのパッチ適用」については後ほど触れますが、ここでは「トレース情報を取る対象とする」という事だと思っておいて頂ければOKです。

2.1 準備①:プロパティシートを変更

関数トレースを有効化するために、プロパティシートを変更します。

まず、プロパティシートを開きます。
開き方は以下に記載されています。

https://solid.kmckk.com/SOLID/doc/latest/user_guide/reload-solution-propsheet.html#id4

ソリューションエクスプローラ上でソリューションを右クリックし、表示されるメニューから「ソリューションプロパティシートを開く」を選択すればOKです。

<PropertyGroup>内にを追加し、値をtrueにします。

そして、ソリューションを保存し再読み込みします。

 

2.2 準備②:メモリ領域割り当て

次に、関数トレース情報を蓄積するためのメモリ領域を割り当てます。

メモリマップデザイナを使用します。
smmファイルをダブルクリックすれば開きます。

見てみます。

今回、既にFTRACEありましたので、このままにします。
FTRACEがない場合は、追加すればOKです。

サイズは、とりあえず10MBになっていますが、もっと小さくすることもできます。

 

2.3 準備③:インストルメンテーション有効化

次に、インストルメンテーション有効化です。
対象とするプロジェクトのプロパティから有効化できます。

[C/C++] → [XRay]を選択し、以下2点を設定します。
・XRayインストルメンテーションの有効化:はい
・命令のしきい値:とりあえずここでは10にしました。(設定しない場合は200になる)

「命令のしきい値」とは、関数が構成される命令数のことです。
指定された命令数以上の関数にのみ、関数トレースが適用される仕組みです。
「命令のしきい値」を小さくすれば、小さい関数にでも適用されます。
ですが、その分、オーバーヘッドにもなってしまうので、注意が必要です。
小さい関数は、頻繁に動くことが多いかと思います。
(レジスタに何やら設定するだけの関数、とか。。。)

 

2.4 準備④:関数へのパッチ有効

最後、関数へのパッチを有効化します。

まず、再ビルドし実行し、適当なところでブレークします。
ここでは、ルートタスク内でタスクを生成した直後くらいでブレークしてみます。

 

[デバッグ]メニュー → [ウインドウ] → [関数トレース] を選択します。

[Patch all]をクリックすると、対象のプロジェクト内のすべての関数(10命令以上の)に対しパッチを適用します。

 

 

3.関数トレース取得

準備は整いました。
関数トレースを取ってみます。

ブレークを削除し、実行!
そして、強制ブレーク!
トレース情報が集まったはずです。
吸い上げてみましょう。
関数トレースウインドウから[Save trace data]をクリックします。

これでデータが収集されました。

収集日のところを、クリックします。

CPU0をダブルクリックして、展開してみます。

トレース結果が表示されました!

上段:タスク遷移
下段:呼び出された関数名

このウインドウの詳細はこちらに記載されています。

https://solid.kmckk.com/SOLID/doc/latest/user_guide/function_trace.html#id8

 

 

4.トレース取得対象の選択

先の例では、命令数が10命令以上の関数すべてをトレース取得の対象にしました。
ですが、
トレース取得の対象にする=トレース収集のオーバーヘッドが存在する
なので、できれば対象範囲は少ない方が良いです。
それにあまり沢山取れてしまっても、後から見るのが大変だったりもしますよね。。。

という事で、トレース取得したい対象を選択する方法についてご紹介します。
先に説明した、「トレース取得の対象とする関数の命令数を適切に設定する」以外にも、選択する方法があります。

 

4.1 取得したい関数名を指定する

先程の関数トレースウインドウで、[Patch all]を選択しましたが、そうではなく関数単位に選択することも可能です。
[Patch]を選択します。

このように、選択することが可能です。

例えばイベントフラグの推移をトレースしたい場合、ここでイベント操作系関数のみトレースする、という使い方もできますね。

 

4.2 ファイル単位で選択する

先のご紹介では、「プロジェクト」のプロパティから[XRay]を有効にしましたが、
実はファイル単位でも可能です。

対象とするファイルのプロパティから、[XRay]を有効にすることができます。

こうすると、選択したファイルに書かれている関数をまるっと全部、トレース対象とすることができます。(命令数が、設定したしきい値以上である全関数です)

 

 

5.実現方法

実現方法について少し触れます。
Clangコンパイラの” XRay instrumentation”という機能を使って実現しています。
以下に詳細記載されています。

https://llvm.org/docs/XRayExample.html

関数の中にトレースができるような命令を埋め込む機能です。

Xray を有効にしたときに、コンパイラは、命令数のしきい値を越える関数にだけ、先頭と最後尾に、「数個の連続するNOP命令」を出力します。
これが準備③に該当します。

デバッガは、RAM 上の 「数個のNOP命令」 の部分を、「関数トレースのランタイムを呼び出すコード」に書き換えます。準備④に該当します。
書き換え対象とする関数は、準備④で、パッチ適用を行った関数となります。
ここで使われている「パッチ」とは、「バイナリパッチを当てる」という意味です。

関数トレースのランタイムは、SOLID-OSが持っています。

さらに、プログラムが動作しブレークするとします。
この時、SOLID-IDEの方で、トレース情報を吸い上げ、GUIに表示します。

まさに三位一体、OSとデバッガが協力して、Clangコンパイラの機能を使いこなしています。

実行速度についても少し補足します。
命令を埋め込むという事は、実行速度が落ちるようにも思いますが、トレース対象関数ではない場合はNOP数個埋め込むだけですよね。

近年の高速なCPUであれば、NOP命令の実行には、ほとんどCPUのサイクル数を使わないので、メモリサイズの点で許されるのであれば「製品版ソフトも XRay有効でビルド」し、その上で、市場で問題が起きたときに関数トレースを取るといった使い方も考えられます。

 

 

6.まとめ

今回は、関数トレースをご紹介しました。

トレース用ハードウェアを別途用意する必要がなく、トレース専用端子を占有することも必要ないので手軽だし、逆に必要部分のみトレースできるのも特にOS上で動いている場合に不要なコードまでトレースされているという事を防げるので嬉しい部分ですね。
また、実現方法のあたりで少し触れたとおりOSとデバッガを一緒に開発していなきゃできない機能なので、なかなかレアな機能だと思いました。

それに、なんだかいろいろ設定するところがあって面倒かな?と思いきや、実際にやってみると結構簡単に使えたのも良かったです。

 

次回は、ローダー機能についてご紹介する予定です。