Y at-il un moyen moins coûteux de trouver la profondeur de la pile d'appel que l'utilisation backtrace ()?

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

  •  06-09-2019
  •  | 
  •  

Question

Mon code d'enregistrement utilise la valeur de retour de trace () pour déterminer le courant profondeur pile (à des fins d'impression joli), mais je peux voir de profilage que c'est un appel assez cher.

Je ne pense pas qu'il y ait un moyen moins coûteux de le faire? Notez que je ne me soucie pas des adresses de cadre, combien d'entre eux il y a.

modifier. Ces fonctions de journalisation sont utilisés dans une grande base de code, de sorte que le suivi manuel de la profondeur de la pile ne sont pas vraiment une option

Était-ce utile?

La solution

Marcher la pile vous-même est assez rapide - plus de la lenteur dans backtrace() est de regarder les noms de 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 marche la chaîne de pointeurs de ebp. Gardez à l'esprit que ce qui est extrêmement non-portable. Notez également que cela ne comptera pas toutes les fonctions qui ont été inline ou appel queue optimisée (bien sûr, backtrace() a le même problème).

Une autre question importante est la condition de terminaison - une fois que vous BACKTRACE jusqu'à main(), il y a souvent pas des garanties sur ce que vous trouverez dans la pile. Donc, si libc ne met pas un pointeur de cadre null, vous aurez segfault très probablement. Vous pouvez obtenir la valeur de terminaison en regardant au début même de main().

Autres conseils

Si vos fonctions jolie impression raisonnablement contenu, puis passent au tiret (ou taille tiret) comme paramètre et l'incrément juste lorsque vous appelez d'autres fonctions d'affichage.

Tu ne peux pas porter juste un TLS variables avec vous appelé « profondeur "et incrémenter / décrémenter chaque fonction? Alors que vous pouvez écrire votre propre code pour marcher plus vite la pile, il va encore être plus lent que simplement la variable portant avec vous.

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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top