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