Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

faster than Stackwalk

Does anybody know of a better/ faster way to get the call stack than "StackWalk"? I also think that stackwalk can also be slower on methods with a lot of variables... (I wonder what commercial profilers do?) I'm using C++ on windows. :) thanks :)

like image 717
Idov Avatar asked Oct 02 '10 12:10

Idov


3 Answers

I use Jochen Kalmbachs StackWalker.

I speedet it up this way:

  • The most time is lost in looking for the PDB files in the default directories and PDB Servers.

  • I use only one PDB path and implemented a white list for the images I want to get resolved (no need for me to look for user32.pdb)

  • Sometimes I dont need to dive to the bottom, so I defined a max deep

code changes:

BOOL StackWalker::LoadModules()
{

    ...

    // comment this line out and replace to your pdb path
    // BOOL bRet = this->m_sw->Init(szSymPath);
    BOOL bRet = this->m_sw->Init(<my pdb path>);

    ...

}

BOOL StackWalker::ShowCallstack(int iMaxDeep /* new parameter */ ... )
{

    ... 

// define a maximal deep
// for (frameNum = 0; ; ++frameNum )
    for (frameNum = 0; frameNum < iMaxDeep; ++frameNum )
    {

        ... 

    }
}
like image 74
marsh-wiggle Avatar answered Nov 05 '22 04:11

marsh-wiggle


I don't know if it's faster, and it won't show you any symbols, and I'm sure you can do better than that, but this is some code I wrote a while back when I needed this info (only works for Windows):

struct CallStackItem
{
    void* pc;
    CallStackItem* next;

    CallStackItem()
    {
        pc = NULL;
        next = NULL;
    }
};

typedef void* CallStackHandle;

CallStackHandle CreateCurrentCallStack(int nLevels)
{
    void** ppCurrent = NULL;

    // Get the current saved stack pointer (saved by the compiler on the function prefix).
    __asm { mov ppCurrent, ebp };

    // Don't limit if nLevels is not positive
    if (nLevels <= 0)
        nLevels = 1000000;

    // ebp points to the old call stack, where the first two items look like this:
    // ebp -> [0] Previous ebp
    //        [1] previous program counter
    CallStackItem* pResult = new CallStackItem;
    CallStackItem* pCurItem = pResult;
    int nCurLevel = 0;

    // We need to read two pointers from the stack
    int nRequiredMemorySize = sizeof(void*) * 2;
    while (nCurLevel < nLevels && ppCurrent && !IsBadReadPtr(ppCurrent, nRequiredMemorySize))
    {
        // Keep the previous program counter (where the function will return to)
        pCurItem->pc = ppCurrent[1];
        pCurItem->next = new CallStackItem;

        // Go the the previously kept ebp
        ppCurrent = (void**)*ppCurrent;
        pCurItem = pCurItem->next;
        ++nCurLevel;
    }

    return pResult;
}

void PrintCallStack(CallStackHandle hCallStack)
{
    CallStackItem* pCurItem = (CallStackItem*)hCallStack;
    printf("----- Call stack start -----\n");
    while (pCurItem)
    {
        printf("0x%08x\n", pCurItem->pc);
        pCurItem = pCurItem->next;
    }
    printf("-----  Call stack end  -----\n");
}

void ReleaseCallStack(CallStackHandle hCallStack)
{
    CallStackItem* pCurItem = (CallStackItem*)hCallStack;
    CallStackItem* pPrevItem;
    while (pCurItem)
    {
        pPrevItem = pCurItem;
        pCurItem = pCurItem->next;
        delete pPrevItem;
    }
}
like image 38
Asaf Avatar answered Nov 05 '22 04:11

Asaf


Check out http://msdn.microsoft.com/en-us/library/bb204633%28VS.85%29.aspx - this is "CaptureStackBackTrace", although it's called as "RtlCaptureStackBackTrace".

like image 27
Damyan Avatar answered Nov 05 '22 05:11

Damyan