summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@theqtcompany.com>2015-11-12 13:40:17 +0100
committerEike Ziller <eike.ziller@theqtcompany.com>2015-11-12 13:40:23 +0100
commit3974c55e48057d94ecdee6dad9b2c0c5db8bf573 (patch)
tree5f175aca5497f22a78f786a4c4262715e1a00928
parent1f81c72336e785dcb4a6fa2df9e75c46e071a497 (diff)
parent3e6026766b4f518d4c5631686a4c2b21316f1acb (diff)
Merge remote-tracking branch 'origin/3.6'
-rw-r--r--app/perfdata.cpp11
-rw-r--r--app/perfdata.h1
-rw-r--r--app/perfunwind.cpp96
-rw-r--r--app/perfunwind.h8
4 files changed, 61 insertions, 55 deletions
diff --git a/app/perfdata.cpp b/app/perfdata.cpp
index 87a5fed..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: {
@@ -254,15 +254,6 @@ QDataStream &PerfRecordMmap::readFilename(QDataStream &stream, quint64 filenameL
QDataStream &PerfRecordMmap::readSampleId(QDataStream &stream)
{
stream >> m_sampleId;
-
- if (m_sampleId.sampleType() &
- (PerfEventAttributes::SAMPLE_ID_ALL | PerfEventAttributes::SAMPLE_TID)) {
- if (m_sampleId.pid() != m_pid)
- qWarning() << "ambiguous pids in mmap event" << m_sampleId.pid() << m_pid;
- if (m_sampleId.tid() != m_tid)
- qWarning() << "ambiguous tids in mmap event" << m_sampleId.tid() << m_tid;
- }
-
return stream;
}
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 2a2076c..a5d288a 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);
}
@@ -98,7 +101,10 @@ void PerfUnwind::registerElf(const PerfRecordMmap &mmap)
++i;
}
- lastPid = -1; // Throw out the dwfl state
+ if (dwfl && dwfl_pid(dwfl) == static_cast<pid_t>(mmap.pid())) {
+ dwfl_end(dwfl); // Throw out the dwfl state
+ dwfl = 0;
+ }
}
QLatin1String filePath(mmap.filename());
@@ -149,10 +155,9 @@ void PerfUnwind::comm(PerfRecordComm &comm)
Dwfl_Module *PerfUnwind::reportElf(quint64 ip, quint32 pid, const ElfInfo **info) const
{
QHash<quint32, QMap<quint64, ElfInfo> >::ConstIterator elfsIt = elfs.find(pid);
- if (elfsIt == elfs.end()) {
- qWarning() << "Process" << pid << "has no elfs";
+ if (elfsIt == elfs.end())
return 0;
- }
+
const QMap<quint64, ElfInfo> &procElfs = elfsIt.value();
QMap<quint64, ElfInfo>::ConstIterator i = procElfs.upperBound(ip);
if (i == procElfs.end() || i.key() != ip) {
@@ -212,7 +217,7 @@ static bool accessDsoMem(Dwfl *dwfl, const PerfUnwind::UnwindInfo *ui, Dwarf_Add
// TODO: Take the pgoff into account? Or does elf_getdata do that already?
Dwfl_Module *mod = dwfl_addrmodule(dwfl, addr);
if (!mod) {
- mod = ui->unwind->reportElf(addr, ui->unwind->pid());
+ mod = ui->unwind->reportElf(addr, ui->sample->pid());
if (!mod) {
mod = ui->unwind->reportElf(addr, PerfUnwind::s_kernelPid);
if (!mod)
@@ -253,11 +258,6 @@ static bool memoryRead(Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *ar
if (addr < start || addr + sizeof(Dwarf_Word) > end) {
// not stack, try reading from ELF
if (!accessDsoMem(dwfl, ui, addr, result)) {
- qWarning() << QString::fromLatin1("Cannot read memory at 0x%1").arg(addr, 0, 16);
- qWarning() << QString::fromLatin1(
- "dwfl should only read stack state (0x%1 to 0x%2) with memoryRead().")
- .arg(start, 0, 16).arg(end, 0, 16);
-
ui->broken = true;
return false;
}
@@ -293,7 +293,7 @@ static const Dwfl_Thread_Callbacks callbacks = {
static PerfUnwind::Frame lookupSymbol(PerfUnwind::UnwindInfo *ui, Dwfl *dwfl, Dwarf_Addr ip,
bool isKernel)
{
- Dwfl_Module *mod = dwfl_addrmodule (dwfl, ip);
+ Dwfl_Module *mod = dwfl ? dwfl_addrmodule(dwfl, ip) : 0;
const char *symname = NULL;
const char *elfFile = NULL;
const char *srcFile = NULL;
@@ -302,20 +302,19 @@ static PerfUnwind::Frame lookupSymbol(PerfUnwind::UnwindInfo *ui, Dwfl *dwfl, Dw
GElf_Sym sym;
GElf_Off off;
- if (!mod) {
+ if (dwfl && !mod) {
const PerfUnwind::ElfInfo *elfInfo = 0;
- mod = ui->unwind->reportElf(ip, isKernel ? PerfUnwind::s_kernelPid : ui->unwind->pid(),
+ mod = ui->unwind->reportElf(ip, isKernel ? PerfUnwind::s_kernelPid : ui->sample->pid(),
&elfInfo);
if (!mod && elfInfo)
elfFile = elfInfo->file.fileName().toLocal8Bit();
}
- bool do_adjust = (ui->unwind->architecture() == PerfRegisterInfo::ARCH_ARM);
+ Dwarf_Addr adjusted = (ui->unwind->architecture() != PerfRegisterInfo::ARCH_ARM || (ip & 1)) ?
+ ip : ip + 1;
if (mod) {
- Dwarf_Addr adjusted = (!do_adjust || (ip & 1)) ? ip : ip + 1;
// For addrinfo we need the raw pointer into symtab, so we need to adjust ourselves.
- symname = dwfl_module_addrinfo(mod, adjusted, &off, &sym, 0,
- 0, 0);
+ symname = dwfl_module_addrinfo(mod, adjusted, &off, &sym, 0, 0, 0);
elfFile = dwfl_module_info(mod, 0, 0, 0, 0, 0, 0, 0);
// We take the first line of the function for now, in order to reduce UI complexity
@@ -328,16 +327,14 @@ static PerfUnwind::Frame lookupSymbol(PerfUnwind::UnwindInfo *ui, Dwfl *dwfl, Dw
char *demangled = NULL;
int status = -1;
if (symname[0] == '_' && symname[1] == 'Z')
- demangled = abi::__cxa_demangle (symname, 0, 0, &status);
+ demangled = abi::__cxa_demangle(symname, 0, 0, &status);
else if (ui->unwind->architecture() == PerfRegisterInfo::ARCH_ARM && symname[0] == '$'
&& (symname[1] == 'a' || symname[1] == 't') && symname[2] == '\0')
ui->isInterworking = true;
// Adjust it back. The symtab entries are 1 off for all practical purposes.
- PerfUnwind::Frame frame((do_adjust && (sym.st_value & 1)) ? sym.st_value - 1 :
- sym.st_value,
- isKernel, status == 0 ? demangled : symname, elfFile, srcFile,
- line, column);
+ PerfUnwind::Frame frame(adjusted - off, isKernel, status == 0 ? demangled : symname,
+ elfFile, srcFile, line, column);
free(demangled);
return frame;
} else {
@@ -414,41 +411,56 @@ 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) {
+ currentUnwind.broken = false;
+ currentUnwind.isInterworking = false;
+ currentUnwind.sample = &sample;
+ currentUnwind.frames.clear();
+
+ if (!dwfl || static_cast<pid_t>(sample.pid()) != dwfl_pid(dwfl)) {
dwfl_end(dwfl);
dwfl = dwfl_begin(&offlineCallbacks);
- lastPid = sample.pid();
- reportElf(sample.ip(), lastPid);
+ reportElf(sample.ip(), sample.pid());
if (!dwfl) {
qWarning() << "failed to initialize dwfl" << dwfl_errmsg(dwfl_errno());
- lastPid = -1;
- return;
- }
- if (!dwfl_attach_state(dwfl, 0, sample.pid(), &callbacks, &currentUnwind)) {
- qWarning() << "failed to attach state:" << dwfl_errmsg(dwfl_errno());
- lastPid = -1;
- return;
+ currentUnwind.broken = true;
+ } else if (!dwfl_attach_state(dwfl, 0, sample.pid(), &callbacks, &currentUnwind)) {
+ qWarning() << "failed to attach state" << dwfl_errmsg(dwfl_errno());
+ currentUnwind.broken = true;
}
} else {
if (!dwfl_addrmodule (dwfl, sample.ip()))
- reportElf(sample.ip(), lastPid);
+ reportElf(sample.ip(), sample.pid());
}
- currentUnwind.broken = false;
- currentUnwind.isInterworking = false;
- currentUnwind.sample = &sample;
- currentUnwind.frames.clear();
if (sample.callchain().length() > 0)
resolveCallchain();
- if (sample.registerAbi() != 0 && sample.userStack().length() > 0)
- unwindStack();
+ if (sample.registerAbi() != 0) {
+ if (dwfl && sample.userStack().length() > 0)
+ unwindStack();
+ // If nothing was found, at least look up the IP
+ if (currentUnwind.frames.isEmpty())
+ currentUnwind.frames.append(lookupSymbol(&currentUnwind, dwfl, sample.ip(), false));
+ }
QByteArray buffer;
QDataStream(&buffer, QIODevice::WriteOnly)
- << static_cast<quint8>(currentUnwind.broken ? BadStack : GoodStack) << lastPid
+ << static_cast<quint8>(currentUnwind.broken ? BadStack : GoodStack) << sample.pid()
<< sample.tid() << threads[sample.tid()] << sample.time() << currentUnwind.frames;
sendBuffer(output, buffer);
}
diff --git a/app/perfunwind.h b/app/perfunwind.h
index 3a013a5..1e0f96d 100644
--- a/app/perfunwind.h
+++ b/app/perfunwind.h
@@ -87,11 +87,10 @@ public:
void registerElf(const PerfRecordMmap &mmap);
void comm(PerfRecordComm &comm);
- 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);
@@ -111,7 +110,6 @@ private:
UnwindInfo currentUnwind;
QIODevice *output;
- quint32 lastPid;
QHash<quint32, QString> threads;
Dwfl *dwfl;
@@ -133,9 +131,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