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