diff options
author | Eike Ziller <eike.ziller@theqtcompany.com> | 2015-11-12 13:40:17 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@theqtcompany.com> | 2015-11-12 13:40:23 +0100 |
commit | 3974c55e48057d94ecdee6dad9b2c0c5db8bf573 (patch) | |
tree | 5f175aca5497f22a78f786a4c4262715e1a00928 | |
parent | 1f81c72336e785dcb4a6fa2df9e75c46e071a497 (diff) | |
parent | 3e6026766b4f518d4c5631686a4c2b21316f1acb (diff) |
Merge remote-tracking branch 'origin/3.6'
Change-Id: I605cb170cc7147f4b90272a69c638b6c41a7a3b6
-rw-r--r-- | app/perfdata.cpp | 11 | ||||
-rw-r--r-- | app/perfdata.h | 1 | ||||
-rw-r--r-- | app/perfunwind.cpp | 96 | ||||
-rw-r--r-- | app/perfunwind.h | 8 |
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, ¤tUnwind)) { - 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, ¤tUnwind)) { + 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(¤tUnwind, 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 |