Home | History | Annotate | Download | only in profiler
      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