aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Burchell <robin.burchell@viroteck.net>2015-07-28 12:41:31 +0000
committerRobin Burchell <robin.burchell@viroteck.net>2015-08-21 14:39:30 +0000
commit45ea8df187d5dbe2776d793752d1eb3bf34b8fb3 (patch)
tree8a1f51f2e4c620b888b0a895d92b1452c761473d
parent6328dd2d2743ed540efea89742261f24552d7611 (diff)
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 <ulf.hermann@theqtcompany.com>
-rw-r--r--src/qml/jit/qv4isel_masm.cpp62
1 files changed, 61 insertions, 1 deletions
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 <QtCore/QBuffer>
+#include <QtCore/QCoreApplication>
#include <assembler/LinkBuffer.h>
#include <WTFStubs.h>
@@ -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;
}