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 40 using namespace WTF; 41 42 namespace JSC { 43 44 static 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 58 ProfileNode::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 74 ProfileNode::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 89 ProfileNode* 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, m_head ? m_head : this, 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(newChild.release()); 102 return m_children.last().get(); 103 } 104 105 ProfileNode* ProfileNode::didExecute() 106 { 107 endAndRecordCall(); 108 return m_parent; 109 } 110 111 void 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(child.release()); 118 } 119 120 ProfileNode* 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 133 void 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(i); 141 break; 142 } 143 } 144 145 resetChildrensSiblings(); 146 } 147 148 void 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(m_children[i].release()); 154 155 m_children.clear(); 156 m_children.append(node.release()); 157 } 158 159 void 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 177 ProfileNode* 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 187 ProfileNode* 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 209 void 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 223 void 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 235 bool 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 251 void ProfileNode::exclude(const CallIdentifier& callIdentifier) 252 { 253 if (m_visible && m_callIdentifier == callIdentifier) { 254 setTreeVisible(this, false); 255 256 m_parent->setVisibleSelfTime(m_parent->selfTime() + m_visibleTotalTime); 257 } 258 } 259 260 void ProfileNode::restore() 261 { 262 m_visibleTotalTime = m_actualTotalTime; 263 m_visibleSelfTime = m_actualSelfTime; 264 m_visible = true; 265 } 266 267 void ProfileNode::endAndRecordCall() 268 { 269 m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0; 270 m_startTime = 0.0; 271 272 ++m_numberOfCalls; 273 } 274 275 void ProfileNode::startTimer() 276 { 277 if (!m_startTime) 278 m_startTime = getCount(); 279 } 280 281 void 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 289 void ProfileNode::debugPrintData(int indentLevel) const 290 { 291 // Print function names 292 for (int i = 0; i < indentLevel; ++i) 293 printf(" "); 294 295 printf("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. 310 double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const 311 { 312 printf(" "); 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(" "); 320 321 countedFunctions.add(functionName().rep()); 322 323 printf("%.0f %s\n", sampleCount ? sampleCount : 1, name); 324 } else 325 printf("%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(" "); 338 while (indentLevel--) 339 printf(" "); 340 341 printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().UTF8String().c_str()); 342 } 343 344 return m_actualTotalTime; 345 } 346 #endif 347 348 } // namespace JSC 349