summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/tools/CodeProfile.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-02-03 09:55:33 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-02-03 09:55:33 +0100
commitcd44dc59cdfc39534aef4d417e9f3c412e3be139 (patch)
tree8d89889ba95ed6ec9322e733846cc9cce9d7dff1 /Source/JavaScriptCore/tools/CodeProfile.cpp
parentd11f84f5b5cdc0d92a08af01b13472fdd5f9acb9 (diff)
downloadqtwebkit-cd44dc59cdfc39534aef4d417e9f3c412e3be139.tar.gz
Imported WebKit commit fce473cb4d55aa9fe9d0b0322a2fffecb731b961 (http://svn.webkit.org/repository/webkit/trunk@106560)
Diffstat (limited to 'Source/JavaScriptCore/tools/CodeProfile.cpp')
-rw-r--r--Source/JavaScriptCore/tools/CodeProfile.cpp188
1 files changed, 188 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/tools/CodeProfile.cpp b/Source/JavaScriptCore/tools/CodeProfile.cpp
new file mode 100644
index 000000000..7794f58d3
--- /dev/null
+++ b/Source/JavaScriptCore/tools/CodeProfile.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CodeProfile.h"
+
+#include "CodeBlock.h"
+#include "CodeProfiling.h"
+#include "LinkBuffer.h"
+#include "ProfileTreeNode.h"
+#include "Vector.h"
+#include <wtf/text/WTFString.h>
+
+#if PLATFORM(MAC)
+#include <cxxabi.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#endif
+
+namespace JSC {
+
+// Map from CodeType enum to a corresponding name.
+const char* CodeProfile::s_codeTypeNames[CodeProfile::NumberOfCodeTypes] = {
+ "[[EngineCode]]",
+ "[[GlobalThunk]]",
+ "[[RegExpCode]]",
+ "[[DFGJIT]]",
+ "[[BaselineOnly]]",
+ "[[BaselineProfile]]",
+ "[[BaselineOSR]]",
+ "[[EngineFrame]]"
+};
+
+// Helper function, find the symbol name for a pc in JSC.
+static const char* symbolName(void* address)
+{
+#if PLATFORM(MAC)
+ Dl_info info;
+ if (!dladdr(address, &info) || !info.dli_sname)
+ return "<unknown>";
+
+ const char* mangledName = info.dli_sname;
+ const char* cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
+ return cxaDemangled ? cxaDemangled : mangledName;
+#else
+ UNUSED_PARAM(address);
+ return "<unknown>";
+#endif
+}
+
+// Helper function, truncate traces to prune the output & make very verbose mode a little more readable.
+static bool truncateTrace(const char* symbolName)
+{
+ return !strcmp(symbolName, "JSC::BytecodeGenerator::generate()")
+ || !strcmp(symbolName, "JSC::Parser<JSC::Lexer<unsigned char> >::parseInner()")
+ || !strcmp(symbolName, "WTF::fastMalloc(unsigned long)")
+ || !strcmp(symbolName, "WTF::calculateUTCOffset()")
+ || !strcmp(symbolName, "JSC::DFG::ByteCodeParser::parseCodeBlock()");
+
+}
+
+// Each trace consists of a sequence of zero or more 'EngineFrame' entries,
+// followed by a sample in JIT code, or one or more 'EngineFrame' entries,
+// followed by a 'EngineCode' terminator.
+void CodeProfile::sample(void* pc, void** framePointer)
+{
+ // Disallow traces containing only a 'EngineCode' terminator, without any 'EngineFrame' frames.
+ if (!framePointer)
+ return;
+
+ while (framePointer) {
+ CodeType type;
+
+#if ENABLE(JIT)
+ // Determine if this sample fell in JIT code, and if so, from which JIT & why.
+ void* ownerUID = CodeProfiling::getOwnerUIDForPC(pc);
+
+ if (!ownerUID)
+ type = EngineFrame;
+ else if (ownerUID == GLOBAL_THUNK_ID)
+ type = GlobalThunk;
+ else if (ownerUID == REGEXP_CODE_ID)
+ type = RegExpCode;
+ else {
+ CodeBlock* codeBlock = static_cast<CodeBlock*>(ownerUID);
+ if (codeBlock->getJITType() == JITCode::DFGJIT)
+ type = DFGJIT;
+ else if (codeBlock->canCompileWithDFGState() == CodeBlock::CompileWithDFGFalse)
+ type = BaselineOnly;
+ else if (codeBlock->replacement())
+ type = BaselineOSR;
+ else
+ type = BaselineProfile;
+ }
+#else
+ type = EngineFrame;
+#endif
+
+ // A sample in JIT code terminates the trace.
+ m_samples.append(CodeRecord(pc, type));
+ if (type != EngineFrame)
+ return;
+
+ // Walk up the stack.
+#if PLATFORM(MAC) && CPU(X86_64)
+ pc = framePointer[1];
+ framePointer = reinterpret_cast<void**>(*framePointer);
+#else
+ // This platform is not yet supported!
+ ASSERT_NOT_REACHED();
+#endif
+ }
+
+ // If we get here, we walked the entire stack without finding any frames of JIT code.
+ m_samples.append(CodeRecord(0, EngineCode));
+}
+
+void CodeProfile::report()
+{
+ fprintf(stdout, "<CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
+
+ // How many frames of C-code to print - 0, if not verbose, 1 if verbose, up to 1024 if very verbose.
+ unsigned recursionLimit = CodeProfiling::beVeryVerbose() ? 1024 : CodeProfiling::beVerbose();
+
+ ProfileTreeNode profile;
+
+ // Walk through the sample buffer.
+ size_t trace = 0;
+ while (trace < m_samples.size()) {
+
+ // All traces are zero or more 'EngineFrame's, followed by a non-'EngineFrame'.
+ // Scan to find the last sample in the trace.
+ size_t lastInTrace = trace;
+ while (m_samples[lastInTrace].type == EngineFrame)
+ ++lastInTrace;
+
+ // We use the last sample type to look up a name (used as a bucket in the profiler).
+ ProfileTreeNode* callbacks = profile.sampleChild(s_codeTypeNames[m_samples[lastInTrace].type]);
+
+ // If there are any samples in C-code, add up to recursionLimit of them into the profile tree.
+ size_t lastEngineFrame = lastInTrace;
+ for (unsigned count = 0; lastEngineFrame > trace && count < recursionLimit; ++count) {
+ --lastEngineFrame;
+ ASSERT(m_samples[lastEngineFrame].type == EngineFrame);
+ const char* name = symbolName(m_samples[lastEngineFrame].pc);
+ callbacks = callbacks->sampleChild(name);
+ if (truncateTrace(name))
+ break;
+ }
+
+ // Move on to the next trace.
+ trace = lastInTrace + 1;
+ ASSERT(trace <= m_samples.size());
+ }
+
+ // Output the profile tree.
+ fprintf(stdout, "Total samples: %lld\n", static_cast<long long>(profile.childCount()));
+ profile.dump();
+
+ for (size_t i = 0 ; i < m_children.size(); ++i)
+ m_children[i]->report();
+
+ fprintf(stdout, "</CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
+}
+
+}