2009-02-24 3 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 не помещает указатель нулевого фрейма, вы, скорее всего, будете segfault. Вы можете получить значение завершения, посмотрев на него в самом начале main().

2

Если ваши симпатичные функции печати достаточно содержатся, то в качестве параметра введите в отступ (или отступом) параметр и просто увеличивайте его при вызове других функций отображения.

+0

Если идея добавить еще один параметр к вашей функции пугает вас, вы можете также использовать статическую переменную. По-моему, это не очень хорошая идея. Это будет работать так же, как решение Дугласа. – Brian

2

Нельзя ли просто переносить переменную «TLS» с вами под названием «глубина» и увеличивать ее/уменьшать ее каждую функцию? Хотя вы можете написать свой собственный код, чтобы быстрее пройти стек, он все равно будет медленнее, чем просто переносить переменную с собой.

+0

Нет, я думаю, что приращение/декремент переменной TLS каждый вызов функции будет намного дороже, в зависимости от того, как часто вам нужно делать обратную трассировку. –

+0

Он делал обратную линию * каждый вызов * - нет никакого способа, чтобы целое число inc/dec было медленнее –

2

Для рычажных архитектур:

register unsigned long *rfp asm("fp"); 
unsigned long *fp = rfp; 
unsigned long depth = 0; 

while(fp) 
{ 
    fp = (unsigned long *)(*(fp -3)); 
    depth++; 
} 

return depth; 

 Смежные вопросы

  • Нет связанных вопросов^_^