diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
commit | cd44dc59cdfc39534aef4d417e9f3c412e3be139 (patch) | |
tree | 8d89889ba95ed6ec9322e733846cc9cce9d7dff1 /Source/JavaScriptCore/tools/CodeProfile.cpp | |
parent | d11f84f5b5cdc0d92a08af01b13472fdd5f9acb9 (diff) | |
download | qtwebkit-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.cpp | 188 |
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); +} + +} |