CodeProfile.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * Copyright (C) 2012 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "config.h"
  26. #include "CodeProfile.h"
  27. #include "CodeBlock.h"
  28. #include "CodeProfiling.h"
  29. #include "LinkBuffer.h"
  30. #include "ProfileTreeNode.h"
  31. #include <wtf/Vector.h>
  32. #include <wtf/text/WTFString.h>
  33. #if PLATFORM(MAC)
  34. #include <cxxabi.h>
  35. #include <dlfcn.h>
  36. #include <execinfo.h>
  37. #endif
  38. namespace JSC {
  39. // Map from CodeType enum to a corresponding name.
  40. const char* CodeProfile::s_codeTypeNames[CodeProfile::NumberOfCodeTypes] = {
  41. "[[EngineCode]]",
  42. "[[GlobalThunk]]",
  43. "[[RegExpCode]]",
  44. "[[DFGJIT]]",
  45. "[[BaselineOnly]]",
  46. "[[BaselineProfile]]",
  47. "[[BaselineOSR]]",
  48. "[[EngineFrame]]"
  49. };
  50. // Helper function, find the symbol name for a pc in JSC.
  51. static const char* symbolName(void* address)
  52. {
  53. #if PLATFORM(MAC)
  54. Dl_info info;
  55. if (!dladdr(address, &info) || !info.dli_sname)
  56. return "<unknown>";
  57. const char* mangledName = info.dli_sname;
  58. const char* cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
  59. return cxaDemangled ? cxaDemangled : mangledName;
  60. #else
  61. UNUSED_PARAM(address);
  62. return "<unknown>";
  63. #endif
  64. }
  65. // Helper function, truncate traces to prune the output & make very verbose mode a little more readable.
  66. static bool truncateTrace(const char* symbolName)
  67. {
  68. return !strcmp(symbolName, "JSC::BytecodeGenerator::generate()")
  69. || !strcmp(symbolName, "JSC::Parser<JSC::Lexer<unsigned char> >::parseInner()")
  70. || !strcmp(symbolName, "WTF::fastMalloc(unsigned long)")
  71. || !strcmp(symbolName, "WTF::calculateUTCOffset()")
  72. || !strcmp(symbolName, "JSC::DFG::ByteCodeParser::parseCodeBlock()");
  73. }
  74. // Each trace consists of a sequence of zero or more 'EngineFrame' entries,
  75. // followed by a sample in JIT code, or one or more 'EngineFrame' entries,
  76. // followed by a 'EngineCode' terminator.
  77. void CodeProfile::sample(void* pc, void** framePointer)
  78. {
  79. // Disallow traces containing only a 'EngineCode' terminator, without any 'EngineFrame' frames.
  80. if (!framePointer)
  81. return;
  82. while (framePointer) {
  83. CodeType type;
  84. #if ENABLE(JIT)
  85. // Determine if this sample fell in JIT code, and if so, from which JIT & why.
  86. void* ownerUID = CodeProfiling::getOwnerUIDForPC(pc);
  87. if (!ownerUID)
  88. type = EngineFrame;
  89. else if (ownerUID == GLOBAL_THUNK_ID)
  90. type = GlobalThunk;
  91. else if (ownerUID == REGEXP_CODE_ID)
  92. type = RegExpCode;
  93. else {
  94. CodeBlock* codeBlock = static_cast<CodeBlock*>(ownerUID);
  95. if (codeBlock->getJITType() == JITCode::DFGJIT)
  96. type = DFGJIT;
  97. else if (codeBlock->canCompileWithDFGState() != DFG::CanCompile)
  98. type = BaselineOnly;
  99. else if (codeBlock->replacement())
  100. type = BaselineOSR;
  101. else
  102. type = BaselineProfile;
  103. }
  104. #else
  105. type = EngineFrame;
  106. #endif
  107. // A sample in JIT code terminates the trace.
  108. m_samples.append(CodeRecord(pc, type));
  109. if (type != EngineFrame)
  110. return;
  111. #if PLATFORM(MAC) && CPU(X86_64)
  112. // Walk up the stack.
  113. pc = framePointer[1];
  114. framePointer = reinterpret_cast<void**>(*framePointer);
  115. #elif OS(LINUX) && CPU(X86)
  116. // Don't unwind the stack as some dependent third party libraries
  117. // may be compiled with -fomit-frame-pointer.
  118. framePointer = 0;
  119. #else
  120. // This platform is not yet supported!
  121. RELEASE_ASSERT_NOT_REACHED();
  122. #endif
  123. }
  124. // If we get here, we walked the entire stack without finding any frames of JIT code.
  125. m_samples.append(CodeRecord(0, EngineCode));
  126. }
  127. void CodeProfile::report()
  128. {
  129. dataLogF("<CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
  130. // How many frames of C-code to print - 0, if not verbose, 1 if verbose, up to 1024 if very verbose.
  131. unsigned recursionLimit = CodeProfiling::beVeryVerbose() ? 1024 : CodeProfiling::beVerbose();
  132. ProfileTreeNode profile;
  133. // Walk through the sample buffer.
  134. size_t trace = 0;
  135. while (trace < m_samples.size()) {
  136. // All traces are zero or more 'EngineFrame's, followed by a non-'EngineFrame'.
  137. // Scan to find the last sample in the trace.
  138. size_t lastInTrace = trace;
  139. while (m_samples[lastInTrace].type == EngineFrame)
  140. ++lastInTrace;
  141. // We use the last sample type to look up a name (used as a bucket in the profiler).
  142. ProfileTreeNode* callbacks = profile.sampleChild(s_codeTypeNames[m_samples[lastInTrace].type]);
  143. // If there are any samples in C-code, add up to recursionLimit of them into the profile tree.
  144. size_t lastEngineFrame = lastInTrace;
  145. for (unsigned count = 0; lastEngineFrame > trace && count < recursionLimit; ++count) {
  146. --lastEngineFrame;
  147. ASSERT(m_samples[lastEngineFrame].type == EngineFrame);
  148. const char* name = symbolName(m_samples[lastEngineFrame].pc);
  149. callbacks = callbacks->sampleChild(name);
  150. if (truncateTrace(name))
  151. break;
  152. }
  153. // Move on to the next trace.
  154. trace = lastInTrace + 1;
  155. ASSERT(trace <= m_samples.size());
  156. }
  157. // Output the profile tree.
  158. dataLogF("Total samples: %lld\n", static_cast<long long>(profile.childCount()));
  159. profile.dump();
  160. for (size_t i = 0 ; i < m_children.size(); ++i)
  161. m_children[i]->report();
  162. dataLogF("</CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
  163. }
  164. }