diff options
Diffstat (limited to 'app/perfunwind.cpp')
-rw-r--r-- | app/perfunwind.cpp | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/app/perfunwind.cpp b/app/perfunwind.cpp index 849b220..94b68ef 100644 --- a/app/perfunwind.cpp +++ b/app/perfunwind.cpp @@ -365,8 +365,12 @@ static int frameCallback(Dwfl_Frame *state, void *arg) return DWARF_CB_OK; } -void PerfUnwind::unwindStack(Dwfl *dwfl) +void PerfUnwind::unwindStack() { + Dwfl *dwfl = symbolTable(m_currentUnwind.sample->pid())->attachDwfl(&m_currentUnwind); + if (!dwfl) + return; + dwfl_getthread_frames(dwfl, m_currentUnwind.sample->pid(), frameCallback, &m_currentUnwind); if (m_currentUnwind.isInterworking) { QVector<qint32> savedFrames = m_currentUnwind.frames; @@ -417,12 +421,14 @@ void PerfUnwind::resolveCallchain() // sometimes it skips the first user frame. if (i == 0 && !isKernel && ip != m_currentUnwind.sample->ip()) { + symbols->attachDwfl(&m_currentUnwind); m_currentUnwind.frames.append(symbols->lookupFrame( m_currentUnwind.sample->ip(), false, &m_currentUnwind.isInterworking)); } if (ip <= PERF_CONTEXT_MAX) { + symbols->attachDwfl(&m_currentUnwind); m_currentUnwind.frames.append(symbols->lookupFrame( ip, isKernel, &m_currentUnwind.isInterworking)); @@ -508,8 +514,7 @@ void PerfUnwind::analyze(const PerfRecordSample &sample) if (m_stats.enabled) // don't do any time intensive work in stats mode return; - const bool isKernel = ipIsInKernelSpace(sample.ip()); - + PerfSymbolTable *kernelSymbols = symbolTable(s_kernelPid); PerfSymbolTable *userSymbols = symbolTable(sample.pid()); for (int unwindingAttempt = 0; unwindingAttempt < 2; ++unwindingAttempt) { @@ -519,32 +524,38 @@ void PerfUnwind::analyze(const PerfRecordSample &sample) m_currentUnwind.frames.clear(); userSymbols->updatePerfMap(); - - Dwfl *userDwfl = userSymbols->attachDwfl(&m_currentUnwind); if (sample.callchain().length() > 0) resolveCallchain(); + bool userDirty = userSymbols->cacheIsDirty(); + bool kernelDirty = kernelSymbols->cacheIsDirty(); + // only try to unwind when resolveCallchain did not dirty the cache - if (!userSymbols->cacheIsDirty()) { - if (userDwfl && sample.registerAbi() != 0 && sample.userStack().length() > 0) - unwindStack(userDwfl); - else + if (!userDirty && !kernelDirty) { + if (sample.registerAbi() != 0 && sample.userStack().length() > 0) { + unwindStack(); + userDirty = userSymbols->cacheIsDirty(); + } else { break; + } } // when the cache is dirty, we clean it up and try again, otherwise we can // stop as unwinding should have succeeded - if (userSymbols->cacheIsDirty()) + if (userDirty) userSymbols->clearCache(); // fail, try again - else + if (kernelDirty) + kernelSymbols->clearCache(); + if (!userDirty && !kernelDirty) break; // success } // If nothing was found, at least look up the IP if (m_currentUnwind.frames.isEmpty()) { - PerfSymbolTable *symbols = isKernel ? symbolTable(s_kernelPid) : userSymbols; - m_currentUnwind.frames.append(symbols->lookupFrame(sample.ip(), isKernel, - &m_currentUnwind.isInterworking)); + const bool isKernel = ipIsInKernelSpace(sample.ip()); + PerfSymbolTable *ipSymbols = isKernel ? kernelSymbols : userSymbols; + m_currentUnwind.frames.append(ipSymbols->lookupFrame(sample.ip(), isKernel, + &m_currentUnwind.isInterworking)); } |