]> git.saurik.com Git - apple/javascriptcore.git/blob - profiler/ProfileNode.cpp
JavaScriptCore-521.tar.gz
[apple/javascriptcore.git] / profiler / ProfileNode.cpp
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 "DateMath.h"
33 #include "Profiler.h"
34 #include <stdio.h>
35
36 #if PLATFORM(WIN_OS)
37 #include <windows.h>
38 #endif
39
40 namespace JSC {
41
42 static double getCount()
43 {
44 #if PLATFORM(WIN_OS)
45 static LARGE_INTEGER frequency = {0};
46 if (!frequency.QuadPart)
47 QueryPerformanceFrequency(&frequency);
48 LARGE_INTEGER counter;
49 QueryPerformanceCounter(&counter);
50 return static_cast<double>(counter.QuadPart) / frequency.QuadPart;
51 #else
52 return getCurrentUTCTimeWithMicroseconds();
53 #endif
54 }
55
56 ProfileNode::ProfileNode(const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
57 : m_callIdentifier(callIdentifier)
58 , m_head(headNode)
59 , m_parent(parentNode)
60 , m_nextSibling(0)
61 , m_startTime(0.0)
62 , m_actualTotalTime(0.0)
63 , m_visibleTotalTime(0.0)
64 , m_actualSelfTime(0.0)
65 , m_visibleSelfTime(0.0)
66 , m_numberOfCalls(0)
67 , m_visible(true)
68 {
69 startTimer();
70 }
71
72 ProfileNode::ProfileNode(ProfileNode* headNode, ProfileNode* nodeToCopy)
73 : m_callIdentifier(nodeToCopy->callIdentifier())
74 , m_head(headNode)
75 , m_parent(nodeToCopy->parent())
76 , m_nextSibling(0)
77 , m_startTime(0.0)
78 , m_actualTotalTime(nodeToCopy->actualTotalTime())
79 , m_visibleTotalTime(nodeToCopy->totalTime())
80 , m_actualSelfTime(nodeToCopy->actualSelfTime())
81 , m_visibleSelfTime(nodeToCopy->selfTime())
82 , m_numberOfCalls(nodeToCopy->numberOfCalls())
83 , m_visible(nodeToCopy->visible())
84 {
85 }
86
87 ProfileNode* ProfileNode::willExecute(const CallIdentifier& callIdentifier)
88 {
89 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
90 if ((*currentChild)->callIdentifier() == callIdentifier) {
91 (*currentChild)->startTimer();
92 return (*currentChild).get();
93 }
94 }
95
96 RefPtr<ProfileNode> newChild = ProfileNode::create(callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
97 if (m_children.size())
98 m_children.last()->setNextSibling(newChild.get());
99 m_children.append(newChild.release());
100 return m_children.last().get();
101 }
102
103 ProfileNode* ProfileNode::didExecute()
104 {
105 endAndRecordCall();
106 return m_parent;
107 }
108
109 void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
110 {
111 RefPtr<ProfileNode> child = prpChild;
112 child->setParent(this);
113 if (m_children.size())
114 m_children.last()->setNextSibling(child.get());
115 m_children.append(child.release());
116 }
117
118 ProfileNode* ProfileNode::findChild(ProfileNode* node) const
119 {
120 if (!node)
121 return 0;
122
123 for (size_t i = 0; i < m_children.size(); ++i) {
124 if (*node == m_children[i].get())
125 return m_children[i].get();
126 }
127
128 return 0;
129 }
130
131 void ProfileNode::removeChild(ProfileNode* node)
132 {
133 if (!node)
134 return;
135
136 for (size_t i = 0; i < m_children.size(); ++i) {
137 if (*node == m_children[i].get()) {
138 m_children.remove(i);
139 break;
140 }
141 }
142
143 resetChildrensSiblings();
144 }
145
146 void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
147 {
148 RefPtr<ProfileNode> node = prpNode;
149
150 for (unsigned i = 0; i < m_children.size(); ++i)
151 node->addChild(m_children[i].release());
152
153 m_children.clear();
154 m_children.append(node.release());
155 }
156
157 void ProfileNode::stopProfiling()
158 {
159 if (m_startTime)
160 endAndRecordCall();
161
162 m_visibleTotalTime = m_actualTotalTime;
163
164 ASSERT(m_actualSelfTime == 0.0 && m_startTime == 0.0);
165
166 // Because we iterate in post order all of our children have been stopped before us.
167 for (unsigned i = 0; i < m_children.size(); ++i)
168 m_actualSelfTime += m_children[i]->totalTime();
169
170 ASSERT(m_actualSelfTime <= m_actualTotalTime);
171 m_actualSelfTime = m_actualTotalTime - m_actualSelfTime;
172 m_visibleSelfTime = m_actualSelfTime;
173 }
174
175 ProfileNode* ProfileNode::traverseNextNodePostOrder() const
176 {
177 ProfileNode* next = m_nextSibling;
178 if (!next)
179 return m_parent;
180 while (ProfileNode* firstChild = next->firstChild())
181 next = firstChild;
182 return next;
183 }
184
185 ProfileNode* ProfileNode::traverseNextNodePreOrder(bool processChildren) const
186 {
187 if (processChildren && m_children.size())
188 return m_children[0].get();
189
190 if (m_nextSibling)
191 return m_nextSibling;
192
193 ProfileNode* nextParent = m_parent;
194 if (!nextParent)
195 return 0;
196
197 ProfileNode* next;
198 for (next = m_parent->nextSibling(); !next; next = nextParent->nextSibling()) {
199 nextParent = nextParent->parent();
200 if (!nextParent)
201 return 0;
202 }
203
204 return next;
205 }
206
207 void ProfileNode::sort(bool comparator(const RefPtr<ProfileNode>& , const RefPtr<ProfileNode>& ))
208 {
209 std::sort(childrenBegin(), childrenEnd(), comparator);
210 resetChildrensSiblings();
211 }
212
213 void 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
227 void 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
239 bool 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
255 void 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
264 void ProfileNode::restore()
265 {
266 m_visibleTotalTime = m_actualTotalTime;
267 m_visibleSelfTime = m_actualSelfTime;
268 m_visible = true;
269 }
270
271 void ProfileNode::endAndRecordCall()
272 {
273 m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0;
274 m_startTime = 0.0;
275
276 ++m_numberOfCalls;
277 }
278
279 void ProfileNode::startTimer()
280 {
281 if (!m_startTime)
282 m_startTime = getCount();
283 }
284
285 void 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
293 void ProfileNode::debugPrintData(int indentLevel) const
294 {
295 // Print function names
296 for (int i = 0; i < indentLevel; ++i)
297 printf(" ");
298
299 printf("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
300 functionName().UTF8String().c_str(),
301 m_numberOfCalls, m_actualSelfTime, selfPercent(), m_actualTotalTime, totalPercent(),
302 m_visibleSelfTime, m_visibleTotalTime,
303 (m_visible ? "True" : "False"),
304 m_nextSibling ? m_nextSibling->functionName().UTF8String().c_str() : "");
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.
314 double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
315 {
316 printf(" ");
317
318 // Print function names
319 const char* name = functionName().UTF8String().c_str();
320 double sampleCount = m_actualTotalTime * 1000;
321 if (indentLevel) {
322 for (int i = 0; i < indentLevel; ++i)
323 printf(" ");
324
325 countedFunctions.add(functionName().rep());
326
327 printf("%.0f %s\n", sampleCount ? sampleCount : 1, name);
328 } else
329 printf("%s\n", name);
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) {
341 printf(" ");
342 while (indentLevel--)
343 printf(" ");
344
345 printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().UTF8String().c_str());
346 }
347
348 return m_actualTotalTime;
349 }
350 #endif
351
352 } // namespace JSC