From 45ea8df187d5dbe2776d793752d1eb3bf34b8fb3 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 28 Jul 2015 12:41:31 +0000 Subject: Implement support for providing information to Linux's perf JIT interface. For more information on what this is, see: https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt [ChangeLog][QtQml][Profiling] QtQml can now write additional information so that perf is able to give function names of JavaScript methods when profiling. To enable this, set the environment variable QV4_PROFILE_WRITE_PERF_MAP=1 when running the process in question. Change-Id: I187c9b0792f40d93c89a986c0edb3c4487095cb7 Reviewed-by: Ulf Hermann --- src/qml/jit/qv4isel_masm.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index acead2088b..5dfd891b80 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -45,6 +45,7 @@ #include "qv4binop_p.h" #include +#include #include #include @@ -120,6 +121,19 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput, const Q qDebug("%s", processedOutput.constData()); } +#if defined(Q_OS_LINUX) +static FILE *pmap; + +static void qt_closePmap() +{ + if (pmap) { + fclose(pmap); + pmap = 0; + } +} + +#endif + JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) { Label endOfCode = label(); @@ -167,6 +181,8 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) *codeSize = linkBuffer.offsetOf(endOfCode); + QByteArray name; + JSC::MacroAssemblerCodeRef codeRef; static bool showCode = !qgetenv("QV4_SHOW_ASM").isNull(); @@ -175,7 +191,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) buf.open(QIODevice::WriteOnly); WTF::setDataFile(new QIODevicePrintStream(&buf)); - QByteArray name = _function->name->toUtf8(); + name = _function->name->toUtf8(); if (name.isEmpty()) { name = QByteArray::number(quintptr(_function), 16); name.prepend("IR::Function(0x"); @@ -189,6 +205,50 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) codeRef = linkBuffer.finalizeCodeWithoutDisassembly(); } +#if defined(Q_OS_LINUX) + // This implements writing of JIT'd addresses so that perf can find the + // symbol names. + // + // Perf expects the mapping to be in a certain place and have certain + // content, for more information, see: + // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt + static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP"); + static bool profileInitialized = false; + if (doProfile && !profileInitialized) { + profileInitialized = true; + + char pname[PATH_MAX]; + snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map", + (unsigned long)QCoreApplication::applicationPid()); + + pmap = fopen(pname, "w"); + if (!pmap) + qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname); + + // make sure we clean up nicely + std::atexit(qt_closePmap); + } + + if (pmap) { + // this may have been pre-populated, if QV4_SHOW_ASM was on + if (name.isEmpty()) { + name = _function->name->toUtf8(); + if (name.isEmpty()) { + name = QByteArray::number(quintptr(_function), 16); + name.prepend("IR::Function(0x"); + name.append(")"); + } + } + + fprintf(pmap, "%llx %x %.*s\n", + (long long unsigned int)codeRef.code().executableAddress(), + *codeSize, + name.length(), + name.constData()); + fflush(pmap); + } +#endif + return codeRef; } -- cgit v1.2.3