Question

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.

Was it helpful?

Solution

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().

OTHER TIPS

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.

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.

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top