0 votes

Existe-t-il un moyen moins coûteux de connaître la profondeur de la pile d'appels que d'utiliser backtrace() ?

Mon code de journalisation utilise la valeur de retour de backtrace() pour déterminer la profondeur actuelle de la pile (à des fins d'impression), mais le profilage me permet de constater que cet appel est assez coûteux.

Je suppose qu'il n'y a pas de moyen moins cher de faire ça ? Notez que je ne me soucie pas de l'adresse des cadres, mais seulement de leur nombre.

edit : Ces fonctions de journalisation sont utilisées sur une large base de code, donc suivre manuellement la profondeur de la pile n'est pas vraiment une option.

5voto

Adam Rosenfield Points 176408

Parcourir la pile vous-même est assez rapide - la plupart de la lenteur dans le processus de création de la pile est due à l'utilisation d'un logiciel de gestion de la pile. backtrace() c'est en cherchant les noms des symboles. Sur x86, vous pouvez faire ce qui suit :

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

Cela permettra de parcourir la chaîne de ebp pointeurs. Gardez à l'esprit que ceci est extrêmement non-portable. Notez également que cela ne comptera pas les fonctions qui ont été inlined ou optimisées par tail-call (bien sûr, backtrace() a le même problème).

Un autre problème important est la condition de terminaison -- une fois que vous avez fait un backtrace jusqu'à main() il n'y a souvent aucune garantie sur ce que vous trouverez dans la pile. Donc, si la libc ne met pas un pointeur de trame nul, vous aurez très probablement un défaut de segmentation. Vous pouvez obtenir la valeur de terminaison en la regardant au tout début du fichier main() .

2voto

Douglas Leeder Points 29986

Si vos fonctions d'impression sont raisonnablement limitées, passez l'indentation (ou la taille de l'indentation) en tant que paramètre, et incrémentez-la simplement lorsque vous appelez d'autres fonctions d'affichage.

2voto

will Points 1

Pour les architectures de bras :

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

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

return depth;

1voto

Paul Betts Points 41354

Tu ne peux pas juste porter un TLS une variable appelée "profondeur" et l'incrémenter/décrémenter à chaque fonction ? Bien que vous puissiez écrire votre propre code pour parcourir la pile plus rapidement, cela sera toujours plus lent que de simplement transporter la variable avec vous.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X