]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
81345200 | 2 | * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. |
9dae56ea A |
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. | |
81345200 | 13 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
9dae56ea A |
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 | ||
93a37866 | 32 | #include "LegacyProfiler.h" |
ba379fdc | 33 | #include <wtf/DateMath.h> |
6fe7ccc8 | 34 | #include <wtf/DataLog.h> |
4e4e5a6f | 35 | #include <wtf/text/StringHash.h> |
9dae56ea | 36 | |
f9bf01c6 A |
37 | using namespace WTF; |
38 | ||
9dae56ea A |
39 | namespace JSC { |
40 | ||
14957cd0 A |
41 | ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode) |
42 | : m_callerCallFrame(callerCallFrame) | |
43 | , m_callIdentifier(callIdentifier) | |
9dae56ea A |
44 | , m_head(headNode) |
45 | , m_parent(parentNode) | |
81345200 A |
46 | , m_nextSibling(nullptr) |
47 | , m_totalTime(0) | |
48 | , m_selfTime(0) | |
9dae56ea A |
49 | { |
50 | startTimer(); | |
51 | } | |
52 | ||
14957cd0 A |
53 | ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy) |
54 | : m_callerCallFrame(callerCallFrame) | |
55 | , m_callIdentifier(nodeToCopy->callIdentifier()) | |
9dae56ea A |
56 | , m_head(headNode) |
57 | , m_parent(nodeToCopy->parent()) | |
58 | , m_nextSibling(0) | |
81345200 A |
59 | , m_totalTime(nodeToCopy->totalTime()) |
60 | , m_selfTime(nodeToCopy->selfTime()) | |
61 | , m_calls(nodeToCopy->calls()) | |
9dae56ea A |
62 | { |
63 | } | |
64 | ||
14957cd0 | 65 | ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier) |
9dae56ea A |
66 | { |
67 | for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) { | |
68 | if ((*currentChild)->callIdentifier() == callIdentifier) { | |
69 | (*currentChild)->startTimer(); | |
70 | return (*currentChild).get(); | |
71 | } | |
72 | } | |
73 | ||
14957cd0 | 74 | RefPtr<ProfileNode> newChild = ProfileNode::create(callerCallFrame, callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head. |
9dae56ea A |
75 | if (m_children.size()) |
76 | m_children.last()->setNextSibling(newChild.get()); | |
77 | m_children.append(newChild.release()); | |
78 | return m_children.last().get(); | |
79 | } | |
80 | ||
81 | ProfileNode* ProfileNode::didExecute() | |
82 | { | |
83 | endAndRecordCall(); | |
84 | return m_parent; | |
85 | } | |
86 | ||
87 | void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild) | |
88 | { | |
89 | RefPtr<ProfileNode> child = prpChild; | |
90 | child->setParent(this); | |
91 | if (m_children.size()) | |
92 | m_children.last()->setNextSibling(child.get()); | |
93 | m_children.append(child.release()); | |
94 | } | |
95 | ||
9dae56ea A |
96 | void ProfileNode::removeChild(ProfileNode* node) |
97 | { | |
98 | if (!node) | |
99 | return; | |
100 | ||
101 | for (size_t i = 0; i < m_children.size(); ++i) { | |
102 | if (*node == m_children[i].get()) { | |
103 | m_children.remove(i); | |
104 | break; | |
105 | } | |
106 | } | |
107 | ||
108 | resetChildrensSiblings(); | |
109 | } | |
110 | ||
111 | void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode) | |
112 | { | |
113 | RefPtr<ProfileNode> node = prpNode; | |
114 | ||
115 | for (unsigned i = 0; i < m_children.size(); ++i) | |
116 | node->addChild(m_children[i].release()); | |
117 | ||
118 | m_children.clear(); | |
119 | m_children.append(node.release()); | |
120 | } | |
121 | ||
122 | void ProfileNode::stopProfiling() | |
123 | { | |
81345200 | 124 | ASSERT(!m_calls.isEmpty()); |
9dae56ea | 125 | |
81345200 A |
126 | if (isnan(m_calls.last().totalTime())) |
127 | endAndRecordCall(); | |
9dae56ea A |
128 | |
129 | // Because we iterate in post order all of our children have been stopped before us. | |
130 | for (unsigned i = 0; i < m_children.size(); ++i) | |
81345200 | 131 | m_selfTime += m_children[i]->totalTime(); |
9dae56ea | 132 | |
81345200 A |
133 | ASSERT(m_selfTime <= m_totalTime); |
134 | m_selfTime = m_totalTime - m_selfTime; | |
9dae56ea A |
135 | } |
136 | ||
137 | ProfileNode* ProfileNode::traverseNextNodePostOrder() const | |
138 | { | |
139 | ProfileNode* next = m_nextSibling; | |
140 | if (!next) | |
141 | return m_parent; | |
142 | while (ProfileNode* firstChild = next->firstChild()) | |
143 | next = firstChild; | |
144 | return next; | |
145 | } | |
146 | ||
9dae56ea A |
147 | void ProfileNode::endAndRecordCall() |
148 | { | |
81345200 A |
149 | Call& last = lastCall(); |
150 | ASSERT(isnan(last.totalTime())); | |
151 | ||
152 | last.setTotalTime(currentTime() - last.startTime()); | |
9dae56ea | 153 | |
81345200 | 154 | m_totalTime += last.totalTime(); |
9dae56ea A |
155 | } |
156 | ||
157 | void ProfileNode::startTimer() | |
158 | { | |
81345200 | 159 | m_calls.append(Call(currentTime())); |
9dae56ea A |
160 | } |
161 | ||
162 | void ProfileNode::resetChildrensSiblings() | |
163 | { | |
164 | unsigned size = m_children.size(); | |
165 | for (unsigned i = 0; i < size; ++i) | |
166 | m_children[i]->setNextSibling(i + 1 == size ? 0 : m_children[i + 1].get()); | |
167 | } | |
168 | ||
169 | #ifndef NDEBUG | |
170 | void ProfileNode::debugPrintData(int indentLevel) const | |
171 | { | |
172 | // Print function names | |
173 | for (int i = 0; i < indentLevel; ++i) | |
93a37866 | 174 | dataLogF(" "); |
9dae56ea | 175 | |
81345200 A |
176 | dataLogF("Function Name %s %zu SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% Next Sibling %s\n", |
177 | functionName().utf8().data(), | |
178 | numberOfCalls(), m_selfTime, selfPercent(), m_totalTime, totalPercent(), | |
14957cd0 | 179 | m_nextSibling ? m_nextSibling->functionName().utf8().data() : ""); |
9dae56ea A |
180 | |
181 | ++indentLevel; | |
182 | ||
183 | // Print children's names and information | |
184 | for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) | |
185 | (*currentChild)->debugPrintData(indentLevel); | |
186 | } | |
187 | ||
188 | // print the profiled data in a format that matches the tool sample's output. | |
189 | double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const | |
190 | { | |
93a37866 | 191 | dataLogF(" "); |
9dae56ea A |
192 | |
193 | // Print function names | |
14957cd0 | 194 | const char* name = functionName().utf8().data(); |
81345200 | 195 | double sampleCount = m_totalTime * 1000; |
9dae56ea A |
196 | if (indentLevel) { |
197 | for (int i = 0; i < indentLevel; ++i) | |
93a37866 | 198 | dataLogF(" "); |
9dae56ea | 199 | |
14957cd0 | 200 | countedFunctions.add(functionName().impl()); |
9dae56ea | 201 | |
93a37866 | 202 | dataLogF("%.0f %s\n", sampleCount ? sampleCount : 1, name); |
9dae56ea | 203 | } else |
93a37866 | 204 | dataLogF("%s\n", name); |
9dae56ea A |
205 | |
206 | ++indentLevel; | |
207 | ||
208 | // Print children's names and information | |
209 | double sumOfChildrensCount = 0.0; | |
210 | for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) | |
211 | sumOfChildrensCount += (*currentChild)->debugPrintDataSampleStyle(indentLevel, countedFunctions); | |
212 | ||
213 | sumOfChildrensCount *= 1000; // | |
214 | // Print remainder of samples to match sample's output | |
215 | if (sumOfChildrensCount < sampleCount) { | |
93a37866 | 216 | dataLogF(" "); |
9dae56ea | 217 | while (indentLevel--) |
93a37866 | 218 | dataLogF(" "); |
9dae56ea | 219 | |
93a37866 | 220 | dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data()); |
9dae56ea A |
221 | } |
222 | ||
81345200 | 223 | return m_totalTime; |
9dae56ea A |
224 | } |
225 | #endif | |
226 | ||
227 | } // namespace JSC |