こんにちは、
まず最初に、書かれている内容はすべてClaudeエージェントによるものです。なぜなら、私が作成するものはすべてObsidianリポジトリ内で作成され、エージェントに書き込ませる方が速いからです。
私は修士論文のために、FRDM-MCXN947を用いてサイクル精度のタイミング測定を行っており、いくつかのリアルタイムオペレーティングシステムのスケジューリングオーバーヘッドを比較しています。報告するすべての数値は2つのDWT->CYCCNT読み取り値の差なので、測定は1サイクル単位で繰り返し可能でなければなりません。違いますし、かなり長い調査の末、原因はドキュメントから確認できない一つのメカニズムに絞り込みました。私の説明が本当に正しいかどうか確認したいのですが、もし間違っているとしたら、他の可能性をすべて排除してしまい、候補が一人も残っていないことになります。
質問の要点を簡潔にまとめると、デバッグセッションが開いている間、LinkServerは定期的にDHCSRとCPACRを読み取り、コアが停止したかどうかを確認します。これらはどちらもプライベート周辺バス内のSCSレジスタであり、アクセスはコア内で処理され、コードバスやシステムバスには表示されません。私の仮定では、そのようなアクセスはコア内部の命令フェッチやデータアクセスと競合しており、これが測定ウィンドウ内にポールが届くたびに数サイクルのコストを落とす原因だと思います。その推測は正しいですか?
ボードはFRDM-MCXN947で、コア0のみを使用しています。実際の測定では150MHz、後述する制御実験では12MHzを使用しています。搭載MCU-Linkを使ってLinkServerを使ってデバッグしており、これはUSBでCMSIS-DAP v2を言語し、SWDの50と500のワイヤークロックも試しました。起動設定は--no-rtosと--semihost-port=-1を通過し、liveWatchは無効化されているため、コアが動作している間はIDEがターゲットから何かを読み取ることはありません。
テスト対象のコードは、RAMのアドレス0x2000_0000から実行されます。つまり、システムバス経由でフェッチされるということです。キャッシュとRAM ECCは無効になっています。画像がRAMに入る方法にはもう一つ別のバリエーションがあります。ほとんどの作業ではプローブが単にRAMに読み込みますが、ある実験では画像をフラッシュに保存し、起動時にRAMにコピーしました。なぜなら、RAMにしか存在しないイメージはプローブなしでは起動できないからです。その区別はその実験に限っていて、今ここで言及するのは後で明確に設定できるようにするためです。
計測対象は、指定された回数だけ実行される空のカウントループであり、実行前後にCYCCNTを読み取ることで時間を計測します。私はそれぞれの測定を64回繰り返します。
同じ測定を2回行っても、同じ結果は得られない。空ループでは64の値が3〜6サイクルにわたって分散し、実際のアプリケーションコードでは10万回中約9回が他のすべての反復より1〜10サイクル上に出てきます。偏差は常に上昇する一方であり、下降することは決してなく、最小値は完全に安定しており、再現性も高い。最も参考になったのは、測定間隔の長さに応じて変動するコストが、測定呼び出しごとの固定コストではないという点です。これは、私の計測機器のどこかに一定のオーバーヘッドが存在する可能性をすでに排除しています。
これが全容です。各セルは空のループの64回の測定値です。「外れ値」は、64回のうち最初の値を超えた回数をカウントし、minとmaxはループのクリーン値からのサイクル数として示されます。
コアループ数 SWD 50: 外れ値最小値最大値 SWD 500: 外れ値最小値最大値
| コアF | ループ | 64回の測定あたりの外れ値 | 最小ジッター数 | 最大ジッター数 | 外れ値/64mea。 | 最小ジッター | 最大ジッター |
| 12MHz | 100 | 0 | +13 | +13 | 0 | +13 | +13 |
| 1000 | 4 | +13 | +15 | 7 | +13 | +16 | |
| 10000 | 24 | +13 | +16 | 18 | +13 | +17 | |
| 100000 | 55 | +13 | +23 | 57 | +13 | +22 | |
| 1,000,000 | 56 | +40 | +69 | 59 | +45 | +102 | |
| 150MHz | 100 | 0 | +13 | +13 | 0 | +13 | +13 |
| 1000 | 0 | +13 | +13 | 1 | +13 | +15 | |
| 10000 | 4 | +13 | +15 | 3 | +13 | +15 | |
| 100000 | 13 | +13 | +15 | 16 | +13 | +17 | |
| 1,000,000 | 53 | +13 | +20 | 60 | +13 | +25 |
この表からは3つのことが分かります。まず、定数+13は問題の一部ではありません。これは、コアクロックとワイヤ速度の両方において、飽和していないすべてのセルで最小値として現れ、ループのプロローグとCYCCNTの読み取り自体に単純に一致します。これはコアクロックとプローブの両方から独立しているため、私が減算する固定バイアスであり、+13を超える値はすべて私が実際に追い求めているものです。
第二に、そしてこれが重要な点だが、この障害は実行されたサイクル数ではなく、実際の時間経過に比例する。同じループ回数で2つのクロックを比較すると、150 MHzよりも12 MHzの方が一貫して外れ値が多くなります。1000回の反復では4対0、7対1、1万回の反復では24対4、18対3、10万回の反復では55対13、57対16です。命令ストリームは両者とも同一であるため、同じサイクル数を実行し、唯一の違いは12 MHzの実行がリアルタイムで12.5倍長くかかることです。
第三に、SWDワイヤークロックは全く影響しません。上記の10組の一致した対では、カウントは両方向に散乱し、カウントノイズ内にとどまるため、ワイヤーレートが10倍に変化してもカウントは残ります。何がペースを決めるにせよ、それはワイヤーではない。
最初に断っておきたいのは、リセット時のデフォルト値がまだ有効であると仮定するのではなく、セッションを開いた状態でターゲットから関連するレジスタを実際に読み戻すことによって、これらの可能性の多くが排除されたということです。
SoC側では、CPU1、eDMA0、eDMA1、SmartDMAはすべて無効化されており、RAMのECCもコードキャッシュもオフなので、他のメモリが競合していません。トレース側では、ITMが無効化され、刺激ポートも有効化されず、タイムスタンプもオフ、ストール・フォー・トレースビットはクリアでETMもオフになります。つまり、トレースパケットが何も生成されていないため、何もストールしていないため、それを配信するものが何も起こらないということです。DWT内では、PCサンプリングがオフで、例外トレースがオフで、すべてのイベントカウンタがオフで、ウォッチポイントコンパレータも使われず、パフォーマンスモニターもオフです。TRCENAはもちろん設定されていますが、CYCCNTが依存しているため、妨害されたCASEと未攪乱のCASEの両方に設定されている必要があります。したがって、それが両者の違いにはなりません。
割り込みと例外は、その規模の大きさという理由だけで除外されます。このコアにおける例外処理は、25~50サイクル程度のコストがかかり、私の場合は1~10の誤差が生じる。例外の小さなバージョンは存在せず、割り込みマスクが何を言おうとクラス全体が除外されます。ブレークポイントも同様の理由で使われていません。FPBコンパレータはマッチするまでコストがかかり、マッチするとコアを停止させるため、わずかに遅延しません。
対照実験の結果、テスト対象のコードは除外されました。空ループにはデータ依存的な仕事が一切含まれないため、それ自体で変化することはなく、いずれにせよ変化します。つまり、原因は私が測定しているものではなくプラットフォームにあります。
左デバッガメモリの読み取り値は、これまでで最も有望な説明であり、私がそれを却下した理由を説明したいと思います。なぜなら、それはほとんどの人が合理的に疑うであろうメカニズムだからです。SRAMのデバッグリードはコアから離れ、バスポートをめぐってコアと戦うため、この仕組みは完璧に機能します。問題は、それが起こらないということだ。IDEが行うすべての読み取りはGDB mパケットとして移動し、gdbserverログには$vCont間に単一のパケットはありません。実行を開始し、ホストが32秒後に割り込みます。そのログで読み取られるすべてのメモリは停止後に残っており、これはコアが停止した後にIDEがビューを埋めるだけです。同じ議論は、デバッガがCYCCNT自体を読み取っているという、さらに魅力的な理論を否定する。この理論は私の測定結果と直接矛盾する。なぜなら、それもmパケットとして現れるはずだが、実際には現れず、いずれにせよliveWatchは無効になっているからだ。
プローブをセッションから分離するために、プローブを物理的に接続した状態で同一のバイナリを実行しました。
しかし、デバッグセッションは開かれていません。これは、起動時にフラッシュメモリからRAMへのコピーが必要だった実験です。
前述したように、RAMのみのイメージはプローブなしではロードする方法がないためです。探査機はそのまま残った
両方のランでコネクテッドだったので、違いはセッションが接続されているかどうかだけでした。
デバッグセッションを行わないと、ジッターは解消される。同じバイナリ、同じクロック、同じブートパス。SO、
プローブがコネクテッドなのではなく、単に接続されているだけで「いいえ」を発信するプローブではありません
トランザクションはコストがかかりませんし、セッションを接続するとジッターが戻ります。
その時点で、セッション自体が確実に引き起こした乱れがあり、リアルタイムでペースが調整されています
コアクロックでではなく、私は考えられる限りのあらゆるメカニズムを排除していました。
コアが稼働している間にLinkServerが何を送信しているかを調べるために、USBPcapとWiresharkでMCU-LinkのCMSIS-DAPバルクエンドポイントをキャプチャしました。2つのDAP_Transferリクエストが、約50ミリ秒ごとに継続的に繰り返される。
その数字については、すぐに補足説明をしなければなりません。ポーリングは固定タイマーのようには見えません。なぜなら、ホストは前の応答が返ってきた後に次のリクエストを送るように見えるため、この間隔は少なくとも部分的にイベント駆動型です — ホストのターンアラウンドとUSBレイテンシ、さらにホストが自ら挿入する遅延が加わるのです。つまり50ミリ秒は、繰り返しの頻度を示す桁違いの数字であり、引用したい期間ではありません。また、その速度からきれいに逆算することもできません。
最初の要求では、DHCSRとCPACRが一緒に記載されています。回線上のデータは 05 00 06 08 00 00 00 00 05 f0 ed 00 e0 0f 08 00 00 00 00 05 88 ed 00 e0 0f であり、これをデコードすると次のようになります。
# Req デコードデータ ターゲットアクセス
| 1 | 08 | DP書き込みSELECT | 0x00000000 | なし(DP内部) |
| 2 | 05 | AP は TAR を書きます | 0xE000EDF0 (DHCSR) | なし(AP内部) |
| 3 | 0F | AP通信はDRWを読んだ。 | — | 1読了、PPB |
| 4 | 08 | DP書き込みSELECT | 0x00000000 | なし(DP内部) |
| 5 | 05 | AP は TAR を書きます | 0xE000ED88 (CPACR) | なし(AP内部) |
| 6 | 0F | AP通信はDRWを読んだ。 | — | 1読了、PPB |
回答は、DHCSR = 0x01100001 であり、これはコアがセキュアデバッグを有効にして命令をリタイアしていることを意味します。また、CPACR = 0x00F00003 であり、これはFPUに完全にアクセスできることを意味します。2 番目の要求は 05 00 03 08 00 00 00 00 05 f0 ed 00 e0 0f で、これは上記の前半部分のみで、FPU チェックなしでコアが停止したかどうかのみを尋ねます。
SO、測定ウィンドウ中にターゲットに到達する全トラフィックは2PPB読み取り、短いリクエストの場合は1回です。SELECTとTARの書き込みは、それぞれDPとAP内部にあるため、ターゲットアクセスは一切発生しません。実際にどこかへ行くのは2回のDRW読み取りだけです。転送カウントとデータワードカウントを照合し、このアダプターでposted-readシフトなしの直接的な値-レジスタ対応を確認したので、どの値がどのアドレスに属しているか確信を持っています。
両方のアドレスはPPB内のSCSレジスタであり、どちらもSoCバスマトリックスには表示されません。この中にはSRAMアクセスはなく、コアレジスタファイルにもアクセスできません。なぜなら、DCRSR/DCRDRキーホールを通るものは一切入らないため、コアを先に停止させる必要があるからです。補足として、S0からS31およびFPSCRの71転送分のダンプが別途キャプチャに含まれていますが、これはコアがstopAtSymbolブレークポイントで停止した時点のみであり、実行中ではありません。私の推測では、CPACRはDHCSRとセットされているため、コアが停止した瞬間に浮動小数点レジスタが稼働しているかどうかをアダプターがすでに把握できるようにしているのだと思います。
私が現在考えているのは、こういうことです。リクエストはD-AHBデバッグを通じてコアに入ります
ポートはコア内部のインターコネクトによって、コア自身の命令に対して仲裁されます
フェッチやデータアクセス。コア内で解決されているからといって、アクセスが
実行から分離;それでも実行は共有された内部段階で行われます。コアが優先され、
SO、通常のCASEではデバッグアクセスが待機し、コアは影響を受けずに継続されます。残留費用
デバッグビートがすでに進行中でプリエンプトできない場合にのみ現れ、その場合コアは
そのビートが終わるのを待たなければなりません。その待ち時間はまさに私が観察している通りです。数サイクル、いつも
上昇傾向を示し、しかも世論調査がたまたま含まれる測定期間のごく一部に限られる。
こんにちは、 @hms-isyu さん。
詳細な分析をありがとうございました。
申し訳ありませんが、この質問はNXP MCUアプリケーションのサポートの通常の範囲を超えています。MCXN947、MCU-Link、SDK、デバイス使用に関する質問にはお手伝いできます。しかし、あなたが調査している挙動はCortex-M33のデバッグアーキテクチャとサイクル精度の高いパフォーマンス解析に関わっており、私の専門外です。
パフォーマンス測定時に追加サイクルカウントを注入することに関する質問は、Armサポートにお問い合わせください。
ご理解いただきありがとうございます。
BR
アリス