]>
git.saurik.com Git - apple/javascriptcore.git/blob - tools/CodeProfile.cpp
2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "CodeProfile.h"
29 #include "CodeBlock.h"
30 #include "CodeProfiling.h"
31 #include "LinkBuffer.h"
32 #include "ProfileTreeNode.h"
33 #include <wtf/Vector.h>
34 #include <wtf/text/WTFString.h>
44 // Map from CodeType enum to a corresponding name.
45 const char* CodeProfile::s_codeTypeNames
[CodeProfile::NumberOfCodeTypes
] = {
51 "[[BaselineProfile]]",
56 // Helper function, find the symbol name for a pc in JSC.
57 static const char* symbolName(void* address
)
61 if (!dladdr(address
, &info
) || !info
.dli_sname
)
64 const char* mangledName
= info
.dli_sname
;
65 const char* cxaDemangled
= abi::__cxa_demangle(mangledName
, 0, 0, 0);
66 return cxaDemangled
? cxaDemangled
: mangledName
;
68 UNUSED_PARAM(address
);
73 // Helper function, truncate traces to prune the output & make very verbose mode a little more readable.
74 static bool truncateTrace(const char* symbolName
)
76 return !strcmp(symbolName
, "JSC::BytecodeGenerator::generate()")
77 || !strcmp(symbolName
, "JSC::Parser<JSC::Lexer<unsigned char>>::parseInner()")
78 || !strcmp(symbolName
, "WTF::fastMalloc(unsigned long)")
79 || !strcmp(symbolName
, "WTF::calculateUTCOffset()")
80 || !strcmp(symbolName
, "JSC::DFG::ByteCodeParser::parseCodeBlock()");
84 // Each trace consists of a sequence of zero or more 'EngineFrame' entries,
85 // followed by a sample in JIT code, or one or more 'EngineFrame' entries,
86 // followed by a 'EngineCode' terminator.
87 void CodeProfile::sample(void* pc
, void** framePointer
)
89 // Disallow traces containing only a 'EngineCode' terminator, without any 'EngineFrame' frames.
93 while (framePointer
) {
97 // Determine if this sample fell in JIT code, and if so, from which JIT & why.
98 void* ownerUID
= CodeProfiling::getOwnerUIDForPC(pc
);
102 else if (ownerUID
== GLOBAL_THUNK_ID
)
104 else if (ownerUID
== REGEXP_CODE_ID
)
107 CodeBlock
* codeBlock
= static_cast<CodeBlock
*>(ownerUID
);
108 if (codeBlock
->jitType() == JITCode::DFGJIT
)
110 else if (!canCompile(codeBlock
->capabilityLevelState()))
112 else if (codeBlock
->replacement())
115 type
= BaselineProfile
;
121 // A sample in JIT code terminates the trace.
122 m_samples
.append(CodeRecord(pc
, type
));
123 if (type
!= EngineFrame
)
126 #if OS(DARWIN) && CPU(X86_64)
127 // Walk up the stack.
128 pc
= framePointer
[1];
129 framePointer
= reinterpret_cast<void**>(*framePointer
);
130 #elif OS(LINUX) && CPU(X86)
131 // Don't unwind the stack as some dependent third party libraries
132 // may be compiled with -fomit-frame-pointer.
135 // This platform is not yet supported!
136 RELEASE_ASSERT_NOT_REACHED();
140 // If we get here, we walked the entire stack without finding any frames of JIT code.
141 m_samples
.append(CodeRecord(0, EngineCode
));
144 void CodeProfile::report()
146 dataLogF("<CodeProfiling %s:%d>\n", m_file
.data(), m_lineNumber
);
148 // How many frames of C-code to print - 0, if not verbose, 1 if verbose, up to 1024 if very verbose.
149 unsigned recursionLimit
= CodeProfiling::beVeryVerbose() ? 1024 : CodeProfiling::beVerbose();
151 ProfileTreeNode profile
;
153 // Walk through the sample buffer.
155 while (trace
< m_samples
.size()) {
157 // All traces are zero or more 'EngineFrame's, followed by a non-'EngineFrame'.
158 // Scan to find the last sample in the trace.
159 size_t lastInTrace
= trace
;
160 while (m_samples
[lastInTrace
].type
== EngineFrame
)
163 // We use the last sample type to look up a name (used as a bucket in the profiler).
164 ProfileTreeNode
* callbacks
= profile
.sampleChild(s_codeTypeNames
[m_samples
[lastInTrace
].type
]);
166 // If there are any samples in C-code, add up to recursionLimit of them into the profile tree.
167 size_t lastEngineFrame
= lastInTrace
;
168 for (unsigned count
= 0; lastEngineFrame
> trace
&& count
< recursionLimit
; ++count
) {
170 ASSERT(m_samples
[lastEngineFrame
].type
== EngineFrame
);
171 const char* name
= symbolName(m_samples
[lastEngineFrame
].pc
);
172 callbacks
= callbacks
->sampleChild(name
);
173 if (truncateTrace(name
))
177 // Move on to the next trace.
178 trace
= lastInTrace
+ 1;
179 ASSERT(trace
<= m_samples
.size());
182 // Output the profile tree.
183 dataLogF("Total samples: %lld\n", static_cast<long long>(profile
.childCount()));
186 for (size_t i
= 0 ; i
< m_children
.size(); ++i
)
187 m_children
[i
]->report();
189 dataLogF("</CodeProfiling %s:%d>\n", m_file
.data(), m_lineNumber
);