2  * Copyright (C) 2008 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 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. 
  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. 
  30 #include "ProfileNode.h" 
  34 #include <wtf/DateMath.h> 
  44 static double getCount() 
  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
; 
  54     return currentTimeMS(); 
  58 ProfileNode::ProfileNode(const CallIdentifier
& callIdentifier
, ProfileNode
* headNode
, ProfileNode
* parentNode
) 
  59     : m_callIdentifier(callIdentifier
) 
  61     , m_parent(parentNode
) 
  64     , m_actualTotalTime(0.0) 
  65     , m_visibleTotalTime(0.0) 
  66     , m_actualSelfTime(0.0) 
  67     , m_visibleSelfTime(0.0) 
  74 ProfileNode::ProfileNode(ProfileNode
* headNode
, ProfileNode
* nodeToCopy
) 
  75     : m_callIdentifier(nodeToCopy
->callIdentifier()) 
  77     , m_parent(nodeToCopy
->parent()) 
  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()) 
  89 ProfileNode
* ProfileNode::willExecute(const CallIdentifier
& callIdentifier
) 
  91     for (StackIterator currentChild 
= m_children
.begin(); currentChild 
!= m_children
.end(); ++currentChild
) { 
  92         if ((*currentChild
)->callIdentifier() == callIdentifier
) { 
  93             (*currentChild
)->startTimer(); 
  94             return (*currentChild
).get(); 
  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(); 
 105 ProfileNode
* ProfileNode::didExecute() 
 111 void ProfileNode::addChild(PassRefPtr
<ProfileNode
> prpChild
) 
 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()); 
 120 ProfileNode
* ProfileNode::findChild(ProfileNode
* node
) const 
 125     for (size_t i 
= 0; i 
< m_children
.size(); ++i
) { 
 126         if (*node 
== m_children
[i
].get()) 
 127             return m_children
[i
].get(); 
 133 void ProfileNode::removeChild(ProfileNode
* node
) 
 138     for (size_t i 
= 0; i 
< m_children
.size(); ++i
) { 
 139         if (*node 
== m_children
[i
].get()) { 
 140             m_children
.remove(i
); 
 145     resetChildrensSiblings(); 
 148 void ProfileNode::insertNode(PassRefPtr
<ProfileNode
> prpNode
) 
 150     RefPtr
<ProfileNode
> node 
= prpNode
; 
 152     for (unsigned i 
= 0; i 
< m_children
.size(); ++i
) 
 153         node
->addChild(m_children
[i
].release()); 
 156     m_children
.append(node
.release()); 
 159 void ProfileNode::stopProfiling() 
 164     m_visibleTotalTime 
= m_actualTotalTime
; 
 166     ASSERT(m_actualSelfTime 
== 0.0 && m_startTime 
== 0.0); 
 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(); 
 172     ASSERT(m_actualSelfTime 
<= m_actualTotalTime
); 
 173     m_actualSelfTime 
= m_actualTotalTime 
- m_actualSelfTime
; 
 174     m_visibleSelfTime 
= m_actualSelfTime
; 
 177 ProfileNode
* ProfileNode::traverseNextNodePostOrder() const 
 179     ProfileNode
* next 
= m_nextSibling
; 
 182     while (ProfileNode
* firstChild 
= next
->firstChild()) 
 187 ProfileNode
* ProfileNode::traverseNextNodePreOrder(bool processChildren
) const 
 189     if (processChildren 
&& m_children
.size()) 
 190         return m_children
[0].get(); 
 193         return m_nextSibling
; 
 195     ProfileNode
* nextParent 
= m_parent
; 
 200     for (next 
= m_parent
->nextSibling(); !next
; next 
= nextParent
->nextSibling()) { 
 201         nextParent 
= nextParent
->parent(); 
 209 void ProfileNode::setTreeVisible(ProfileNode
* node
, bool visible
) 
 211     ProfileNode
* nodeParent 
= node
->parent(); 
 212     ProfileNode
* nodeSibling 
= node
->nextSibling(); 
 214     node
->setNextSibling(0); 
 216     for (ProfileNode
* currentNode 
= node
; currentNode
; currentNode 
= currentNode
->traverseNextNodePreOrder()) 
 217         currentNode
->setVisible(visible
); 
 219     node
->setParent(nodeParent
); 
 220     node
->setNextSibling(nodeSibling
); 
 223 void ProfileNode::calculateVisibleTotalTime() 
 225     double sumOfVisibleChildrensTime 
= 0.0; 
 227     for (unsigned i 
= 0; i 
< m_children
.size(); ++i
) { 
 228         if (m_children
[i
]->visible()) 
 229             sumOfVisibleChildrensTime 
+= m_children
[i
]->totalTime(); 
 232     m_visibleTotalTime 
= m_visibleSelfTime 
+ sumOfVisibleChildrensTime
; 
 235 bool ProfileNode::focus(const CallIdentifier
& callIdentifier
) 
 240     if (m_callIdentifier 
!= callIdentifier
) { 
 245     for (ProfileNode
* currentParent 
= m_parent
; currentParent
; currentParent 
= currentParent
->parent()) 
 246         currentParent
->setVisible(true); 
 251 void ProfileNode::exclude(const CallIdentifier
& callIdentifier
) 
 253     if (m_visible 
&& m_callIdentifier 
== callIdentifier
) { 
 254         setTreeVisible(this, false); 
 256         m_parent
->setVisibleSelfTime(m_parent
->selfTime() + m_visibleTotalTime
); 
 260 void ProfileNode::restore() 
 262     m_visibleTotalTime 
= m_actualTotalTime
; 
 263     m_visibleSelfTime 
= m_actualSelfTime
; 
 267 void ProfileNode::endAndRecordCall() 
 269     m_actualTotalTime 
+= m_startTime 
? getCount() - m_startTime 
: 0.0; 
 275 void ProfileNode::startTimer() 
 278         m_startTime 
= getCount(); 
 281 void ProfileNode::resetChildrensSiblings() 
 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()); 
 289 void ProfileNode::debugPrintData(int indentLevel
) const 
 291     // Print function names 
 292     for (int i 
= 0; i 
< indentLevel
; ++i
) 
 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() : ""); 
 304     // Print children's names and information 
 305     for (StackIterator currentChild 
= m_children
.begin(); currentChild 
!= m_children
.end(); ++currentChild
) 
 306         (*currentChild
)->debugPrintData(indentLevel
); 
 309 // print the profiled data in a format that matches the tool sample's output. 
 310 double ProfileNode::debugPrintDataSampleStyle(int indentLevel
, FunctionCallHashCount
& countedFunctions
) const 
 314     // Print function names 
 315     const char* name 
= functionName().UTF8String().c_str(); 
 316     double sampleCount 
= m_actualTotalTime 
* 1000; 
 318         for (int i 
= 0; i 
< indentLevel
; ++i
) 
 321          countedFunctions
.add(functionName().rep()); 
 323         printf("%.0f %s\n", sampleCount 
? sampleCount 
: 1, name
); 
 325         printf("%s\n", name
); 
 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
); 
 334     sumOfChildrensCount 
*= 1000;    // 
 335     // Print remainder of samples to match sample's output 
 336     if (sumOfChildrensCount 
< sampleCount
) { 
 338         while (indentLevel
--) 
 341         printf("%.0f %s\n", sampleCount 
- sumOfChildrensCount
, functionName().UTF8String().c_str()); 
 344     return m_actualTotalTime
;