Commit c74bed15 authored by kmccullough@apple.com's avatar kmccullough@apple.com

2008-05-20 Kevin McCullough <kmccullough@apple.com>

        Reviewed by Tim.

        <rdar://problem/5770054> JavaScript profiler (10928)
        Split function name into 3 parts so that the Web Inspector can link it to
        the resource location from whence it came.

        * kjs/ustring.cpp: Implemented operator> for UStrings
        (KJS::operator>):
        * kjs/ustring.h:
        * profiler/Profile.cpp:
        (KJS::Profile::Profile): Initialize all 3 values.
        (KJS::Profile::willExecute): Use CallIdentifier struct.
        (KJS::Profile::didExecute): Ditto.
        * profiler/Profile.h: Ditto and remove unused function.
        * profiler/ProfileNode.cpp:
        (KJS::ProfileNode::ProfileNode): Use CallIdentifier struct.
        (KJS::ProfileNode::willExecute): Ditto and fix an issue where we
        restarted the m_startTime even though it was already started.
        (KJS::ProfileNode::didExecute): Ditto.
        (KJS::ProfileNode::findChild): Ditto.
        (KJS::functionNameDescendingComparator): Ditto and use new comparator.
        (KJS::functionNameAscendingComparator): Ditto.
        (KJS::ProfileNode::printDataInspectorStyle): Use CallIdentifier struct.
        (KJS::ProfileNode::printDataSampleStyle): Ditto.
        * profiler/ProfileNode.h:
        (KJS::CallIdentifier::CallIdentifier): Describe the CallIdentifier struct
        (KJS::CallIdentifier::operator== ):
        (KJS::ProfileNode::create): Use the CallIdentifier struct.
        (KJS::ProfileNode::callIdentifier):
        (KJS::ProfileNode::functionName): Now only return the function name, not
        the url and line number too.
        (KJS::ProfileNode::url):
        (KJS::ProfileNode::lineNumber):
        * profiler/Profiler.cpp: Use the CallIdentifier struct. 
        (KJS::Profiler::startProfiling):
        (KJS::Profiler::willExecute):
        (KJS::Profiler::didExecute):
        (KJS::getCallIdentifiers):
        (KJS::getCallIdentifierFromFunctionImp):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@33941 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent d8560b94
2008-05-20 Kevin McCullough <kmccullough@apple.com>
Reviewed by Tim.
<rdar://problem/5770054> JavaScript profiler (10928)
Split function name into 3 parts so that the Web Inspector can link it to
the resource location from whence it came.
* kjs/ustring.cpp: Implemented operator> for UStrings
(KJS::operator>):
* kjs/ustring.h:
* profiler/Profile.cpp:
(KJS::Profile::Profile): Initialize all 3 values.
(KJS::Profile::willExecute): Use CallIdentifier struct.
(KJS::Profile::didExecute): Ditto.
* profiler/Profile.h: Ditto and remove unused function.
* profiler/ProfileNode.cpp:
(KJS::ProfileNode::ProfileNode): Use CallIdentifier struct.
(KJS::ProfileNode::willExecute): Ditto and fix an issue where we
restarted the m_startTime even though it was already started.
(KJS::ProfileNode::didExecute): Ditto.
(KJS::ProfileNode::findChild): Ditto.
(KJS::functionNameDescendingComparator): Ditto and use new comparator.
(KJS::functionNameAscendingComparator): Ditto.
(KJS::ProfileNode::printDataInspectorStyle): Use CallIdentifier struct.
(KJS::ProfileNode::printDataSampleStyle): Ditto.
* profiler/ProfileNode.h:
(KJS::CallIdentifier::CallIdentifier): Describe the CallIdentifier struct
(KJS::CallIdentifier::operator== ):
(KJS::ProfileNode::create): Use the CallIdentifier struct.
(KJS::ProfileNode::callIdentifier):
(KJS::ProfileNode::functionName): Now only return the function name, not
the url and line number too.
(KJS::ProfileNode::url):
(KJS::ProfileNode::lineNumber):
* profiler/Profiler.cpp: Use the CallIdentifier struct.
(KJS::Profiler::startProfiling):
(KJS::Profiler::willExecute):
(KJS::Profiler::didExecute):
(KJS::getCallIdentifiers):
(KJS::getCallIdentifierFromFunctionImp):
2008-05-20 Timothy Hatcher <timothy@apple.com>
Rename sortFileName{Ascending,Descending} to
......
......@@ -86,4 +86,4 @@
#include <wtf/DisallowCType.h>
#endif
#define JAVASCRIPT_PROFILING 0
#define JAVASCRIPT_PROFILING 1
......@@ -1273,6 +1273,25 @@ bool operator<(const UString& s1, const UString& s2)
return (l1 < l2);
}
bool operator>(const UString& s1, const UString& s2)
{
const int l1 = s1.size();
const int l2 = s2.size();
const int lmin = l1 < l2 ? l1 : l2;
const UChar *c1 = s1.data();
const UChar *c2 = s2.data();
int l = 0;
while (l < lmin && *c1 == *c2) {
c1++;
c2++;
l++;
}
if (l < lmin)
return (c1[0] > c2[0]);
return (l1 > l2);
}
int compare(const UString& s1, const UString& s2)
{
const int l1 = s1.size();
......
......@@ -363,6 +363,7 @@ namespace KJS {
return !KJS::operator==(s1, s2);
}
bool operator<(const UString& s1, const UString& s2);
bool operator>(const UString& s1, const UString& s2);
bool operator==(const UString& s1, const char *s2);
inline bool operator!=(const UString& s1, const char *s2) {
return !KJS::operator==(s1, s2);
......
......@@ -40,37 +40,36 @@ Profile::Profile(const UString& title)
{
// FIXME: When multi-threading is supported this will be a vector and calls
// into the profiler will need to know which thread it is executing on.
m_callTree = ProfileNode::create("Thread_1");
m_callTree = ProfileNode::create(CallIdentifier("Thread_1", 0, 0));
}
// The callStackNames are in order of bottom of the stack to top of the stack so we iterate it backwards.
void Profile::willExecute(const Vector<UString>& callStackNames)
// The callIdentifiers are in order of bottom of the stack to top of the stack so we iterate it backwards.
void Profile::willExecute(const Vector<CallIdentifier>& callIdentifiers)
{
RefPtr<ProfileNode> callTreeInsertionPoint;
RefPtr<ProfileNode> foundNameInTree = m_callTree;
int i = callStackNames.size();
int i = callIdentifiers.size();
while (foundNameInTree && i) {
callTreeInsertionPoint = foundNameInTree;
foundNameInTree = callTreeInsertionPoint->findChild(callStackNames[--i]);
foundNameInTree = callTreeInsertionPoint->findChild(callIdentifiers[--i]);
}
if (!foundNameInTree) { // Insert remains of the stack into the call tree.
for (RefPtr<ProfileNode> next; i >= 0; callTreeInsertionPoint = next) {
next = ProfileNode::create(callStackNames[i--]);
next = ProfileNode::create(callIdentifiers[i--]);
callTreeInsertionPoint->addChild(next);
}
} else // We are calling a function that is already in the call tree.
foundNameInTree->willExecute();
}
void Profile::didExecute(const Vector<UString>& stackNames)
void Profile::didExecute(const Vector<CallIdentifier>& callIdentifiers)
{
ASSERT(stackNames.size());
if (!stackNames.size())
if (!callIdentifiers.size())
return;
m_callTree->didExecute(stackNames, stackNames.size() - 1);
m_callTree->didExecute(callIdentifiers, callIdentifiers.size() - 1);
}
void Profile::printDataInspectorStyle() const
......
......@@ -40,8 +40,8 @@ namespace KJS {
public:
static PassRefPtr<Profile> create(const UString& title) { return adoptRef(new Profile(title)); }
void willExecute(const Vector<UString>& callStackNames);
void didExecute(const Vector<UString>& stackNames);
void willExecute(const Vector<CallIdentifier>& CallIdentifier);
void didExecute(const Vector<CallIdentifier>& CallIdentifier);
void stopProfiling() { m_callTree->stopProfiling(); };
const UString& title() const { return m_title; };
......@@ -66,8 +66,6 @@ namespace KJS {
UString m_title;
void insertStackNamesInTree(const Vector<UString>& callStackNames);
RefPtr<ProfileNode> m_callTree;
};
......
......@@ -36,8 +36,8 @@
namespace KJS {
ProfileNode::ProfileNode(const UString& name)
: m_functionName(name)
ProfileNode::ProfileNode(const CallIdentifier& callIdentifier)
: m_callIdentifier(callIdentifier)
, m_totalTime (0.0)
, m_selfTime (0.0)
, m_totalPercent (0.0)
......@@ -49,16 +49,17 @@ ProfileNode::ProfileNode(const UString& name)
void ProfileNode::willExecute()
{
m_startTime = getCurrentUTCTimeWithMicroseconds();
if (!m_startTime)
m_startTime = getCurrentUTCTimeWithMicroseconds();
}
// We start at the end of stackNames and work our way forwards since the names are in
// the reverse order of how the ProfileNode tree is created (e.g. the leaf node is at
// index 0 and the top of the stack is at index stackNames.size() - 1)
void ProfileNode::didExecute(const Vector<UString>& stackNames, unsigned int stackIndex)
void ProfileNode::didExecute(const Vector<CallIdentifier>& stackNames, unsigned int stackIndex)
{
for (size_t i = 0; i < m_children.size(); ++i) {
if (m_children[i]->functionName() == stackNames[stackIndex]) {
if (m_children[i]->callIdentifier() == stackNames[stackIndex]) {
if (stackIndex) // We are not at the bottom of the stack yet
m_children[i]->didExecute(stackNames, stackIndex - 1);
else // This is the child we were looking for
......@@ -81,10 +82,10 @@ void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
m_children.append(child.release());
}
ProfileNode* ProfileNode::findChild(const UString& name)
ProfileNode* ProfileNode::findChild(const CallIdentifier& functionName)
{
for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
if ((*currentChild)->functionName() == name)
if ((*currentChild)->callIdentifier() == functionName)
return (*currentChild).get();
}
......@@ -194,7 +195,7 @@ void ProfileNode::sortCallsAscending()
static inline bool functionNameDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b)
{
return compare(a->functionName(), b->functionName()) == 1 ? true : false ;
return a->functionName() > b->functionName();
}
void ProfileNode::sortFunctionNameDescending()
......@@ -207,7 +208,7 @@ void ProfileNode::sortFunctionNameDescending()
static inline bool functionNameAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b)
{
return compare(a->functionName(), b->functionName()) == -1 ? true : false ;
return a->functionName() < b->functionName();
}
void ProfileNode::sortFunctionNameAscending()
......@@ -232,7 +233,7 @@ void ProfileNode::printDataInspectorStyle(int indentLevel) const
for (int i = 0; i < indentLevel; ++i)
printf(" ");
printf("%d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% FunctionName %s\n", m_numberOfCalls, m_selfTime, selfPercent(), m_totalTime, totalPercent(), m_functionName.UTF8String().c_str());
printf("%d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% Full Name %s\n", m_numberOfCalls, m_selfTime, selfPercent(), m_totalTime, totalPercent(), functionName().UTF8String().c_str());
++indentLevel;
......@@ -247,13 +248,13 @@ double ProfileNode::printDataSampleStyle(int indentLevel, FunctionCallHashCount&
printf(" ");
// Print function names
const char* name = m_functionName.UTF8String().c_str();
const char* name = functionName().UTF8String().c_str();
double sampleCount = m_totalTime * 1000;
if (indentLevel) {
for (int i = 0; i < indentLevel; ++i)
printf(" ");
countedFunctions.add(m_functionName.rep());
countedFunctions.add(functionName().rep());
printf("%.0f %s\n", sampleCount ? sampleCount : 1, name);
} else
......@@ -273,7 +274,7 @@ double ProfileNode::printDataSampleStyle(int indentLevel, FunctionCallHashCount&
while (indentLevel--)
printf(" ");
printf("%.0f %s\n", sampleCount - sumOfChildrensCount, m_functionName.UTF8String().c_str());
printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().UTF8String().c_str());
}
return m_totalTime;
......
......@@ -42,19 +42,34 @@ namespace KJS {
typedef Vector<RefPtr<ProfileNode> >::const_iterator StackIterator;
typedef HashCountedSet<UString::Rep*> FunctionCallHashCount;
struct CallIdentifier {
UString name;
UString url;
unsigned lineNumber;
CallIdentifier(UString name, UString url, int lineNumber) : name(name), url(url), lineNumber(lineNumber) {}
CallIdentifier(const CallIdentifier& ci) : name(ci.name), url(ci.url), lineNumber(ci.lineNumber) {}
inline bool operator== (const CallIdentifier& ci) const { return ci.name == name && ci.lineNumber == lineNumber && ci.url == url; }
};
class ProfileNode : public RefCounted<ProfileNode> {
public:
static PassRefPtr<ProfileNode> create(const UString& name) { return adoptRef(new ProfileNode(name)); }
static PassRefPtr<ProfileNode> create(const CallIdentifier& callIdentifier) { return adoptRef(new ProfileNode(callIdentifier)); }
void willExecute();
void didExecute(const Vector<UString>& stackNames, unsigned int stackIndex);
void didExecute(const Vector<CallIdentifier>& callIdentifiers, unsigned int stackIndex);
void addChild(PassRefPtr<ProfileNode> prpChild);
ProfileNode* findChild(const UString& name);
ProfileNode* findChild(const CallIdentifier& functionName);
void stopProfiling();
UString functionName() const { return m_functionName; }
CallIdentifier callIdentifier() const { return m_callIdentifier; }
UString functionName() const { return m_callIdentifier.name; }
UString url() const { return m_callIdentifier.url; }
unsigned lineNumber() const { return m_callIdentifier.lineNumber; }
double totalTime() const { return m_totalTime; }
double selfTime() const { return m_selfTime; }
double totalPercent() const { return m_totalPercent; }
......@@ -78,9 +93,10 @@ namespace KJS {
double printDataSampleStyle(int indentLevel, FunctionCallHashCount&) const;
private:
ProfileNode(const UString& name);
UString m_functionName;
ProfileNode(const CallIdentifier& callIdentifier);
CallIdentifier m_callIdentifier;
double m_startTime;
double m_totalTime;
double m_selfTime;
......
......@@ -42,10 +42,10 @@ namespace KJS {
static Profiler* sharedProfiler = 0;
static const char* Script = "[SCRIPT] ";
static void getStackNames(Vector<UString>&, ExecState*);
static void getStackNames(Vector<UString>&, ExecState*, JSObject*);
static void getStackNames(Vector<UString>&, ExecState*, const UString& sourceURL, int startingLineNumber);
static UString getFunctionName(FunctionImp*);
static void getCallIdentifiers(ExecState*, Vector<CallIdentifier>& callIdentifiers);
static void getCallIdentifiers(ExecState*, JSObject*, Vector<CallIdentifier>& callIdentifiers);
static void getCallIdentifiers(ExecState*, const UString& sourceURL, int startingLineNumber, Vector<CallIdentifier>& callIdentifiers);
static void getCallIdentifierFromFunctionImp(FunctionImp*, Vector<CallIdentifier>& callIdentifiers);
Profiler* Profiler::profiler()
{
......@@ -64,9 +64,9 @@ void Profiler::startProfiling(ExecState* exec, unsigned pageGroupIdentifier, con
m_currentProfile = Profile::create(title);
m_profiling = true;
Vector<UString> callStackNames;
getStackNames(callStackNames, exec);
m_currentProfile->willExecute(callStackNames);
Vector<CallIdentifier> callIdentifiers;
getCallIdentifiers(exec, callIdentifiers);
m_currentProfile->willExecute(callIdentifiers);
}
void Profiler::stopProfiling()
......@@ -101,9 +101,9 @@ void Profiler::willExecute(ExecState* exec, JSObject* calledFunction)
if (shouldExcludeFunction(exec, calledFunction))
return;
Vector<UString> callStackNames;
getStackNames(callStackNames, exec, calledFunction);
m_currentProfile->willExecute(callStackNames);
Vector<CallIdentifier> callIdentifiers;
getCallIdentifiers(exec, calledFunction, callIdentifiers);
m_currentProfile->willExecute(callIdentifiers);
}
void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
......@@ -111,9 +111,9 @@ void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int starti
if (!m_profiling || exec->lexicalGlobalObject()->pageGroupIdentifier() != m_pageGroupIdentifier)
return;
Vector<UString> callStackNames;
getStackNames(callStackNames, exec, sourceURL, startingLineNumber);
m_currentProfile->willExecute(callStackNames);
Vector<CallIdentifier> callIdentifiers;
getCallIdentifiers(exec, sourceURL, startingLineNumber, callIdentifiers);
m_currentProfile->willExecute(callIdentifiers);
}
void Profiler::didExecute(ExecState* exec, JSObject* calledFunction)
......@@ -124,9 +124,9 @@ void Profiler::didExecute(ExecState* exec, JSObject* calledFunction)
if (shouldExcludeFunction(exec, calledFunction))
return;
Vector<UString> callStackNames;
getStackNames(callStackNames, exec, calledFunction);
m_currentProfile->didExecute(callStackNames);
Vector<CallIdentifier> callIdentifiers;
getCallIdentifiers(exec, calledFunction, callIdentifiers);
m_currentProfile->didExecute(callIdentifiers);
}
void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
......@@ -134,44 +134,43 @@ void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startin
if (!m_profiling || exec->lexicalGlobalObject()->pageGroupIdentifier() != m_pageGroupIdentifier)
return;
Vector<UString> callStackNames;
getStackNames(callStackNames, exec, sourceURL, startingLineNumber);
m_currentProfile->didExecute(callStackNames);
Vector<CallIdentifier> callIdentifiers;
getCallIdentifiers(exec, sourceURL, startingLineNumber, callIdentifiers);
m_currentProfile->didExecute(callIdentifiers);
}
void getStackNames(Vector<UString>& names, ExecState* exec)
void getCallIdentifiers(ExecState* exec, Vector<CallIdentifier>& callIdentifiers)
{
for (ExecState* currentState = exec; currentState; currentState = currentState->callingExecState()) {
if (FunctionImp* functionImp = currentState->function())
names.append(getFunctionName(functionImp));
getCallIdentifierFromFunctionImp(functionImp, callIdentifiers);
else if (ScopeNode* scopeNode = currentState->scopeNode())
names.append(Script + scopeNode->sourceURL() + ": " + UString::from(scopeNode->lineNo() + 1)); // FIXME: Why is the line number always off by one?
callIdentifiers.append(CallIdentifier(Script, scopeNode->sourceURL(), (scopeNode->lineNo() + 1)) ); // FIXME: Why is the line number always off by one?
}
}
void getStackNames(Vector<UString>& names, ExecState* exec, JSObject* calledFunction)
void getCallIdentifiers(ExecState* exec, JSObject* calledFunction, Vector<CallIdentifier>& callIdentifiers)
{
if (calledFunction->inherits(&FunctionImp::info))
names.append(getFunctionName(static_cast<FunctionImp*>(calledFunction)));
getCallIdentifierFromFunctionImp(static_cast<FunctionImp*>(calledFunction), callIdentifiers);
else if (calledFunction->inherits(&InternalFunctionImp::info))
names.append(static_cast<InternalFunctionImp*>(calledFunction)->functionName().ustring());
getStackNames(names, exec);
callIdentifiers.append(CallIdentifier(static_cast<InternalFunctionImp*>(calledFunction)->functionName().ustring(), "", 0) );
getCallIdentifiers(exec, callIdentifiers);
}
void getStackNames(Vector<UString>& names, ExecState* exec, const UString& sourceURL, int startingLineNumber)
void getCallIdentifiers(ExecState* exec, const UString& sourceURL, int startingLineNumber, Vector<CallIdentifier>& callIdentifiers)
{
names.append(Script + sourceURL + ": " + UString::from(startingLineNumber + 1));
getStackNames(names, exec);
callIdentifiers.append(CallIdentifier(Script, sourceURL, (startingLineNumber + 1)) );
getCallIdentifiers(exec, callIdentifiers);
}
UString getFunctionName(FunctionImp* functionImp)
void getCallIdentifierFromFunctionImp(FunctionImp* functionImp, Vector<CallIdentifier>& callIdentifiers)
{
UString name = functionImp->functionName().ustring();
int lineNumber = functionImp->body->lineNo();
UString URL = functionImp->body->sourceURL();
if (name.isEmpty())
name = "[anonymous function]";
return (name.isEmpty() ? "[anonymous function]" : name) + " " + URL + ": " + UString::from(lineNumber);
callIdentifiers.append(CallIdentifier(name, functionImp->body->sourceURL(), functionImp->body->lineNo()) );
}
void Profiler::debugLog(UString message)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment