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  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "ProfileGenerator.h"
     28 
     29 #include "CallFrame.h"
     30 #include "CodeBlock.h"
     31 #include "JSGlobalObject.h"
     32 #include "JSStringRef.h"
     33 #include "JSFunction.h"
     34 #include "Interpreter.h"
     35 #include "Profile.h"
     36 #include "Profiler.h"
     37 #include "Tracing.h"
     38 
     39 namespace JSC {
     40 
     41 static const char* NonJSExecution = "(idle)";
     42 
     43 PassRefPtr<ProfileGenerator> ProfileGenerator::create(const UString& title, ExecState* originatingExec, unsigned uid)
     44 {
     45     return adoptRef(new ProfileGenerator(title, originatingExec, uid));
     46 }
     47 
     48 ProfileGenerator::ProfileGenerator(const UString& title, ExecState* originatingExec, unsigned uid)
     49     : m_originatingGlobalExec(originatingExec ? originatingExec->lexicalGlobalObject()->globalExec() : 0)
     50     , m_profileGroup(originatingExec ? originatingExec->lexicalGlobalObject()->profileGroup() : 0)
     51 {
     52     m_profile = Profile::create(title, uid);
     53     m_currentNode = m_head = m_profile->head();
     54     if (originatingExec)
     55         addParentForConsoleStart(originatingExec);
     56 }
     57 
     58 void ProfileGenerator::addParentForConsoleStart(ExecState* exec)
     59 {
     60     int lineNumber;
     61     intptr_t sourceID;
     62     UString sourceURL;
     63     JSValue function;
     64 
     65     exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function);
     66     m_currentNode = ProfileNode::create(Profiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
     67     m_head->insertNode(m_currentNode.get());
     68 }
     69 
     70 const UString& ProfileGenerator::title() const
     71 {
     72     return m_profile->title();
     73 }
     74 
     75 void ProfileGenerator::willExecute(const CallIdentifier& callIdentifier)
     76 {
     77     if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) {
     78         CString name = callIdentifier.m_name.UTF8String();
     79         CString url = callIdentifier.m_url.UTF8String();
     80         JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.c_str()), const_cast<char*>(url.c_str()), callIdentifier.m_lineNumber);
     81     }
     82 
     83     if (!m_originatingGlobalExec)
     84         return;
     85 
     86     ASSERT_ARG(m_currentNode, m_currentNode);
     87     m_currentNode = m_currentNode->willExecute(callIdentifier);
     88 }
     89 
     90 void ProfileGenerator::didExecute(const CallIdentifier& callIdentifier)
     91 {
     92     if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) {
     93         CString name = callIdentifier.m_name.UTF8String();
     94         CString url = callIdentifier.m_url.UTF8String();
     95         JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.c_str()), const_cast<char*>(url.c_str()), callIdentifier.m_lineNumber);
     96     }
     97 
     98     if (!m_originatingGlobalExec)
     99         return;
    100 
    101     ASSERT_ARG(m_currentNode, m_currentNode);
    102     if (m_currentNode->callIdentifier() != callIdentifier) {
    103         RefPtr<ProfileNode> returningNode = ProfileNode::create(callIdentifier, m_head.get(), m_currentNode.get());
    104         returningNode->setStartTime(m_currentNode->startTime());
    105         returningNode->didExecute();
    106         m_currentNode->insertNode(returningNode.release());
    107         return;
    108     }
    109 
    110     m_currentNode = m_currentNode->didExecute();
    111 }
    112 
    113 void ProfileGenerator::stopProfiling()
    114 {
    115     m_profile->forEach(&ProfileNode::stopProfiling);
    116 
    117     removeProfileStart();
    118     removeProfileEnd();
    119 
    120     ASSERT_ARG(m_currentNode, m_currentNode);
    121 
    122     // Set the current node to the parent, because we are in a call that
    123     // will not get didExecute call.
    124     m_currentNode = m_currentNode->parent();
    125 
    126    if (double headSelfTime = m_head->selfTime()) {
    127         RefPtr<ProfileNode> idleNode = ProfileNode::create(CallIdentifier(NonJSExecution, UString(), 0), m_head.get(), m_head.get());
    128 
    129         idleNode->setTotalTime(headSelfTime);
    130         idleNode->setSelfTime(headSelfTime);
    131         idleNode->setVisible(true);
    132 
    133         m_head->setSelfTime(0.0);
    134         m_head->addChild(idleNode.release());
    135     }
    136 }
    137 
    138 // The console.ProfileGenerator that started this ProfileGenerator will be the first child.
    139 void ProfileGenerator::removeProfileStart()
    140 {
    141     ProfileNode* currentNode = 0;
    142     for (ProfileNode* next = m_head.get(); next; next = next->firstChild())
    143         currentNode = next;
    144 
    145     if (currentNode->callIdentifier().m_name != "profile")
    146         return;
    147 
    148     // Attribute the time of the node aobut to be removed to the self time of its parent
    149     currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
    150     currentNode->parent()->removeChild(currentNode);
    151 }
    152 
    153 // The console.ProfileGeneratorEnd that stopped this ProfileGenerator will be the last child.
    154 void ProfileGenerator::removeProfileEnd()
    155 {
    156     ProfileNode* currentNode = 0;
    157     for (ProfileNode* next = m_head.get(); next; next = next->lastChild())
    158         currentNode = next;
    159 
    160     if (currentNode->callIdentifier().m_name != "profileEnd")
    161         return;
    162 
    163     // Attribute the time of the node aobut to be removed to the self time of its parent
    164     currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
    165 
    166     ASSERT(currentNode->callIdentifier() == (currentNode->parent()->children()[currentNode->parent()->children().size() - 1])->callIdentifier());
    167     currentNode->parent()->removeChild(currentNode);
    168 }
    169 
    170 } // namespace JSC
    171