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 {