0

My logging code uses the return value of backtrace() to determine the current stack depth (for pretty printing purposes), but I can see from profiling that this is a pretty expensive call.

I don't suppose there's a cheaper way of doing this? Note that I don't care about the frame addresses, just how many of them there are.

edit: These logging functions are used all over a large code-base, so manually tracking the stack depth isn't really an option.

4

4 回答 4

6

Walking the stack yourself is pretty quick - most of the slowness in backtrace() is from looking up symbol names. On x86, you can do the following:

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

This will walk the chain of ebp pointers. Keep in mind that this is extremely non-portable. Also note that this will not count any functions which have been inlined or tail-call optimized (of course, backtrace() has the same problem).

Another important issue is the termination condition -- once you backtrace up to main(), there often aren't guarantees about what you'll find in the stack. So, if libc doesn't put a null frame pointer, you'll very likely segfault. You can get the termination value by looking at it at the very beginning of main().

于 2009-02-24T17:59:42.020 回答
2

If your pretty-printing functions are reasonably contained, then pass in the indent (or indent size) as a parameter, and just increment it when you call other display functions.

于 2009-02-24T17:42:15.807 回答
2

Can't you just carry a TLS variable around with you called "depth" and increment it / decrement it every function? While you could write your own code to walk the stack quicker, it's still going to be slower than just carrying the variable around with you.

于 2009-02-24T17:42:22.497 回答
2

For arm architectures :

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

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

return depth;
于 2009-02-27T11:42:03.260 回答