Move Execution Tracer (別名ランタイム/チケット) は、「Web サイトのオンライン訪問者にサービスを提供する製造業のサーバー」で使用できる十分なオーバーヘッドを低く抑えるように 設計されていました。 ここでは、オケージョンを P ごとのバッファーに書き込み、タイムスタンプに RDTSC を使用し、適度に効率的なバイナリ レイアウトにエンコードすることによって実行されます。
… オーバーヘッドの 75% はスタックの巻き戻しです。
– Move Execution Tracer 開発ドキュメント
スタックの巻き戻し (別名スタック ウォーキング) は、スタック チケットを取るための割り当てのセクションです。 これには、すべてのスタック フレームを反復処理し、すべてのフレームでリターン アドレス (プログラム カウンター) を収集することが含まれます。 さらに、ほとんどのプログラム カウンターがインライン ダイアグラム呼び出しのセクションであることが確実である場合は、このチェックリストを拡張することも必要になる可能性があります。 、ファイル名と行番号。 これがシンボル化と呼ばれる最終的なものであり、それについて詳しく読むことができます ここ.
では、なぜスタックの巻き戻しなのかMoveでそんなにコストがかかる? 迅速な反論は、Move が gopclntab と呼ばれる非同期アンワインディング テーブルの発明を実行するためです。このテーブルでは、スタック フレームをトラバースするために自己保証でアサートするための適度にコストのかかる検索が必要です。 このメカニズムの危険な事実は、gentraceback ダイアグラム内にも見られます.
実装を最適化することを考慮に入れるかもしれませんが、今日では分析しないのは困難な戦いです。 別の方法として、もう 1 つの進行状況で時計を操作します。フレーム ポインターの巻き戻しという忘れられた技術です。 これは長い間存在してきた方法論ですが、新たなケースでは容赦ないコンパイラーの最適化に悩まされています.図 1) は、3 つのフレームで構成されるスタックを巻き戻す簡単なプログラムを示しています。
割り当ては、rbp
(amd64) または
r29 おそらく考慮に入れるかもしれませんが、今ではそうではありませんが、これを機能させるのはそれほど洗練されていないので、私はそれを Move ランタイム用の分実験的パッチ (arm64) レジスタ (別名不適切なポインタ)。 これにより、
フレーム 2
のフレーム ポインタに移動します。 )。 このレートより上の 1 フレーズ (8 バイト) は、スコアリングするメイン プログラム カウンターである、呼び出し元のリターン アドレスです。 この後、
フレーム 1
に移動するフレーム ポインタの関連レートを適用します。 、2 番目の返送先住所を確認することができます。 この割り当てをもう 1 回繰り返すと、
frame 0 は、関連するレート 0 を保持するフレーム ポインターを含むため、基盤フレームであることがわかります。 。 したがって、このレベルでは、最終的なリターンアドレスをスコアリングして割り当てを終了します.技術面接以外のチェックリスト (図 2).
この質問に反論するために、BenchmarkPingPongHog。 タイトルが暗示しているように、基本的には、2 つのゴルーチンが、バッファリングされていないチャネルのペアを介してさまざまな間でメッセージをピンポンする効率を測定します。 すべてのチャネル操作がスタック チケットを使用してイベントを記録することになるため、実行トレーサーの絶対的な最悪のケースがここにあります.
正確な数値はマシンによって異なりますが、ここではこのベンチマークをファットで作業するときの最終的な発見について c5n.steel トレースを無効にした EC2 マシンと有効にした EC2 マシン (図 3).
goos: Linux goarch: amd64 pkg: ランタイム cpu: Intel(R) Xeon( R) Platinum 8124M CPU @ 3.00GHz │baseline.txt│gentraceback.txt││sec/op│sec/op 対不適切│PingPongHog-72 642.8n ± 4% 5616.5n ± 3% +773.82% (p=0.000 n=10)
774%オーバーヘッドですね。 しかし、掘り下げてみましょう。この知識は、以前は CPU プロファイラーを操作しているときにキャプチャされていたので、それを悲しむことなく見守ることができます gentraceback
は、以前はこのオーバーヘッドの 94% (!) を占めていました (図 4).
このベースラインを確立したので、見てみましょうフレーム ポインタの巻き戻しがどのように実行されるかを比較します (図 5).
goos: linux goarch: amd64 pkg: ランタイム cpu: Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz │baseline.txt │fp.txt │ │sec/op │sec/op 対不適切 │PingPongHog-72 642.8n ± 4% 834.8n ± 1% +29.87% (p=0.000 n=10)図 5 BenchmarkPingPongHog の実行トレーサーのオーバーヘッドフレームポインターの巻き戻しを使用します。
30% のオーバーヘッド。つまり、gentraceback よりも 26 ケース少ないオーバーヘッドです。 ! 私は、たとえば、リンクされた新しいチェックリストの大君主を歓迎します。 しかし、自分たちよりも早く発見する前に、新しい CPU プロファイル (図 6) を監視してみましょう
見守る立場なので fpcallers は現在、トレーサーのオーバーヘッドの 9% まで削減されたすべての計画です。これは、巻き戻しがもはやアキレス腱ではないことを意味します。実行トレーサーの。 しかし、 それは認められますが、追加の最適化を少しでも行わなくても、フレーム ポインターの巻き戻しは、最大20%~ ほぼ 1% CPU プロファイルは、fpcallers で実行トレーサーのオーバーヘッドの 9% を表示しています。
cputicks
(28 %) および
(*traceStackTable).build
(21%) が出現し始めています。 pprofs をダウンロードして、自分で待機することもできます。
これにより、最終クエリが発生します。 これが簡単な場合、トレーサーがフレーム ポインターを起動するように設計されていないのはなぜですか? 迅速な反論は、トレーサーが以前に 追加された ことです。 go1.5 でしたが、Move コンパイラは go1 以外のフレーム ポインタ命令を発行しなくなりました。 .7.
明らかに、フレーム ポインターを使用してトレーサーを最適化する可能性は、明らかに倫理的な問題に変化するようになったため、元の関連 (および CL 33809, CL 212301) 2016年から。 like
gentraceback
は洗練されています。以前は、それが合理的な要件であるかどうかについて決定されていました。 もう1つの関連は、フレームポインターが最も実用的であるということですamd64で有効そしてarm64なので、
gentraceback
関係なく、さまざまなプラットフォームで引き続き望まれます。 それが認められたとしても、私はこれらのハードルも新しく作られたものによって克服されることを慎重に楽観視しています runtime diagnostics working community.
閉鎖しますが、更新されるようです
momentum C/C++ のフレーム ポインターを有効にする動機内Linux 上のアプリケーションは、従来、効率上の理由から、put コンパイラーを無効にしていました。 これらの議論は、制限されたレジスタを備えた 32 ビット CPU ではかなり理にかなっていますが、実際には再評価されています。 したがって、忘れられていたフレーム ポインターの巻き戻しの技術が復活し、現在はトレーサー内では事実ではありませんが、非現実的な段階で完全なものとして復活することを願っています。 シンプルさと可観測性の利点は非常に大きいでしょう. %%item_read_more_button %%
Pro tip: if you think you will need to profile/trace any natively compiled code at runtime (e.g. some kind of long running service in production) then for the love of god, please don't enable "omit frame pointer" – it can mean the difference between actually readable callstacks/flame graphs and garbage. The days of it having a huge impact on performance are gone, at least from my experience – disabling omitting frame pointer has made no significantly measurable difference to any services I have run in recent years, though you should always confirm that is true for your own case.
So while this article is about Go, it definitely applies to C/C++ as well.