Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2001 Dirk Mueller ( mueller@kde.org ) | 4 * (C) 2001 Dirk Mueller ( mueller@kde.org ) |
| 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All | 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All |
| 6 * rights reserved. | 6 * rights reserved. |
| 7 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) | 7 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) |
| 8 * | 8 * |
| 9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
| 10 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 34 #include "platform/wtf/text/AtomicString.h" | 34 #include "platform/wtf/text/AtomicString.h" |
| 35 #include "platform/wtf/text/AtomicStringTable.h" | 35 #include "platform/wtf/text/AtomicStringTable.h" |
| 36 #include "platform/wtf/text/CString.h" | 36 #include "platform/wtf/text/CString.h" |
| 37 #include "platform/wtf/text/CharacterNames.h" | 37 #include "platform/wtf/text/CharacterNames.h" |
| 38 #include "platform/wtf/text/StringBuffer.h" | 38 #include "platform/wtf/text/StringBuffer.h" |
| 39 #include "platform/wtf/text/StringHash.h" | 39 #include "platform/wtf/text/StringHash.h" |
| 40 #include "platform/wtf/text/StringToNumber.h" | 40 #include "platform/wtf/text/StringToNumber.h" |
| 41 #include <algorithm> | 41 #include <algorithm> |
| 42 #include <memory> | 42 #include <memory> |
| 43 | 43 |
| 44 #ifdef STRING_STATS | |
| 45 #include "platform/wtf/DataLog.h" | |
| 46 #include "platform/wtf/HashMap.h" | |
| 47 #include "platform/wtf/HashSet.h" | |
| 48 #include "platform/wtf/RefCounted.h" | |
| 49 #include "platform/wtf/ThreadingPrimitives.h" | |
| 50 #include <unistd.h> | |
| 51 #endif | |
| 52 | |
| 53 using namespace std; | 44 using namespace std; |
| 54 | 45 |
| 55 namespace WTF { | 46 namespace WTF { |
| 56 | 47 |
| 57 using namespace Unicode; | 48 using namespace Unicode; |
| 58 | 49 |
| 59 // As of Jan 2017, StringImpl needs 2 * sizeof(int) + 29 bits of data, and | 50 // As of Jan 2017, StringImpl needs 2 * sizeof(int) + 29 bits of data, and |
| 60 // sizeof(ThreadRestrictionVerifier) is 16 bytes. Thus, in DCHECK mode the | 51 // sizeof(ThreadRestrictionVerifier) is 16 bytes. Thus, in DCHECK mode the |
| 61 // class may be padded to 32 bytes. | 52 // class may be padded to 32 bytes. |
| 62 #if DCHECK_IS_ON() | 53 #if DCHECK_IS_ON() |
| 63 static_assert(sizeof(StringImpl) <= 8 * sizeof(int), | 54 static_assert(sizeof(StringImpl) <= 8 * sizeof(int), |
| 64 "StringImpl should stay small"); | 55 "StringImpl should stay small"); |
| 65 #else | 56 #else |
| 66 static_assert(sizeof(StringImpl) <= 3 * sizeof(int), | 57 static_assert(sizeof(StringImpl) <= 3 * sizeof(int), |
| 67 "StringImpl should stay small"); | 58 "StringImpl should stay small"); |
| 68 #endif | 59 #endif |
| 69 | 60 |
| 70 #ifdef STRING_STATS | |
|
dcheng
2017/05/03 19:44:40
Hmm... FWIW, the last time I asked about removing
| |
| 71 | |
| 72 static Mutex& statsMutex() { | |
| 73 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); | |
| 74 return mutex; | |
| 75 } | |
| 76 | |
| 77 static HashSet<void*>& liveStrings() { | |
| 78 // Notice that we can't use HashSet<StringImpl*> because then HashSet would | |
| 79 // dedup identical strings. | |
| 80 DEFINE_STATIC_LOCAL(HashSet<void*>, strings, ()); | |
| 81 return strings; | |
| 82 } | |
| 83 | |
| 84 void addStringForStats(StringImpl* string) { | |
| 85 MutexLocker locker(statsMutex()); | |
| 86 liveStrings().add(string); | |
| 87 } | |
| 88 | |
| 89 void removeStringForStats(StringImpl* string) { | |
| 90 MutexLocker locker(statsMutex()); | |
| 91 liveStrings().remove(string); | |
| 92 } | |
| 93 | |
| 94 static void fillWithSnippet(const StringImpl* string, Vector<char>& snippet) { | |
| 95 const unsigned kMaxSnippetLength = 64; | |
| 96 snippet.clear(); | |
| 97 | |
| 98 size_t expectedLength = std::min(string->length(), kMaxSnippetLength); | |
| 99 if (expectedLength == kMaxSnippetLength) | |
| 100 expectedLength += 3; // For the "...". | |
| 101 ++expectedLength; // For the terminating '\0'. | |
| 102 snippet.reserveCapacity(expectedLength); | |
| 103 | |
| 104 size_t i; | |
| 105 for (i = 0; i < string->length() && i < kMaxSnippetLength; ++i) { | |
| 106 UChar c = (*string)[i]; | |
| 107 if (IsASCIIPrintable(c)) | |
| 108 snippet.append(c); | |
| 109 else | |
| 110 snippet.append('?'); | |
| 111 } | |
| 112 if (i < string->length()) { | |
| 113 snippet.append('.'); | |
| 114 snippet.append('.'); | |
| 115 snippet.append('.'); | |
| 116 } | |
| 117 snippet.append('\0'); | |
| 118 } | |
| 119 | |
| 120 static bool isUnnecessarilyWide(const StringImpl* string) { | |
| 121 if (string->is8Bit()) | |
| 122 return false; | |
| 123 UChar c = 0; | |
| 124 for (unsigned i = 0; i < string->length(); ++i) | |
| 125 c |= (*string)[i] >> 8; | |
| 126 return !c; | |
| 127 } | |
| 128 | |
| 129 class PerStringStats : public RefCounted<PerStringStats> { | |
| 130 public: | |
| 131 static PassRefPtr<PerStringStats> create() { | |
| 132 return adoptRef(new PerStringStats); | |
| 133 } | |
| 134 | |
| 135 void add(const StringImpl* string) { | |
| 136 ++m_numberOfCopies; | |
| 137 if (!m_length) { | |
| 138 m_length = string->length(); | |
| 139 fillWithSnippet(string, m_snippet); | |
| 140 } | |
| 141 if (string->isAtomic()) | |
| 142 ++m_numberOfAtomicCopies; | |
| 143 if (isUnnecessarilyWide(string)) | |
| 144 m_unnecessarilyWide = true; | |
| 145 } | |
| 146 | |
| 147 size_t totalCharacters() const { return m_numberOfCopies * m_length; } | |
| 148 | |
| 149 void print() { | |
| 150 const char* status = "ok"; | |
| 151 if (m_unnecessarilyWide) | |
| 152 status = "16"; | |
| 153 dataLogF("%8u copies (%s) of length %8u %s\n", m_numberOfCopies, status, | |
| 154 m_length, m_snippet.data()); | |
| 155 } | |
| 156 | |
| 157 bool m_unnecessarilyWide; | |
| 158 unsigned m_numberOfCopies; | |
| 159 unsigned m_length; | |
| 160 unsigned m_numberOfAtomicCopies; | |
| 161 Vector<char> m_snippet; | |
| 162 | |
| 163 private: | |
| 164 PerStringStats() | |
| 165 : m_unnecessarilyWide(false), | |
| 166 m_numberOfCopies(0), | |
| 167 m_length(0), | |
| 168 m_numberOfAtomicCopies(0) {} | |
| 169 }; | |
| 170 | |
| 171 bool operator<(const RefPtr<PerStringStats>& a, | |
| 172 const RefPtr<PerStringStats>& b) { | |
| 173 if (a->m_unnecessarilyWide != b->m_unnecessarilyWide) | |
| 174 return !a->m_unnecessarilyWide && b->m_unnecessarilyWide; | |
| 175 if (a->totalCharacters() != b->totalCharacters()) | |
| 176 return a->totalCharacters() < b->totalCharacters(); | |
| 177 if (a->m_numberOfCopies != b->m_numberOfCopies) | |
| 178 return a->m_numberOfCopies < b->m_numberOfCopies; | |
| 179 if (a->m_length != b->m_length) | |
| 180 return a->m_length < b->m_length; | |
| 181 return a->m_numberOfAtomicCopies < b->m_numberOfAtomicCopies; | |
| 182 } | |
| 183 | |
| 184 static void printLiveStringStats(void*) { | |
| 185 MutexLocker locker(statsMutex()); | |
| 186 HashSet<void*>& strings = liveStrings(); | |
| 187 | |
| 188 HashMap<StringImpl*, RefPtr<PerStringStats>> stats; | |
| 189 for (HashSet<void*>::iterator iter = strings.begin(); iter != strings.end(); | |
| 190 ++iter) { | |
| 191 StringImpl* string = static_cast<StringImpl*>(*iter); | |
| 192 HashMap<StringImpl*, RefPtr<PerStringStats>>::iterator entry = | |
| 193 stats.find(string); | |
| 194 RefPtr<PerStringStats> value = | |
| 195 entry == stats.end() ? RefPtr<PerStringStats>(PerStringStats::create()) | |
| 196 : entry->value; | |
| 197 value->add(string); | |
| 198 stats.set(string, value.release()); | |
| 199 } | |
| 200 | |
| 201 Vector<RefPtr<PerStringStats>> all; | |
| 202 for (HashMap<StringImpl*, RefPtr<PerStringStats>>::iterator iter = | |
| 203 stats.begin(); | |
| 204 iter != stats.end(); ++iter) | |
| 205 all.append(iter->value); | |
| 206 | |
| 207 std::sort(all.begin(), all.end()); | |
| 208 std::reverse(all.begin(), all.end()); | |
| 209 for (size_t i = 0; i < 20 && i < all.size(); ++i) | |
| 210 all[i]->print(); | |
| 211 } | |
| 212 | |
| 213 StringStats StringImpl::m_stringStats; | |
| 214 | |
| 215 unsigned StringStats::s_stringRemovesTillPrintStats = | |
| 216 StringStats::s_printStringStatsFrequency; | |
| 217 | |
| 218 void StringStats::removeString(StringImpl* string) { | |
| 219 unsigned length = string->length(); | |
| 220 --m_totalNumberStrings; | |
| 221 | |
| 222 if (string->is8Bit()) { | |
| 223 --m_number8BitStrings; | |
| 224 m_total8BitData -= length; | |
| 225 } else { | |
| 226 --m_number16BitStrings; | |
| 227 m_total16BitData -= length; | |
| 228 } | |
| 229 | |
| 230 if (!--s_stringRemovesTillPrintStats) { | |
| 231 s_stringRemovesTillPrintStats = s_printStringStatsFrequency; | |
| 232 printStats(); | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 void StringStats::printStats() { | |
| 237 dataLogF("String stats for process id %d:\n", getpid()); | |
| 238 | |
| 239 unsigned long long totalNumberCharacters = m_total8BitData + m_total16BitData; | |
| 240 double percent8Bit = | |
| 241 m_totalNumberStrings | |
| 242 ? ((double)m_number8BitStrings * 100) / (double)m_totalNumberStrings | |
| 243 : 0.0; | |
| 244 double average8bitLength = | |
| 245 m_number8BitStrings | |
| 246 ? (double)m_total8BitData / (double)m_number8BitStrings | |
| 247 : 0.0; | |
| 248 dataLogF( | |
| 249 "%8u (%5.2f%%) 8 bit %12llu chars %12llu bytes avg length " | |
| 250 "%6.1f\n", | |
| 251 m_number8BitStrings, percent8Bit, m_total8BitData, m_total8BitData, | |
| 252 average8bitLength); | |
| 253 | |
| 254 double percent16Bit = | |
| 255 m_totalNumberStrings | |
| 256 ? ((double)m_number16BitStrings * 100) / (double)m_totalNumberStrings | |
| 257 : 0.0; | |
| 258 double average16bitLength = | |
| 259 m_number16BitStrings | |
| 260 ? (double)m_total16BitData / (double)m_number16BitStrings | |
| 261 : 0.0; | |
| 262 dataLogF( | |
| 263 "%8u (%5.2f%%) 16 bit %12llu chars %12llu bytes avg length " | |
| 264 "%6.1f\n", | |
| 265 m_number16BitStrings, percent16Bit, m_total16BitData, | |
| 266 m_total16BitData * 2, average16bitLength); | |
| 267 | |
| 268 double averageLength = | |
| 269 m_totalNumberStrings | |
| 270 ? (double)totalNumberCharacters / (double)m_totalNumberStrings | |
| 271 : 0.0; | |
| 272 unsigned long long totalDataBytes = m_total8BitData + m_total16BitData * 2; | |
| 273 dataLogF( | |
| 274 "%8u Total %12llu chars %12llu bytes avg length " | |
| 275 "%6.1f\n", | |
| 276 m_totalNumberStrings, totalNumberCharacters, totalDataBytes, | |
| 277 averageLength); | |
| 278 unsigned long long totalSavedBytes = m_total8BitData; | |
| 279 double percentSavings = totalSavedBytes | |
| 280 ? ((double)totalSavedBytes * 100) / | |
| 281 (double)(totalDataBytes + totalSavedBytes) | |
| 282 : 0.0; | |
| 283 dataLogF(" Total savings %12llu bytes (%5.2f%%)\n", totalSavedBytes, | |
| 284 percentSavings); | |
| 285 | |
| 286 unsigned totalOverhead = m_totalNumberStrings * sizeof(StringImpl); | |
| 287 double overheadPercent = (double)totalOverhead / (double)totalDataBytes * 100; | |
| 288 dataLogF(" StringImpl overheader: %8u (%5.2f%%)\n", totalOverhead, | |
| 289 overheadPercent); | |
| 290 | |
| 291 internal::callOnMainThread(&printLiveStringStats, nullptr); | |
| 292 } | |
| 293 #endif | |
| 294 | |
| 295 void* StringImpl::operator new(size_t size) { | 61 void* StringImpl::operator new(size_t size) { |
| 296 DCHECK_EQ(size, sizeof(StringImpl)); | 62 DCHECK_EQ(size, sizeof(StringImpl)); |
| 297 return Partitions::BufferMalloc(size, "WTF::StringImpl"); | 63 return Partitions::BufferMalloc(size, "WTF::StringImpl"); |
| 298 } | 64 } |
| 299 | 65 |
| 300 void StringImpl::operator delete(void* ptr) { | 66 void StringImpl::operator delete(void* ptr) { |
| 301 Partitions::BufferFree(ptr); | 67 Partitions::BufferFree(ptr); |
| 302 } | 68 } |
| 303 | 69 |
| 304 inline StringImpl::~StringImpl() { | 70 inline StringImpl::~StringImpl() { |
| 305 DCHECK(!IsStatic()); | 71 DCHECK(!IsStatic()); |
| 306 | 72 |
| 307 STRING_STATS_REMOVE_STRING(this); | |
| 308 | |
| 309 if (IsAtomic()) | 73 if (IsAtomic()) |
| 310 AtomicStringTable::Instance().Remove(this); | 74 AtomicStringTable::Instance().Remove(this); |
| 311 } | 75 } |
| 312 | 76 |
| 313 void StringImpl::DestroyIfNotStatic() const { | 77 void StringImpl::DestroyIfNotStatic() const { |
| 314 if (!IsStatic()) | 78 if (!IsStatic()) |
| 315 delete this; | 79 delete this; |
| 316 } | 80 } |
| 317 | 81 |
| 318 void StringImpl::UpdateContainsOnlyASCII() const { | 82 void StringImpl::UpdateContainsOnlyASCII() const { |
| (...skipping 1931 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2250 } else if (LocaleIdMatchesLang(locale_identifier, "lt")) { | 2014 } else if (LocaleIdMatchesLang(locale_identifier, "lt")) { |
| 2251 // TODO(rob.buis) implement upper-casing rules for lt | 2015 // TODO(rob.buis) implement upper-casing rules for lt |
| 2252 // like in StringImpl::upper(locale). | 2016 // like in StringImpl::upper(locale). |
| 2253 } | 2017 } |
| 2254 } | 2018 } |
| 2255 | 2019 |
| 2256 return ToUpper(c); | 2020 return ToUpper(c); |
| 2257 } | 2021 } |
| 2258 | 2022 |
| 2259 } // namespace WTF | 2023 } // namespace WTF |
| OLD | NEW |