]> git.saurik.com Git - apple/javascriptcore.git/blob - profiler/ProfileNode.cpp
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / profiler / ProfileNode.cpp
1 /*
2 * Copyright (C) 2008, 2014 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 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30 #include "ProfileNode.h"
31
32 #include "LegacyProfiler.h"
33 #include <wtf/DateMath.h>
34 #include <wtf/DataLog.h>
35 #include <wtf/text/StringHash.h>
36
37 using namespace WTF;
38
39 namespace JSC {
40
41 ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
42 : m_callerCallFrame(callerCallFrame)
43 , m_callIdentifier(callIdentifier)
44 , m_head(headNode)
45 , m_parent(parentNode)
46 , m_nextSibling(nullptr)
47 , m_totalTime(0)
48 , m_selfTime(0)
49 {
50 startTimer();
51 }
52
53 ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy)
54 : m_callerCallFrame(callerCallFrame)
55 , m_callIdentifier(nodeToCopy->callIdentifier())
56 , m_head(headNode)
57 , m_parent(nodeToCopy->parent())
58 , m_nextSibling(0)
59 , m_totalTime(nodeToCopy->totalTime())
60 , m_selfTime(nodeToCopy->selfTime())
61 , m_calls(nodeToCopy->calls())
62 {
63 }
64
65 ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
66 {
67 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
68 if ((*currentChild)->callIdentifier() == callIdentifier) {
69 (*currentChild)->startTimer();
70 return (*currentChild).get();
71 }
72 }
73
74 RefPtr<ProfileNode> newChild = ProfileNode::create(callerCallFrame, callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
75 if (m_children.size())
76 m_children.last()->setNextSibling(newChild.get());
77 m_children.append(newChild.release());
78 return m_children.last().get();
79 }
80
81 ProfileNode* ProfileNode::didExecute()
82 {
83 endAndRecordCall();
84 return m_parent;
85 }
86
87 void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
88 {
89 RefPtr<ProfileNode> child = prpChild;
90 child->setParent(this);
91 if (m_children.size())
92 m_children.last()->setNextSibling(child.get());
93 m_children.append(child.release());
94 }
95
96 void ProfileNode::removeChild(ProfileNode* node)
97 {
98 if (!node)
99 return;
100
101 for (size_t i = 0; i < m_children.size(); ++i) {
102 if (*node == m_children[i].get()) {
103 m_children.remove(i);
104 break;
105 }
106 }
107
108 resetChildrensSiblings();
109 }
110
111 void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
112 {
113 RefPtr<ProfileNode> node = prpNode;
114
115 for (unsigned i = 0; i < m_children.size(); ++i)
116 node->addChild(m_children[i].release());
117
118 m_children.clear();
119 m_children.append(node.release());
120 }
121
122 void ProfileNode::stopProfiling()
123 {
124 ASSERT(!m_calls.isEmpty());
125
126 if (isnan(m_calls.last().totalTime()))
127 endAndRecordCall();
128
129 // Because we iterate in post order all of our children have been stopped before us.
130 for (unsigned i = 0; i < m_children.size(); ++i)
131 m_selfTime += m_children[i]->totalTime();
132
133 ASSERT(m_selfTime <= m_totalTime);
134 m_selfTime = m_totalTime - m_selfTime;
135 }
136
137 ProfileNode* ProfileNode::traverseNextNodePostOrder() const
138 {
139 ProfileNode* next = m_nextSibling;
140 if (!next)
141 return m_parent;
142 while (ProfileNode* firstChild = next->firstChild())
143 next = firstChild;
144 return next;
145 }
146
147 void ProfileNode::endAndRecordCall()
148 {
149 Call& last = lastCall();
150 ASSERT(isnan(last.totalTime()));
151
152 last.setTotalTime(currentTime() - last.startTime());
153
154 m_totalTime += last.totalTime();
155 }
156
157 void ProfileNode::startTimer()
158 {
159 m_calls.append(Call(currentTime()));
160 }
161
162 void ProfileNode::resetChildrensSiblings()
163 {
164 unsigned size = m_children.size();
165 for (unsigned i = 0; i < size; ++i)
166 m_children[i]->setNextSibling(i + 1 == size ? 0 : m_children[i + 1].get());
167 }
168
169 #ifndef NDEBUG
170 void ProfileNode::debugPrintData(int indentLevel) const
171 {
172 // Print function names
173 for (int i = 0; i < indentLevel; ++i)
174 dataLogF(" ");
175
176 dataLogF("Function Name %s %zu SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% Next Sibling %s\n",
177 functionName().utf8().data(),
178 numberOfCalls(), m_selfTime, selfPercent(), m_totalTime, totalPercent(),
179 m_nextSibling ? m_nextSibling->functionName().utf8().data() : "");
180
181 ++indentLevel;
182
183 // Print children's names and information
184 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
185 (*currentChild)->debugPrintData(indentLevel);
186 }
187
188 // print the profiled data in a format that matches the tool sample's output.
189 double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
190 {
191 dataLogF(" ");
192
193 // Print function names
194 const char* name = functionName().utf8().data();
195 double sampleCount = m_totalTime * 1000;
196 if (indentLevel) {
197 for (int i = 0; i < indentLevel; ++i)
198 dataLogF(" ");
199
200 countedFunctions.add(functionName().impl());
201
202 dataLogF("%.0f %s\n", sampleCount ? sampleCount : 1, name);
203 } else
204 dataLogF("%s\n", name);
205
206 ++indentLevel;
207
208 // Print children's names and information
209 double sumOfChildrensCount = 0.0;
210 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
211 sumOfChildrensCount += (*currentChild)->debugPrintDataSampleStyle(indentLevel, countedFunctions);
212
213 sumOfChildrensCount *= 1000; //
214 // Print remainder of samples to match sample's output
215 if (sumOfChildrensCount < sampleCount) {
216 dataLogF(" ");
217 while (indentLevel--)
218 dataLogF(" ");
219
220 dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data());
221 }
222
223 return m_totalTime;
224 }
225 #endif
226
227 } // namespace JSC