diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2018-01-25 14:56:45 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2018-01-25 14:26:21 +0000 |
commit | d13a5eeded0f80ed88060e6a2e5b31ede849d572 (patch) | |
tree | 9db3e08d2243bcd4d0794ba76b49fd31143b956b | |
parent | 70cd96d631e2a63381cde248f6b68e0b7c9289f0 (diff) |
Try to unwind the user stack even if IP is in kernel space
Quite often we get both a kernel call chain in sample.callchain() and a
user stack and user registers. We should analyze both then, each with
the right symbol table.
Also, when resolving a call chain we need to make sure that every time
we resolve a frame the dwfl is attached. This is important as context
switches force us to change the symbol table.
Change-Id: I9e5849eefef6780f822166e8c6a798749d18fce2
Reviewed-by: Milian Wolff <milian.wolff@kdab.com>
-rw-r--r-- | app/perfunwind.cpp | 40 | ||||
-rw-r--r-- | app/perfunwind.h | 2 |
2 files changed, 26 insertions, 16 deletions
diff --git a/app/perfunwind.cpp b/app/perfunwind.cpp index fab3e15..9680683 100644 --- a/app/perfunwind.cpp +++ b/app/perfunwind.cpp @@ -365,8 +365,9 @@ 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); dwfl_getthread_frames(dwfl, m_currentUnwind.sample->pid(), frameCallback, &m_currentUnwind); if (m_currentUnwind.isInterworking) { QVector<qint32> savedFrames = m_currentUnwind.frames; @@ -417,12 +418,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 +511,8 @@ 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 *symbols = symbolTable(isKernel ? s_kernelPid : sample.pid()); + PerfSymbolTable *kernelSymbols = symbolTable(s_kernelPid); + PerfSymbolTable *userSymbols = symbolTable(sample.pid()); for (int unwindingAttempt = 0; unwindingAttempt < 2; ++unwindingAttempt) { m_currentUnwind.isInterworking = false; @@ -517,32 +520,39 @@ void PerfUnwind::analyze(const PerfRecordSample &sample) m_currentUnwind.sample = &sample; m_currentUnwind.frames.clear(); - symbols->updatePerfMap(); - - Dwfl *dwfl = symbols->attachDwfl(&m_currentUnwind); + userSymbols->updatePerfMap(); 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 (!symbols->cacheIsDirty()) { - if (dwfl && sample.registerAbi() != 0 && sample.userStack().length() > 0) - unwindStack(dwfl); - 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 (symbols->cacheIsDirty()) - symbols->clearCache(); // fail, try again - else + if (userDirty) + userSymbols->clearCache(); // fail, try again + if (kernelDirty) + kernelSymbols->clearCache(); + if (!userDirty && !kernelDirty) break; // success } // If nothing was found, at least look up the IP if (m_currentUnwind.frames.isEmpty()) { - 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)); } diff --git a/app/perfunwind.h b/app/perfunwind.h index a18d6a0..82713a3 100644 --- a/app/perfunwind.h +++ b/app/perfunwind.h @@ -284,7 +284,7 @@ private: Stats m_stats; - void unwindStack(Dwfl *dwfl); + void unwindStack(); void resolveCallchain(); void analyze(const PerfRecordSample &sample); void sendBuffer(const QByteArray &buffer); |