Commit 21b94191 authored by kmccullough@apple.com's avatar kmccullough@apple.com

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

        Reviewed by Darin.

        <rdar://problem/5770054> JavaScript profiler (10928)
        - Fix "sample" output so that it can be imported into Instruments
        - Also keep track of number of times a function is profiled.

        * JavaScriptCore.xcodeproj/project.pbxproj: Add StrHash.h which needed
        to be pulled out of identifier.cpp so that it could be used by the
        profiler and identifiers.
        * kjs/identifier.cpp: Ditto.
        * profiler/FunctionCallProfile.cpp:
        (KJS::FunctionCallProfile::printDataInspectorStyle): Inspector style
        printing should show microseconds.
        (KJS::FunctionCallProfile::printDataSampleStyle): Sample style printing
        now counts the number of times a function is in the stack tree and does
        not print microseconds since that does not make sense for a sampler.
        * profiler/FunctionCallProfile.h: Keep track of number of times a
        function is profiled.
        (KJS::FunctionCallProfile::numberOfCalls):
        * profiler/Profiler.cpp:
        (KJS::functionNameCountPairComparator): Comparator for sort function in
        printDataSampleStyle.
        (KJS::Profiler::printDataSampleStyle): Print the number of times that a
        function is listed in the stack tree in order of most times listed.
        * wtf/HashCountedSet.h: Added copyToVector since it didn't exist and is
        a more standard way to copy a HashSet to a Vector. I added on variant
        that takes a pair as the Vector's type and so the HashCountedSet simply
        fills in that pair with its internal pair, and another variant that
        takes a Vector of the type of the HashCountedSet and only fills in the
        Vector with the first element of the pair.
        (WTF::copyToVector):
        * wtf/StrHash.h: Added.
        (WTF::):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@32760 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 55996084
2008-05-01 Kevin McCullough <kmccullough@apple.com>
Reviewed by Darin.
<rdar://problem/5770054> JavaScript profiler (10928)
- Fix "sample" output so that it can be imported into Instruments
- Also keep track of number of times a function is profiled.
* JavaScriptCore.xcodeproj/project.pbxproj: Add StrHash.h which needed
to be pulled out of identifier.cpp so that it could be used by the
profiler and identifiers.
* kjs/identifier.cpp: Ditto.
* profiler/FunctionCallProfile.cpp:
(KJS::FunctionCallProfile::printDataInspectorStyle): Inspector style
printing should show microseconds.
(KJS::FunctionCallProfile::printDataSampleStyle): Sample style printing
now counts the number of times a function is in the stack tree and does
not print microseconds since that does not make sense for a sampler.
* profiler/FunctionCallProfile.h: Keep track of number of times a
function is profiled.
(KJS::FunctionCallProfile::numberOfCalls):
* profiler/Profiler.cpp:
(KJS::functionNameCountPairComparator): Comparator for sort function in
printDataSampleStyle.
(KJS::Profiler::printDataSampleStyle): Print the number of times that a
function is listed in the stack tree in order of most times listed.
* wtf/HashCountedSet.h: Added copyToVector since it didn't exist and is
a more standard way to copy a HashSet to a Vector. I added on variant
that takes a pair as the Vector's type and so the HashCountedSet simply
fills in that pair with its internal pair, and another variant that
takes a Vector of the type of the HashCountedSet and only fills in the
Vector with the first element of the pair.
(WTF::copyToVector):
* wtf/StrHash.h: Added.
(WTF::):
2008-04-29 David Kilzer <ddkilzer@apple.com>
BUILD FIX for ENABLE(DASHBOARD_SUPPORT)
......
......@@ -185,6 +185,7 @@
93E26BE608B1517100F85226 /* pcre_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E26BE508B1517100F85226 /* pcre_internal.h */; };
93E26BFE08B151D400F85226 /* ucpinternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E26BFC08B151D400F85226 /* ucpinternal.h */; };
93F0B3AC09BB4DC00068FCE3 /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F0B3AA09BB4DC00068FCE3 /* Parser.h */; settings = {ATTRIBUTES = (Private, ); }; };
958D85830DC93230008ABF27 /* StrHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 958D85820DC93230008ABF27 /* StrHash.h */; };
95AB83420DA4322500BC83F3 /* Profiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95AB832E0DA42CAD00BC83F3 /* Profiler.cpp */; };
95AB83480DA432EB00BC83F3 /* Profiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 95AB832F0DA42CAD00BC83F3 /* Profiler.h */; settings = {ATTRIBUTES = (Private, ); }; };
95AB83560DA43C3000BC83F3 /* FunctionCallProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95AB83540DA43B4400BC83F3 /* FunctionCallProfile.cpp */; };
......@@ -492,6 +493,7 @@
93F0B3A909BB4DC00068FCE3 /* Parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Parser.cpp; sourceTree = "<group>"; };
93F0B3AA09BB4DC00068FCE3 /* Parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Parser.h; sourceTree = "<group>"; };
93F1981A08245AAE001E9ABC /* keywords.table */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text; path = keywords.table; sourceTree = "<group>"; tabWidth = 8; };
958D85820DC93230008ABF27 /* StrHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StrHash.h; sourceTree = "<group>"; };
95AB832E0DA42CAD00BC83F3 /* Profiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Profiler.cpp; path = profiler/Profiler.cpp; sourceTree = "<group>"; };
95AB832F0DA42CAD00BC83F3 /* Profiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Profiler.h; path = profiler/Profiler.h; sourceTree = "<group>"; };
95AB83540DA43B4400BC83F3 /* FunctionCallProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FunctionCallProfile.cpp; path = profiler/FunctionCallProfile.cpp; sourceTree = "<group>"; };
......@@ -820,6 +822,7 @@
935AF46B09E9D9DB00ACD1D8 /* UnusedParam.h */,
6592C316098B7DE10003D4F6 /* Vector.h */,
6592C317098B7DE10003D4F6 /* VectorTraits.h */,
958D85820DC93230008ABF27 /* StrHash.h */,
);
path = wtf;
sourceTree = "<group>";
......@@ -1140,6 +1143,7 @@
95AB83570DA43C3000BC83F3 /* FunctionCallProfile.h in Headers */,
E1B7C8BE0DA3A3360074B0DC /* ThreadSpecific.h in Headers */,
06D358B20DAADA93003B174E /* MainThread.h in Headers */,
958D85830DC93230008ABF27 /* StrHash.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -28,28 +28,12 @@
#include <wtf/Assertions.h>
#include <wtf/FastMalloc.h>
#include <wtf/HashSet.h>
//#include <wtf/StrHash.h>
#if USE(MULTIPLE_THREADS)
#include <wtf/ThreadSpecific.h>
using namespace WTF;
#endif
namespace WTF {
template<typename T> struct DefaultHash;
template<typename T> struct StrHash;
template<> struct StrHash<KJS::UString::Rep *> {
static unsigned hash(const KJS::UString::Rep *key) { return key->hash(); }
static bool equal(const KJS::UString::Rep *a, const KJS::UString::Rep *b) { return KJS::Identifier::equal(a, b); }
static const bool safeToCompareToEmptyOrDeleted = false;
};
template<> struct DefaultHash<KJS::UString::Rep *> {
typedef StrHash<KJS::UString::Rep *> Hash;
};
}
namespace KJS {
class IdentifierTable {
......
......@@ -111,7 +111,7 @@ void FunctionCallProfile::printDataInspectorStyle(int indentLevel) const
for (int i = 0; i < indentLevel; ++i)
printf(" ");
printf("%.0fms %s\n", m_timeSum, m_functionName.UTF8String().c_str());
printf("%.3fms %s\n", m_timeSum, m_functionName.UTF8String().c_str());
} else
printf("%s\n", m_functionName.UTF8String().c_str());
......@@ -123,34 +123,38 @@ void FunctionCallProfile::printDataInspectorStyle(int indentLevel) const
}
// print the profiled data in a format that matches the tool sample's output.
double FunctionCallProfile::printDataSampleStyle(int indentLevel) const
double FunctionCallProfile::printDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
{
printf(" ");
// Print function names
const char* name = m_functionName.UTF8String().c_str();
double sampleCount = m_timeSum * 1000;
if (indentLevel) {
for (int i = 0; i < indentLevel; ++i)
printf(" ");
// We've previously asserted that m_timeSum will always be >= 1
printf("%.0f %s\n", m_timeSum ? m_timeSum : 1, m_functionName.UTF8String().c_str());
countedFunctions.add(m_functionName.rep());
printf("%.0f %s\n", sampleCount ? sampleCount : 1, name);
} else
printf("%s\n", m_functionName.UTF8String().c_str());
printf("%s\n", name);
++indentLevel;
// Print children's names and information
double sumOfChildrensTimes = 0.0;
double sumOfChildrensCount = 0.0;
for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
sumOfChildrensTimes += (*currentChild)->printDataSampleStyle(indentLevel);
sumOfChildrensCount += (*currentChild)->printDataSampleStyle(indentLevel, countedFunctions);
// Print remainder of time to match sample's output
if (sumOfChildrensTimes < m_timeSum) {
sumOfChildrensCount *= 1000; //
// Print remainder of samples to match sample's output
if (sumOfChildrensCount < sampleCount) {
printf(" ");
while (indentLevel--)
printf(" ");
printf("%f %s\n", m_timeSum - sumOfChildrensTimes, m_functionName.UTF8String().c_str());
printf("%.0f %s\n", sampleCount - sumOfChildrensCount, m_functionName.UTF8String().c_str());
}
return m_timeSum;
......
......@@ -31,12 +31,14 @@
#include <kjs/ustring.h>
#include <wtf/Deque.h>
#include <wtf/StrHash.h>
namespace KJS {
class FunctionCallProfile;
typedef Deque<FunctionCallProfile*>::const_iterator StackIterator;
typedef HashCountedSet<UString::Rep*> FunctionCallHashCount;
class FunctionCallProfile {
public:
......@@ -53,9 +55,10 @@ namespace KJS {
UString functionName() const { return m_functionName; }
double milliSecs() const { return m_timeSum; }
unsigned numberOfCalls() const { return m_numberOfCalls; }
void printDataInspectorStyle(int indentLevel) const;
double printDataSampleStyle(int indentLevel) const;
double printDataSampleStyle(int indentLevel, FunctionCallHashCount&) const;
private:
void endAndRecordCall();
......
......@@ -177,13 +177,29 @@ void Profiler::printDataInspectorStyle() const
m_callTree->printDataInspectorStyle(0);
}
typedef pair<UString::Rep*, unsigned> NameCountPair;
static inline bool functionNameCountPairComparator(const NameCountPair a, const NameCountPair b)
{
return a.second > b.second;
}
void Profiler::printDataSampleStyle() const
{
typedef Vector<NameCountPair> NameCountPairVector;
FunctionCallHashCount countedFunctions;
printf("Call graph:\n");
m_callTree->printDataSampleStyle(0);
m_callTree->printDataSampleStyle(0, countedFunctions);
printf("\nTotal number in stack:\n");
NameCountPairVector sortedFunctions(countedFunctions.size());
copyToVector(countedFunctions, sortedFunctions);
std::sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator);
for (NameCountPairVector::iterator it = sortedFunctions.begin(); it != sortedFunctions.end(); ++it)
printf(" %-12d%s\n", (*it).second, UString((*it).first).UTF8String().c_str());
// FIXME: Since no one seems to understand this part of sample's output I will implement it when I have a better idea of what it's meant to be doing.
printf("\nTotal number in stack (recursive counted multiple, when >=5):\n");
printf("\nSort by top of stack, same collapsed (when >= 5):\n");
}
......
......@@ -25,6 +25,7 @@
#include "Assertions.h"
#include "HashMap.h"
#include "Vector.h"
namespace WTF {
......@@ -170,6 +171,33 @@ namespace WTF {
{
m_impl.clear();
}
template<typename Value, typename HashFunctions, typename Traits, typename VectorType>
inline void copyToVector(const HashCountedSet<Value, HashFunctions, Traits>& collection, VectorType& vector)
{
typedef typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator iterator;
vector.resize(collection.size());
iterator it = collection.begin();
iterator end = collection.end();
for (unsigned i = 0; it != end; ++it, ++i)
vector[i] = *it;
}
template<typename Value, typename HashFunctions, typename Traits>
inline void copyToVector(const HashCountedSet<Value, HashFunctions, Traits>& collection, Vector<Value>& vector)
{
typedef typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator iterator;
vector.resize(collection.size());
iterator it = collection.begin();
iterator end = collection.end();
for (unsigned i = 0; it != end; ++it, ++i)
vector[i] = (*it).first;
}
} // namespace khtml
......
/*
* Copyright (C) 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "identifier.h"
namespace WTF {
template<typename T> struct DefaultHash;
template<typename T> struct StrHash;
template<> struct StrHash<KJS::UString::Rep*> {
static unsigned hash(const KJS::UString::Rep* key) { return key->hash(); }
static bool equal(const KJS::UString::Rep* a, const KJS::UString::Rep* b) { return KJS::Identifier::equal(a, b); }
static const bool safeToCompareToEmptyOrDeleted = false;
};
template<> struct DefaultHash<KJS::UString::Rep*> {
typedef StrHash<KJS::UString::Rep*> Hash;
};
}
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