2009-02-24 23 views
0

我的日誌記錄代碼使用返回值backtrace()來確定當前的堆棧深度(用於漂亮的打印目的),但從分析中我可以看出這是一個相當昂貴的調用。有沒有比使用backtrace()更便宜的方法來查找調用堆棧的深度?

我不認爲有這樣做的更便宜的方法?請注意,我不關心幀地址,只是其中有多少。

編輯:這些日誌記錄函數全部用於大型代碼庫,因此手動跟蹤堆棧深度並不是真正的選擇。

回答

5

自己走棧非常快 - 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()的最開始處查看終止值。

2

如果您的漂亮打印函數被合理包含,則將縮進(或縮進大小)作爲參數傳遞,並在調用其他顯示函數時遞增。

+0

如果添加另一個參數,以你的函數的想法讓你害怕,你也可以使用一個靜態變量。在我看來,這通常不是一個好主意。這將和道格拉斯的解決方案一樣。 – Brian 2009-02-24 17:52:22

2

難道你不能隨身攜帶一個TLS變量稱爲「深度」,並增加/減少它的每一個功能嗎?儘管你可以編寫自己的代碼來更快地執行堆棧,但它仍然會比只是隨身攜帶變量慢。

+0

不,我認爲在每次函數調用時遞增/遞減TLS變量將會相當昂貴得多,這取決於您需要多久進行一次回溯。 – 2009-02-24 17:52:30

2

針對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; 
相關問題