diff options
author | Eike Ziller <eike.ziller@qt.io> | 2017-04-18 15:01:55 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2017-04-18 15:01:55 +0200 |
commit | 11d3069202f952433682cdd8a31ceea5b82cc632 (patch) | |
tree | b93b349ad3871126fc284859f3954b1b8c9d9754 | |
parent | 4354fca122233691498b388a321c53163c2fa012 (diff) | |
parent | 2549d1b3224bdca399837b5b9c7dfc40857f8bac (diff) |
Merge remote-tracking branch 'origin/4.3'
Conflicts:
app/perfsymboltable.cpp
app/perfunwind.cpp
Change-Id: If343bb33fabeb60a3eab566769cf2c4dda88fcc5
-rw-r--r-- | app/main.cpp | 2 | ||||
-rw-r--r-- | app/perfsymboltable.cpp | 12 | ||||
-rw-r--r-- | app/perfsymboltable.h | 2 | ||||
-rw-r--r-- | app/perfunwind.cpp | 49 |
4 files changed, 48 insertions, 17 deletions
diff --git a/app/main.cpp b/app/main.cpp index 242676a..5a6023a 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -70,7 +70,7 @@ int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); app.setApplicationName(QLatin1String("perfparser")); - app.setApplicationVersion(QLatin1String("1.0")); + app.setApplicationVersion(QLatin1String("4.3")); QCommandLineParser parser; parser.setApplicationDescription(QLatin1String("Perf data parser and unwinder.")); diff --git a/app/perfsymboltable.cpp b/app/perfsymboltable.cpp index f23b0f4..5501a68 100644 --- a/app/perfsymboltable.cpp +++ b/app/perfsymboltable.cpp @@ -37,7 +37,11 @@ PerfSymbolTable::PerfSymbolTable(quint32 pid, Dwfl_Callbacks *callbacks, PerfUnwind *parent) : m_perfMapFile(QString::fromLatin1("/tmp/perf-%1.map").arg(pid)), - m_unwind(parent), m_firstElf(nullptr), m_callbacks(callbacks), m_pid(pid) + m_cacheIsDirty(false), + m_unwind(parent), + m_firstElf(nullptr), + m_callbacks(callbacks), + m_pid(pid) { m_dwfl = dwfl_begin(m_callbacks); } @@ -422,8 +426,10 @@ Dwfl_Module *PerfSymbolTable::reportElf(const PerfElfMap::ElfInfo& info) m_dwfl, info.originalFileName.constData(), info.localFile.absoluteFilePath().toLocal8Bit().constData(), -1, info.addr, false); - if (!ret) + if (!ret) { reportError(info, dwfl_errmsg(dwfl_errno())); + m_cacheIsDirty = true; + } return ret; } @@ -632,4 +638,6 @@ void PerfSymbolTable::clearCache() // Throw out the dwfl state dwfl_end(m_dwfl); m_dwfl = dwfl_begin(m_callbacks); + + m_cacheIsDirty = false; } diff --git a/app/perfsymboltable.h b/app/perfsymboltable.h index 840fa93..4f9503b 100644 --- a/app/perfsymboltable.h +++ b/app/perfsymboltable.h @@ -72,6 +72,7 @@ public: Dwfl *attachDwfl(void *arg); void clearCache(); + bool cacheIsDirty() const { return m_cacheIsDirty; } private: @@ -83,6 +84,7 @@ private: QFile m_perfMapFile; QVector<PerfMapSymbol> m_perfMap; QHash<Dwarf_Addr, AddressCacheEntry> m_addressCache; + bool m_cacheIsDirty; PerfUnwind *m_unwind; Dwfl *m_dwfl; diff --git a/app/perfunwind.cpp b/app/perfunwind.cpp index cf86b72..0878dbb 100644 --- a/app/perfunwind.cpp +++ b/app/perfunwind.cpp @@ -304,10 +304,14 @@ static int frameCallback(Dwfl_Frame *state, void *arg) Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1); + auto* symbolTable = ui->unwind->symbolTable(ui->sample->pid()); // isKernel = false as unwinding generally only works on user code bool isInterworking = false; - ui->frames.append(ui->unwind->symbolTable(ui->sample->pid())->lookupFrame( - pc_adjusted, false, &isInterworking)); + const auto frame = symbolTable->lookupFrame(pc_adjusted, false, &isInterworking); + if (symbolTable->cacheIsDirty()) + return DWARF_CB_ABORT; + + ui->frames.append(frame); if (isInterworking && ui->frames.length() == 1) ui->isInterworking = true; return DWARF_CB_OK; @@ -375,6 +379,9 @@ void PerfUnwind::resolveCallchain() ip, isKernel, &m_currentUnwind.isInterworking)); } + + if (symbols->cacheIsDirty()) + break; } } @@ -388,23 +395,37 @@ void PerfUnwind::analyze(const PerfRecordSample &sample) if (m_stats.enabled) // don't do any time intensive work in stats mode return; - m_currentUnwind.isInterworking = false; - m_currentUnwind.firstGuessedFrame = -1; - m_currentUnwind.sample = &sample; - m_currentUnwind.frames.clear(); - const bool isKernel = ipIsInKernelSpace(sample.ip()); PerfSymbolTable *userSymbols = symbolTable(sample.pid()); - userSymbols->updatePerfMap(); - // Do this before any lookupFrame() calls; we want to clear the caches if timestamps reset. - Dwfl *userDwfl = userSymbols->attachDwfl(&m_currentUnwind); - if (sample.callchain().length() > 0) - resolveCallchain(); + for (int unwindingAttempt = 0; unwindingAttempt < 2; ++unwindingAttempt) { + m_currentUnwind.isInterworking = false; + m_currentUnwind.firstGuessedFrame = -1; + m_currentUnwind.sample = &sample; + m_currentUnwind.frames.clear(); + + userSymbols->updatePerfMap(); + + Dwfl *userDwfl = userSymbols->attachDwfl(&m_currentUnwind); + if (sample.callchain().length() > 0) + resolveCallchain(); - if (userDwfl && sample.registerAbi() != 0 && sample.userStack().length() > 0) - unwindStack(userDwfl); + // 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 + 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()) + userSymbols->clearCache(); // fail, try again + else + break; // success + } // If nothing was found, at least look up the IP if (m_currentUnwind.frames.isEmpty()) { |