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

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/profiler/ProfileNode.cpp