]> git.saurik.com Git - apple/javascriptcore.git/blame - profiler/ProfileNode.cpp
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / profiler / ProfileNode.cpp
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 2008 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 Computer, 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
93a37866 32#include "LegacyProfiler.h"
9dae56ea 33#include <stdio.h>
ba379fdc 34#include <wtf/DateMath.h>
6fe7ccc8 35#include <wtf/DataLog.h>
4e4e5a6f 36#include <wtf/text/StringHash.h>
9dae56ea 37
f9bf01c6 38#if OS(WINDOWS)
9dae56ea
A
39#include <windows.h>
40#endif
41
f9bf01c6
A
42using namespace WTF;
43
9dae56ea
A
44namespace JSC {
45
46static double getCount()
47{
f9bf01c6 48#if OS(WINDOWS)
14957cd0 49 static LARGE_INTEGER frequency;
9dae56ea
A
50 if (!frequency.QuadPart)
51 QueryPerformanceFrequency(&frequency);
52 LARGE_INTEGER counter;
53 QueryPerformanceCounter(&counter);
54 return static_cast<double>(counter.QuadPart) / frequency.QuadPart;
55#else
f9bf01c6 56 return currentTimeMS();
9dae56ea
A
57#endif
58}
59
14957cd0
A
60ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
61 : m_callerCallFrame(callerCallFrame)
62 , m_callIdentifier(callIdentifier)
9dae56ea
A
63 , m_head(headNode)
64 , m_parent(parentNode)
65 , m_nextSibling(0)
66 , m_startTime(0.0)
67 , m_actualTotalTime(0.0)
68 , m_visibleTotalTime(0.0)
69 , m_actualSelfTime(0.0)
70 , m_visibleSelfTime(0.0)
71 , m_numberOfCalls(0)
72 , m_visible(true)
73{
74 startTimer();
75}
76
14957cd0
A
77ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy)
78 : m_callerCallFrame(callerCallFrame)
79 , m_callIdentifier(nodeToCopy->callIdentifier())
9dae56ea
A
80 , m_head(headNode)
81 , m_parent(nodeToCopy->parent())
82 , m_nextSibling(0)
83 , m_startTime(0.0)
84 , m_actualTotalTime(nodeToCopy->actualTotalTime())
85 , m_visibleTotalTime(nodeToCopy->totalTime())
86 , m_actualSelfTime(nodeToCopy->actualSelfTime())
87 , m_visibleSelfTime(nodeToCopy->selfTime())
88 , m_numberOfCalls(nodeToCopy->numberOfCalls())
89 , m_visible(nodeToCopy->visible())
90{
91}
92
14957cd0 93ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
9dae56ea
A
94{
95 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
96 if ((*currentChild)->callIdentifier() == callIdentifier) {
97 (*currentChild)->startTimer();
98 return (*currentChild).get();
99 }
100 }
101
14957cd0 102 RefPtr<ProfileNode> newChild = ProfileNode::create(callerCallFrame, callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
9dae56ea
A
103 if (m_children.size())
104 m_children.last()->setNextSibling(newChild.get());
105 m_children.append(newChild.release());
106 return m_children.last().get();
107}
108
109ProfileNode* ProfileNode::didExecute()
110{
111 endAndRecordCall();
112 return m_parent;
113}
114
115void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
116{
117 RefPtr<ProfileNode> child = prpChild;
118 child->setParent(this);
119 if (m_children.size())
120 m_children.last()->setNextSibling(child.get());
121 m_children.append(child.release());
122}
123
124ProfileNode* ProfileNode::findChild(ProfileNode* node) const
125{
126 if (!node)
127 return 0;
128
129 for (size_t i = 0; i < m_children.size(); ++i) {
130 if (*node == m_children[i].get())
131 return m_children[i].get();
132 }
133
134 return 0;
135}
136
137void ProfileNode::removeChild(ProfileNode* node)
138{
139 if (!node)
140 return;
141
142 for (size_t i = 0; i < m_children.size(); ++i) {
143 if (*node == m_children[i].get()) {
144 m_children.remove(i);
145 break;
146 }
147 }
148
149 resetChildrensSiblings();
150}
151
152void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
153{
154 RefPtr<ProfileNode> node = prpNode;
155
156 for (unsigned i = 0; i < m_children.size(); ++i)
157 node->addChild(m_children[i].release());
158
159 m_children.clear();
160 m_children.append(node.release());
161}
162
163void ProfileNode::stopProfiling()
164{
165 if (m_startTime)
166 endAndRecordCall();
167
168 m_visibleTotalTime = m_actualTotalTime;
169
170 ASSERT(m_actualSelfTime == 0.0 && m_startTime == 0.0);
171
172 // Because we iterate in post order all of our children have been stopped before us.
173 for (unsigned i = 0; i < m_children.size(); ++i)
174 m_actualSelfTime += m_children[i]->totalTime();
175
176 ASSERT(m_actualSelfTime <= m_actualTotalTime);
177 m_actualSelfTime = m_actualTotalTime - m_actualSelfTime;
178 m_visibleSelfTime = m_actualSelfTime;
179}
180
181ProfileNode* ProfileNode::traverseNextNodePostOrder() const
182{
183 ProfileNode* next = m_nextSibling;
184 if (!next)
185 return m_parent;
186 while (ProfileNode* firstChild = next->firstChild())
187 next = firstChild;
188 return next;
189}
190
191ProfileNode* ProfileNode::traverseNextNodePreOrder(bool processChildren) const
192{
193 if (processChildren && m_children.size())
194 return m_children[0].get();
195
196 if (m_nextSibling)
197 return m_nextSibling;
198
199 ProfileNode* nextParent = m_parent;
200 if (!nextParent)
201 return 0;
202
203 ProfileNode* next;
204 for (next = m_parent->nextSibling(); !next; next = nextParent->nextSibling()) {
205 nextParent = nextParent->parent();
206 if (!nextParent)
207 return 0;
208 }
209
210 return next;
211}
212
9dae56ea
A
213void ProfileNode::setTreeVisible(ProfileNode* node, bool visible)
214{
215 ProfileNode* nodeParent = node->parent();
216 ProfileNode* nodeSibling = node->nextSibling();
217 node->setParent(0);
218 node->setNextSibling(0);
219
220 for (ProfileNode* currentNode = node; currentNode; currentNode = currentNode->traverseNextNodePreOrder())
221 currentNode->setVisible(visible);
222
223 node->setParent(nodeParent);
224 node->setNextSibling(nodeSibling);
225}
226
227void ProfileNode::calculateVisibleTotalTime()
228{
229 double sumOfVisibleChildrensTime = 0.0;
230
231 for (unsigned i = 0; i < m_children.size(); ++i) {
232 if (m_children[i]->visible())
233 sumOfVisibleChildrensTime += m_children[i]->totalTime();
234 }
235
236 m_visibleTotalTime = m_visibleSelfTime + sumOfVisibleChildrensTime;
237}
238
239bool ProfileNode::focus(const CallIdentifier& callIdentifier)
240{
241 if (!m_visible)
242 return false;
243
244 if (m_callIdentifier != callIdentifier) {
245 m_visible = false;
246 return true;
247 }
248
249 for (ProfileNode* currentParent = m_parent; currentParent; currentParent = currentParent->parent())
250 currentParent->setVisible(true);
251
252 return false;
253}
254
255void ProfileNode::exclude(const CallIdentifier& callIdentifier)
256{
257 if (m_visible && m_callIdentifier == callIdentifier) {
258 setTreeVisible(this, false);
259
260 m_parent->setVisibleSelfTime(m_parent->selfTime() + m_visibleTotalTime);
261 }
262}
263
264void ProfileNode::restore()
265{
266 m_visibleTotalTime = m_actualTotalTime;
267 m_visibleSelfTime = m_actualSelfTime;
268 m_visible = true;
269}
270
271void ProfileNode::endAndRecordCall()
272{
273 m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0;
274 m_startTime = 0.0;
275
276 ++m_numberOfCalls;
277}
278
279void ProfileNode::startTimer()
280{
281 if (!m_startTime)
282 m_startTime = getCount();
283}
284
285void ProfileNode::resetChildrensSiblings()
286{
287 unsigned size = m_children.size();
288 for (unsigned i = 0; i < size; ++i)
289 m_children[i]->setNextSibling(i + 1 == size ? 0 : m_children[i + 1].get());
290}
291
292#ifndef NDEBUG
293void ProfileNode::debugPrintData(int indentLevel) const
294{
295 // Print function names
296 for (int i = 0; i < indentLevel; ++i)
93a37866 297 dataLogF(" ");
9dae56ea 298
93a37866 299 dataLogF("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
14957cd0 300 functionName().utf8().data(),
9dae56ea
A
301 m_numberOfCalls, m_actualSelfTime, selfPercent(), m_actualTotalTime, totalPercent(),
302 m_visibleSelfTime, m_visibleTotalTime,
303 (m_visible ? "True" : "False"),
14957cd0 304 m_nextSibling ? m_nextSibling->functionName().utf8().data() : "");
9dae56ea
A
305
306 ++indentLevel;
307
308 // Print children's names and information
309 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
310 (*currentChild)->debugPrintData(indentLevel);
311}
312
313// print the profiled data in a format that matches the tool sample's output.
314double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
315{
93a37866 316 dataLogF(" ");
9dae56ea
A
317
318 // Print function names
14957cd0 319 const char* name = functionName().utf8().data();
9dae56ea
A
320 double sampleCount = m_actualTotalTime * 1000;
321 if (indentLevel) {
322 for (int i = 0; i < indentLevel; ++i)
93a37866 323 dataLogF(" ");
9dae56ea 324
14957cd0 325 countedFunctions.add(functionName().impl());
9dae56ea 326
93a37866 327 dataLogF("%.0f %s\n", sampleCount ? sampleCount : 1, name);
9dae56ea 328 } else
93a37866 329 dataLogF("%s\n", name);
9dae56ea
A
330
331 ++indentLevel;
332
333 // Print children's names and information
334 double sumOfChildrensCount = 0.0;
335 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
336 sumOfChildrensCount += (*currentChild)->debugPrintDataSampleStyle(indentLevel, countedFunctions);
337
338 sumOfChildrensCount *= 1000; //
339 // Print remainder of samples to match sample's output
340 if (sumOfChildrensCount < sampleCount) {
93a37866 341 dataLogF(" ");
9dae56ea 342 while (indentLevel--)
93a37866 343 dataLogF(" ");
9dae56ea 344
93a37866 345 dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data());
9dae56ea
A
346 }
347
348 return m_actualTotalTime;
349}
350#endif
351
352} // namespace JSC