Есть ли более дешевый способ определить глубину стека вызовов, чем с помощью backtrace()?

StackOverflow https://stackoverflow.com/questions/582673

  •  06-09-2019
  •  | 
  •  

Вопрос

Мой код ведения журнала использует возвращаемое значение обратная трассировка() чтобы определить текущую глубину стека (для удобства печати), но из профилирования я вижу, что это довольно дорогой вызов.

Я не полагаю, что есть более дешевый способ сделать это?Обратите внимание, что меня не волнуют адреса фреймов, просто сколько их там.

Редактировать:Эти функции ведения журнала используются по всей большой базе кода, поэтому вручную отслеживать глубину стека на самом деле не вариант.

Это было полезно?

Решение

Ходить по стеку самостоятельно довольно быстро - большая часть медлительности в 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().

Другие советы

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

Разве ты не можешь просто нести 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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top