Existe uma maneira mais barata para encontrar a profundidade da pilha de chamadas de usar backtrace ()?

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

  •  06-09-2019
  •  | 
  •  

Pergunta

Meu código de registro utiliza o valor de retorno backtrace () para determinar a corrente profundidade da pilha (para fins de impressão bonitas), mas eu posso ver a partir de perfis que esta é uma chamada muito caro.

Eu não suponho que há uma maneira mais barata de fazer isso? Note que eu não me importo sobre os endereços de quadro, apenas quantos deles existem.

edit:. Estas funções de log são utilizados em todo uma grande base de código, seguindo-lo manualmente a profundidade da pilha não é realmente uma opção

Foi útil?

Solução

Passeio a pilha de si mesmo é muito rápido - a maior parte da lentidão na backtrace() é de olhar para cima nomes de símbolo. Em x86, você pode fazer o seguinte:

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;
}

Este vai andar a cadeia de ponteiros ebp. Tenha em mente que isso é extremamente não-portáteis. Além disso, note que este não contará quaisquer funções que foram inlined ou cauda-call otimizados (claro, backtrace() tem o mesmo problema).

Outra questão importante é a condição de término - uma vez que você backtrace até main(), há muitas vezes não são garantias sobre o que você vai encontrar na pilha. Então, se libc não colocar um ponteiro do quadro nulo, você muito provavelmente segfault. Você pode obter o valor de rescisão por olhando para ele no início de main().

Outras dicas

Se suas funções pretty-impressão são razoavelmente contida, em seguida, passar no travessão (ou tamanho travessão) como um parâmetro, e apenas incrementá-lo quando você chamar outras funções de visualização.

Você não pode apenas levar um TLS variável ao redor com você chamado de "profundidade "e incrementá-lo / diminuí-lo cada função? Enquanto você pode escrever seu próprio código para andar a pilha mais rápido, ele ainda vai ser mais lento do que apenas transportando a variável ao redor com você.

Para arquiteturas de braço:

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

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

return depth;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top