summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2015-11-05 15:04:34 +0100
committerUlf Hermann <ulf.hermann@theqtcompany.com>2015-11-10 11:00:32 +0000
commit0e2b2f9135cac094e2486a664b3da4edf1c49ed5 (patch)
tree2e2d85740dc82e4af520c5786718757a56a5ed52
parent5f823442f9e655768622b226ec63056068852a55 (diff)
Buffer samples before analyzing them
perf may give us samples before the MMAPs which define the DSOs they refer to. This leads to breakage when trying to unwind those same samples. By buffering the samples until the MMAPs have been processed we can avoid this. The ring buffer the kernel uses for recording is usually about 512k in size. Thus, by buffering more than that we can be pretty sure that by the time we start analyzing a sample we have processed all MMAPs that were in the ring buffer at the time we received it. Change-Id: Iec02ff968d82698b9952375a63b915aed54fc15d Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
-rw-r--r--app/perfdata.cpp2
-rw-r--r--app/perfdata.h1
-rw-r--r--app/perfunwind.cpp20
-rw-r--r--app/perfunwind.h6
4 files changed, 25 insertions, 4 deletions
diff --git a/app/perfdata.cpp b/app/perfdata.cpp
index 5b498c3..fa831dd 100644
--- a/app/perfdata.cpp
+++ b/app/perfdata.cpp
@@ -93,7 +93,7 @@ PerfData::ReadStatus PerfData::processEvents(QDataStream &stream)
// TODO: for this we have to find the right attribute by some kind of hash and id ...
PerfRecordSample sample(&m_eventHeader, sampleAttrs);
stream >> sample;
- m_destination->analyze(sample);
+ m_destination->sample(sample);
break;
}
case PERF_RECORD_MMAP2: {
diff --git a/app/perfdata.h b/app/perfdata.h
index 3c85390..7b3a1f6 100644
--- a/app/perfdata.h
+++ b/app/perfdata.h
@@ -361,6 +361,7 @@ public:
quint64 ip() const { return m_ip; }
const QByteArray &userStack() const { return m_userStack; }
const QList<quint64> &callchain() const { return m_callchain; }
+ uint size() const { return m_header.size; }
private:
struct ReadFormat {
diff --git a/app/perfunwind.cpp b/app/perfunwind.cpp
index f8c8bf3..b8f304a 100644
--- a/app/perfunwind.cpp
+++ b/app/perfunwind.cpp
@@ -31,8 +31,8 @@ static const QChar colon = QLatin1Char(':');
PerfUnwind::PerfUnwind(QIODevice *output, const QString &systemRoot, const QString &debugPath,
const QString &extraLibsPath, const QString &appPath) :
- output(output), lastPid(0), registerArch(PerfRegisterInfo::ARCH_INVALID),
- systemRoot(systemRoot), extraLibsPath(extraLibsPath), appPath(appPath)
+ output(output), registerArch(PerfRegisterInfo::ARCH_INVALID), systemRoot(systemRoot),
+ extraLibsPath(extraLibsPath), appPath(appPath), sampleBufferSize(0)
{
currentUnwind.unwind = this;
offlineCallbacks.find_elf = dwfl_build_id_find_elf;
@@ -49,6 +49,9 @@ PerfUnwind::PerfUnwind(QIODevice *output, const QString &systemRoot, const QStri
PerfUnwind::~PerfUnwind()
{
+ foreach (const PerfRecordSample &sample, sampleBuffer)
+ analyze(sample);
+
delete[] debugInfoPath;
dwfl_end(dwfl);
}
@@ -405,6 +408,19 @@ void PerfUnwind::resolveCallchain()
}
}
+void PerfUnwind::sample(const PerfRecordSample &sample)
+{
+ sampleBuffer.append(sample);
+ sampleBufferSize += sample.size();
+
+ while (sampleBufferSize > maxSampleBufferSize) {
+ const PerfRecordSample &sample = sampleBuffer.front();
+ sampleBufferSize -= sample.size();
+ analyze(sample);
+ sampleBuffer.removeFirst();
+ }
+}
+
void PerfUnwind::analyze(const PerfRecordSample &sample)
{
if (sample.pid() != lastPid) {
diff --git a/app/perfunwind.h b/app/perfunwind.h
index 3a013a5..2095130 100644
--- a/app/perfunwind.h
+++ b/app/perfunwind.h
@@ -90,8 +90,8 @@ public:
quint32 pid() const { return lastPid; }
Dwfl_Module *reportElf(quint64 ip, quint32 pid, const ElfInfo **info = 0) const;
+ void sample(const PerfRecordSample &sample);
- void analyze(const PerfRecordSample &sample);
void fork(const PerfRecordFork &sample);
void exit(const PerfRecordExit &sample);
@@ -133,9 +133,13 @@ private:
QString appPath;
QHash<quint32, QMap<quint64, ElfInfo> > elfs; // The inner map needs to be sorted
+ QList<PerfRecordSample> sampleBuffer;
+ uint sampleBufferSize;
+ static const uint maxSampleBufferSize = 1024 * 1024;
void unwindStack();
void resolveCallchain();
+ void analyze(const PerfRecordSample &sample);
};
#endif // PERFUNWIND_H