バックトレースを()を使用して、よりコールスタックの深さを見つけるために安価な方法はありますか?
質問
私のロギングコードは、電流を決定するために、バックトレース()するの戻り値を使用し(かなり印刷目的のために)の深さを積み重ね、私はこれはかなり高価な呼び出しであることをプロファイリングから見ることができます。
私はこれを行うための安価な方法がありますと仮定しないのですか?私はそこにどれだけ多くのそれらの、フレームアドレスを気にしないことに注意してください。
編集:これらのロギング機能は、手動でスタックの深さを追跡することは本当にオプションではありません、すべての大規模なコードベース上で使用されている。
。解決
スタックを自分で歩くかなり速いです - backtrace()
での遅さのほとんどは、シンボル名を検索するからです。 x86では、次の操作を行うことができます:
inline uint32_t get_ebp(void)
{
__asm__ __volatile__("mov %%ebp, %%eax");
}
int get_stack_depth(void)
{
uint32_t ebp = get_ebp();
int stack_depth = 0;
while(ebp != 0)
{
ebp = *(uint32_t *)ebp;
stack_depth++;
}
return stack_depth;
}
このはebp
ポインタのチェーンを歩いていきます。これは非常に非ポータブルであることに留意してください。また、これはインライン展開または末尾呼び出しが(もちろん、backtrace()
は同じ問題を抱えている)。
もう一つの重要な問題は、終了条件である - あなたがmain()
までバックトレース後、多くの場合、あなたはスタックに見つけるかについての保証はありません。 libcのがヌルフレームポインタを置いていないのであれば、あなたは非常に可能性がセグメンテーションフォルトをよ。あなたはmain()
の一番最初にそれを見て、終了値を取得することができます。
他のヒント
、その後、インデント(またはインデントサイズ)に渡すパラメータとして、あなたは他の表示機能を呼び出すときにちょうどそれをインクリメントします。
あなたはちょうどあなたが深さ「と呼ばれると周りの TLS の変数を運ぶことはできません。 「それは/それのすべての機能デクリメントインクリメント?あなたがより速く、スタックを歩いて独自のコードを書くことができますが、まだあなたの変数を持ち歩いよりも遅くなるだろう。
ARMアーキテクチャ:
register unsigned long *rfp asm("fp");
unsigned long *fp = rfp;
unsigned long depth = 0;
while(fp)
{
fp = (unsigned long *)(*(fp -3));
depth++;
}
return depth;