123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- /*
- * 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 <wtf/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() != DFG::CanCompile)
- 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;
- #if PLATFORM(MAC) && CPU(X86_64)
- // Walk up the stack.
- pc = framePointer[1];
- framePointer = reinterpret_cast<void**>(*framePointer);
- #elif OS(LINUX) && CPU(X86)
- // Don't unwind the stack as some dependent third party libraries
- // may be compiled with -fomit-frame-pointer.
- framePointer = 0;
- #else
- // This platform is not yet supported!
- RELEASE_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()
- {
- dataLogF("<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.
- dataLogF("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();
- dataLogF("</CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
- }
- }
|