2 * Copyright (C) 2008, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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 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.
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.
32 #include "CallIdentifier.h"
33 #include <wtf/HashCountedSet.h>
34 #include <wtf/RefCounted.h>
35 #include <wtf/RefPtr.h>
36 #include <wtf/Vector.h>
43 typedef HashCountedSet
<StringImpl
*> FunctionCallHashCount
;
45 class ProfileNode
: public RefCounted
<ProfileNode
> {
47 static Ref
<ProfileNode
> create(ExecState
* callerCallFrame
, const CallIdentifier
& callIdentifier
, ProfileNode
* parentNode
)
49 return adoptRef(*new ProfileNode(callerCallFrame
, callIdentifier
, parentNode
));
52 static Ref
<ProfileNode
> create(ExecState
* callerCallFrame
, ProfileNode
* node
)
54 return adoptRef(*new ProfileNode(callerCallFrame
, node
));
59 Call(double startTime
, double elapsedTime
= NAN
)
60 : m_startTime(startTime
)
61 , m_elapsedTime(elapsedTime
)
65 double startTime() const { return m_startTime
; }
66 void setStartTime(double time
)
68 ASSERT_ARG(time
, time
>= 0.0 || std::isnan(time
));
72 double elapsedTime() const { return m_elapsedTime
; }
73 void setElapsedTime(double time
)
75 ASSERT_ARG(time
, time
>= 0.0 || std::isnan(time
));
84 bool operator==(ProfileNode
* node
) { return m_callIdentifier
== node
->callIdentifier(); }
86 ExecState
* callerCallFrame() const { return m_callerCallFrame
; }
87 const CallIdentifier
& callIdentifier() const { return m_callIdentifier
; }
88 unsigned id() const { return m_callIdentifier
.hash(); }
89 const String
& functionName() const { return m_callIdentifier
.functionName(); }
90 const String
& url() const { return m_callIdentifier
.url(); }
91 unsigned lineNumber() const { return m_callIdentifier
.lineNumber(); }
92 unsigned columnNumber() const { return m_callIdentifier
.columnNumber(); }
94 ProfileNode
* parent() const { return m_parent
; }
95 void setParent(ProfileNode
* parent
) { m_parent
= parent
; }
97 const Vector
<Call
>& calls() const { return m_calls
; }
98 Call
& lastCall() { ASSERT(!m_calls
.isEmpty()); return m_calls
.last(); }
99 void appendCall(Call call
) { m_calls
.append(call
); }
101 const Vector
<RefPtr
<ProfileNode
>>& children() const { return m_children
; }
102 ProfileNode
* firstChild() const { return m_children
.size() ? m_children
.first().get() : nullptr; }
103 ProfileNode
* lastChild() const { return m_children
.size() ? m_children
.last().get() : nullptr; }
105 void removeChild(ProfileNode
*);
106 void addChild(PassRefPtr
<ProfileNode
>);
107 // Reparent our child nodes to the passed node, and make it a child node of |this|.
108 void spliceNode(PassRefPtr
<ProfileNode
>);
111 struct ProfileSubtreeData
{
112 HashMap
<ProfileNode
*, std::pair
<double, double>> selfAndTotalTimes
;
113 double rootTotalTime
;
116 // Use these functions to dump the subtree rooted at this node.
118 void debugPrintSampleStyle();
120 // These are used to recursively print entire subtrees using precomputed self and total times.
121 template <typename Functor
> void forEachNodePostorder(Functor
&);
123 void debugPrintRecursively(int indentLevel
, const ProfileSubtreeData
&);
124 double debugPrintSampleStyleRecursively(int indentLevel
, FunctionCallHashCount
&, const ProfileSubtreeData
&);
128 typedef Vector
<RefPtr
<ProfileNode
>>::const_iterator StackIterator
;
130 ProfileNode(ExecState
* callerCallFrame
, const CallIdentifier
&, ProfileNode
* parentNode
);
131 ProfileNode(ExecState
* callerCallFrame
, ProfileNode
* nodeToCopy
);
134 ProfileNode
* nextSibling() const { return m_nextSibling
; }
135 void setNextSibling(ProfileNode
* nextSibling
) { m_nextSibling
= nextSibling
; }
137 ProfileNode
* traverseNextNodePostOrder() const;
140 ExecState
* m_callerCallFrame
;
141 CallIdentifier m_callIdentifier
;
142 ProfileNode
* m_parent
;
143 Vector
<Call
> m_calls
;
144 Vector
<RefPtr
<ProfileNode
>> m_children
;
147 ProfileNode
* m_nextSibling
;
152 template <typename Functor
> inline void ProfileNode::forEachNodePostorder(Functor
& functor
)
154 ProfileNode
* currentNode
= this;
155 // Go down to the first node of the traversal, and slowly walk back up.
156 for (ProfileNode
* nextNode
= currentNode
; nextNode
; nextNode
= nextNode
->firstChild())
157 currentNode
= nextNode
;
159 ProfileNode
* endNode
= this;
160 while (currentNode
&& currentNode
!= endNode
) {
161 functor(currentNode
);
162 currentNode
= currentNode
->traverseNextNodePostOrder();
168 struct CalculateProfileSubtreeDataFunctor
{
169 void operator()(ProfileNode
* node
)
171 double selfTime
= 0.0;
172 for (const ProfileNode::Call
& call
: node
->calls())
173 selfTime
+= call
.elapsedTime();
175 double totalTime
= selfTime
;
176 for (RefPtr
<ProfileNode
> child
: node
->children()) {
177 auto it
= m_data
.selfAndTotalTimes
.find(child
.get());
178 if (it
!= m_data
.selfAndTotalTimes
.end())
179 totalTime
+= it
->value
.second
;
183 m_data
.selfAndTotalTimes
.set(node
, std::make_pair(selfTime
, totalTime
));
186 ProfileNode::ProfileSubtreeData
returnValue() { return WTF::move(m_data
); }
188 ProfileNode::ProfileSubtreeData m_data
;
194 #endif // ProfileNode_h