summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2017-04-18 15:01:55 +0200
committerEike Ziller <eike.ziller@qt.io>2017-04-18 15:01:55 +0200
commit11d3069202f952433682cdd8a31ceea5b82cc632 (patch)
treeb93b349ad3871126fc284859f3954b1b8c9d9754
parent4354fca122233691498b388a321c53163c2fa012 (diff)
parent2549d1b3224bdca399837b5b9c7dfc40857f8bac (diff)
Merge remote-tracking branch 'origin/4.3'
Conflicts: app/perfsymboltable.cpp app/perfunwind.cpp Change-Id: If343bb33fabeb60a3eab566769cf2c4dda88fcc5
-rw-r--r--app/main.cpp2
-rw-r--r--app/perfsymboltable.cpp12
-rw-r--r--app/perfsymboltable.h2
-rw-r--r--app/perfunwind.cpp49
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()) {