diff options
author | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-11-05 15:04:34 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-11-10 11:00:32 +0000 |
commit | 0e2b2f9135cac094e2486a664b3da4edf1c49ed5 (patch) | |
tree | 2e2d85740dc82e4af520c5786718757a56a5ed52 | |
parent | 5f823442f9e655768622b226ec63056068852a55 (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.cpp | 2 | ||||
-rw-r--r-- | app/perfdata.h | 1 | ||||
-rw-r--r-- | app/perfunwind.cpp | 20 | ||||
-rw-r--r-- | app/perfunwind.h | 6 |
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 |