Title: [127799] trunk/Source/WTF
Revision
127799
Author
msab...@apple.com
Date
2012-09-06 16:41:29 -0700 (Thu, 06 Sep 2012)

Log Message

ENH: Add Logging to StringImpl to track String Types
https://bugs.webkit.org/show_bug.cgi?id=95807

Reviewed by Benjamin Poulain.

Added StringsStats class that keeps track of the number of strings, number of 8 and 16 bit
strings as well as the number of 8 bit strings up converted to 16 bits. The number of characrters
for each type is also accumulated. These statistics are output via DataLog every 5000
calls to StringImpl destructor. The 5000 can be adjusted via s_printStringStatsFrequency.
This StringStats code is disabled by default and enabled by defining STRING_STATS in
wtf/text/StringImpl.h.

* wtf/text/StringImpl.cpp:
(WTF::StringStats::removeString):
(WTF::StringStats::printStats):
(WTF::StringImpl::~StringImpl):
(WTF::StringImpl::getData16SlowCase):
* wtf/text/StringImpl.h:
(WTF::StringStats::add8BitString):
(StringStats):
(WTF::StringStats::add16BitString):
(WTF::StringStats::addUpconvertedString):
(WTF::StringImpl::StringImpl):
(StringImpl):
(WTF::StringImpl::isSubString):
(WTF::StringImpl::stringStats):

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (127798 => 127799)


--- trunk/Source/WTF/ChangeLog	2012-09-06 23:40:56 UTC (rev 127798)
+++ trunk/Source/WTF/ChangeLog	2012-09-06 23:41:29 UTC (rev 127799)
@@ -1,3 +1,32 @@
+2012-09-06  Michael Saboff  <msab...@apple.com>
+
+        ENH: Add Logging to StringImpl to track String Types
+        https://bugs.webkit.org/show_bug.cgi?id=95807
+
+        Reviewed by Benjamin Poulain.
+
+        Added StringsStats class that keeps track of the number of strings, number of 8 and 16 bit
+        strings as well as the number of 8 bit strings up converted to 16 bits. The number of characrters
+        for each type is also accumulated. These statistics are output via DataLog every 5000
+        calls to StringImpl destructor. The 5000 can be adjusted via s_printStringStatsFrequency.
+        This StringStats code is disabled by default and enabled by defining STRING_STATS in
+        wtf/text/StringImpl.h.
+
+        * wtf/text/StringImpl.cpp:
+        (WTF::StringStats::removeString):
+        (WTF::StringStats::printStats):
+        (WTF::StringImpl::~StringImpl):
+        (WTF::StringImpl::getData16SlowCase):
+        * wtf/text/StringImpl.h:
+        (WTF::StringStats::add8BitString):
+        (StringStats):
+        (WTF::StringStats::add16BitString):
+        (WTF::StringStats::addUpconvertedString):
+        (WTF::StringImpl::StringImpl):
+        (StringImpl):
+        (WTF::StringImpl::isSubString):
+        (WTF::StringImpl::stringStats):
+
 2012-09-06  Patrick Gansterer  <par...@webkit.org>
 
         Fix export macros in IntegerToStringConversion.h

Modified: trunk/Source/WTF/wtf/text/StringImpl.cpp (127798 => 127799)


--- trunk/Source/WTF/wtf/text/StringImpl.cpp	2012-09-06 23:40:56 UTC (rev 127798)
+++ trunk/Source/WTF/wtf/text/StringImpl.cpp	2012-09-06 23:41:29 UTC (rev 127799)
@@ -32,6 +32,9 @@
 #include <wtf/WTFThreadData.h>
 #include <wtf/unicode/CharacterNames.h>
 
+#ifdef STRING_STATS
+#include <wtf/DataLog.h>
+#endif
 
 using namespace std;
 
@@ -41,10 +44,69 @@
 
 COMPILE_ASSERT(sizeof(StringImpl) == 2 * sizeof(int) + 3 * sizeof(void*), StringImpl_should_stay_small);
 
+#ifdef STRING_STATS
+StringStats StringImpl::m_stringStats;
+
+static unsigned StringStats::s_stringRemovesTillPrintStats = StringStats::s_printStringStatsFrequency;
+
+void StringStats::removeString(StringImpl* string)
+{
+    unsigned length = string->length();
+    bool isSubString = string->isSubString();
+
+    --m_totalNumberStrings;
+
+    if (string->has16BitShadow()) {
+        --m_numberUpconvertedStrings;
+        if (!isSubString)
+            m_totalUpconvertedData -= length;
+    }
+
+    if (string->is8Bit()) {
+        --m_number8BitStrings;
+        if (!isSubString)
+            m_total8BitData -= length;
+    } else {
+        --m_number16BitStrings;
+        if (!isSubString)
+            m_total16BitData -= length;
+    }
+
+    if (!--s_stringRemovesTillPrintStats) {
+        s_stringRemovesTillPrintStats = s_printStringStatsFrequency;
+        printStats();
+    }
+}
+
+void StringStats::printStats()
+{
+    dataLog("String stats for process id %d:\n", getpid());
+
+    unsigned long long totalNumberCharacters = m_total8BitData + m_total16BitData;
+    double percent8Bit = m_totalNumberStrings ? ((double)m_number8BitStrings * 100) / (double)m_totalNumberStrings : 0.0;
+    double average8bitLength = m_number8BitStrings ? (double)m_total8BitData / (double)m_number8BitStrings : 0.0;
+    dataLog("%8u (%5.2f%%) 8 bit        %12llu chars  %12llu bytes  avg length %6.1f\n", m_number8BitStrings, percent8Bit, m_total8BitData, m_total8BitData, average8bitLength);
+
+    double percent16Bit = m_totalNumberStrings ? ((double)m_number16BitStrings * 100) / (double)m_totalNumberStrings : 0.0;
+    double average16bitLength = m_number16BitStrings ? (double)m_total16BitData / (double)m_number16BitStrings : 0.0;
+    dataLog("%8u (%5.2f%%) 16 bit       %12llu chars  %12llu bytes  avg length %6.1f\n", m_number16BitStrings, percent16Bit, m_total16BitData, m_total16BitData * 2, average16bitLength);
+
+    double percentUpconverted = m_totalNumberStrings ? ((double)m_numberUpconvertedStrings * 100) / (double)m_number8BitStrings : 0.0;
+    double averageUpconvertedLength = m_numberUpconvertedStrings ? (double)m_totalUpconvertedData / (double)m_numberUpconvertedStrings : 0.0;
+    dataLog("%8u (%5.2f%%) upconverted  %12llu chars  %12llu bytes  avg length %6.1f\n", m_numberUpconvertedStrings, percentUpconverted, m_totalUpconvertedData, m_totalUpconvertedData * 2, averageUpconvertedLength);
+
+    double averageLength = m_totalNumberStrings ? (double)totalNumberCharacters / (double)m_totalNumberStrings : 0.0;
+    dataLog("%8u Total                 %12llu chars  %12llu bytes  avg length %6.1f\n", m_totalNumberStrings, totalNumberCharacters, m_total8BitData + (m_total16BitData + m_totalUpconvertedData) * 2, averageLength);
+}
+#endif
+
+
 StringImpl::~StringImpl()
 {
     ASSERT(!isStatic());
 
+    STRING_STATS_REMOVE_STRING(this);
+
     if (isAtomic())
         AtomicString::remove(this);
 #if USE(JSC)
@@ -221,6 +283,8 @@
         return m_substringBuffer->characters() + offset;
     }
 
+    STRING_STATS_ADD_UPCONVERTED_STRING(m_length);
+    
     unsigned len = length();
     if (hasTerminatingNullCharacter())
         len++;

Modified: trunk/Source/WTF/wtf/text/StringImpl.h (127798 => 127799)


--- trunk/Source/WTF/wtf/text/StringImpl.h	2012-09-06 23:40:56 UTC (rev 127798)
+++ trunk/Source/WTF/wtf/text/StringImpl.h	2012-09-06 23:41:29 UTC (rev 127799)
@@ -68,6 +68,63 @@
 typedef bool (*CharacterMatchFunctionPtr)(UChar);
 typedef bool (*IsWhiteSpaceFunctionPtr)(UChar);
 
+// Define STRING_STATS to turn on run time statistics of string sizes and memory usage
+#undef STRING_STATS
+
+#ifdef STRING_STATS
+struct StringStats {
+    inline void add8BitString(unsigned length, bool isSubString = false)
+    {
+        ++m_totalNumberStrings;
+        ++m_number8BitStrings;
+        if (!isSubString)
+            m_total8BitData += length;
+    }
+
+    inline void add16BitString(unsigned length, bool isSubString = false)
+    {
+        ++m_totalNumberStrings;
+        ++m_number16BitStrings;
+        if (!isSubString)
+            m_total16BitData += length;
+    }
+
+    inline void addUpconvertedString(unsigned length)
+    {
+        ++m_numberUpconvertedStrings;
+        m_totalUpconvertedData += length;
+    }
+
+    void removeString(StringImpl*);
+    void printStats();
+
+    static const unsigned s_printStringStatsFrequency = 5000;
+    static unsigned s_stringRemovesTillPrintStats;
+
+    unsigned m_totalNumberStrings;
+    unsigned m_number8BitStrings;
+    unsigned m_number16BitStrings;
+    unsigned m_numberUpconvertedStrings;
+    unsigned long long m_total8BitData;
+    unsigned long long m_total16BitData;
+    unsigned long long m_totalUpconvertedData;
+};
+
+#define STRING_STATS_ADD_8BIT_STRING(length) StringImpl::stringStats().add8BitString(length)
+#define STRING_STATS_ADD_8BIT_STRING2(length, isSubString) StringImpl::stringStats().add8BitString(length, isSubString)
+#define STRING_STATS_ADD_16BIT_STRING(length) StringImpl::stringStats().add16BitString(length)
+#define STRING_STATS_ADD_16BIT_STRING2(length, isSubString) StringImpl::stringStats().add16BitString(length, isSubString)
+#define STRING_STATS_ADD_UPCONVERTED_STRING(length) StringImpl::stringStats().addUpconvertedString(length)
+#define STRING_STATS_REMOVE_STRING(string) StringImpl::stringStats().removeString(string)
+#else
+#define STRING_STATS_ADD_8BIT_STRING(length) ((void)0)
+#define STRING_STATS_ADD_8BIT_STRING2(length, isSubString) ((void)0)
+#define STRING_STATS_ADD_16BIT_STRING(length) ((void)0)
+#define STRING_STATS_ADD_16BIT_STRING2(length, isSubString) ((void)0)
+#define STRING_STATS_ADD_UPCONVERTED_STRING(length) ((void)0)
+#define STRING_STATS_REMOVE_STRING(string) ((void)0)
+#endif
+
 class StringImpl {
     WTF_MAKE_NONCOPYABLE(StringImpl); WTF_MAKE_FAST_ALLOCATED;
     friend struct JSC::IdentifierASCIIStringTranslator;
@@ -110,6 +167,8 @@
         // Ensure that the hash is computed so that AtomicStringHash can call existingHash()
         // with impunity. The empty string is special because it is never entered into
         // AtomicString's HashKey, but still needs to compare correctly.
+        STRING_STATS_ADD_16BIT_STRING(m_length);
+
         hash();
     }
 
@@ -126,6 +185,8 @@
         // Ensure that the hash is computed so that AtomicStringHash can call existingHash()
         // with impunity. The empty string is special because it is never entered into
         // AtomicString's HashKey, but still needs to compare correctly.
+        STRING_STATS_ADD_8BIT_STRING(m_length);
+
         hash();
     }
 
@@ -141,6 +202,8 @@
     {
         ASSERT(m_data8);
         ASSERT(m_length);
+
+        STRING_STATS_ADD_8BIT_STRING(m_length);
     }
 
     // Create a normal 16-bit string with internal storage (BufferInternal)
@@ -153,6 +216,8 @@
     {
         ASSERT(m_data16);
         ASSERT(m_length);
+
+        STRING_STATS_ADD_16BIT_STRING(m_length);
     }
 
     // Create a StringImpl adopting ownership of the provided buffer (BufferOwned)
@@ -165,6 +230,8 @@
     {
         ASSERT(m_data8);
         ASSERT(m_length);
+
+        STRING_STATS_ADD_8BIT_STRING(m_length);
     }
 
     enum ConstructFromLiteralTag { ConstructFromLiteral };
@@ -178,6 +245,8 @@
         ASSERT(m_data8);
         ASSERT(m_length);
         ASSERT(!characters[length]);
+
+        STRING_STATS_ADD_8BIT_STRING(0);
     }
 
     // Create a StringImpl adopting ownership of the provided buffer (BufferOwned)
@@ -190,6 +259,8 @@
     {
         ASSERT(m_data16);
         ASSERT(m_length);
+
+        STRING_STATS_ADD_16BIT_STRING(m_length);
     }
 
     // Used to create new strings that are a substring of an existing 8-bit StringImpl (BufferSubstring)
@@ -204,6 +275,8 @@
         ASSERT(m_data8);
         ASSERT(m_length);
         ASSERT(m_substringBuffer->bufferOwnership() != BufferSubstring);
+
+        STRING_STATS_ADD_8BIT_STRING2(m_length, true);
     }
 
     // Used to create new strings that are a substring of an existing 16-bit StringImpl (BufferSubstring)
@@ -218,6 +291,8 @@
         ASSERT(m_data16);
         ASSERT(m_length);
         ASSERT(m_substringBuffer->bufferOwnership() != BufferSubstring);
+
+        STRING_STATS_ADD_16BIT_STRING2(m_length, true);
     }
 
     enum CreateEmptyUnique_T { CreateEmptyUnique };
@@ -238,6 +313,8 @@
         if (!hash)
             hash = 1 << s_flagCount;
         m_hashAndFlags = hash | BufferInternal;
+
+        STRING_STATS_ADD_16BIT_STRING(m_length);
     }
 
 #if PLATFORM(QT)
@@ -260,6 +337,8 @@
         // Now that we have a ref we can safely reference the string data
         m_data16 = reinterpret_cast_ptr<const UChar*>(qStringData->data());
         ASSERT(m_data16);
+
+        STRING_STATS_ADD_16BIT_STRING(m_length);
     }
 #endif
 
@@ -432,6 +511,10 @@
             m_hashAndFlags &= ~s_hashFlagIsAtomic;
     }
 
+#ifdef STRING_STATS
+    bool isSubString() const { return  bufferOwnership() == BufferSubstring; }
+#endif
+
 #if PLATFORM(QT)
     QStringData* qStringData() { return bufferOwnership() == BufferAdoptedQString ? m_qStringData : 0; }
 #endif
@@ -622,6 +705,9 @@
     operator NSString*();
 #endif
 
+#ifdef STRING_STATS
+    ALWAYS_INLINE static StringStats& stringStats() { return m_stringStats; }
+#endif
 private:
     // This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings.
     static const unsigned s_copyCharsInlineCutOff = 20;
@@ -650,6 +736,9 @@
     static const unsigned s_hashFlagIsIdentifier = 1u << 2;
     static const unsigned s_hashMaskBufferOwnership = 1u | (1u << 1);
 
+#ifdef STRING_STATS
+    WTF_EXPORTDATA static StringStats m_stringStats;
+#endif
     unsigned m_refCount;
     unsigned m_length;
     union {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to