Bug 943744 (part 2) - Represent the sizes in StringInfo more compactly. r=till.

--HG--
extra : rebase_source : 799693bac2beb4609daf55fc5e8cbe19adff3ed8
This commit is contained in:
Nicholas Nethercote 2013-12-02 21:40:25 -08:00
parent 929454ee8d
commit c2c4132e4f
3 changed files with 64 additions and 51 deletions

View File

@ -211,49 +211,45 @@ struct CodeSizes
// This class holds information about the memory taken up by identical copies of
// a particular string. Multiple JSStrings may have their sizes aggregated
// together into one StringInfo object.
// together into one StringInfo object. Note that two strings with identical
// chars will not be aggregated together if one is a short string and the other
// is not.
struct StringInfo
{
StringInfo()
: numCopies(0), shortGCHeap(0), normalGCHeap(0), normalMallocHeap(0)
: numCopies(0),
isShort(0),
gcHeap(0),
mallocHeap(0)
{}
StringInfo(size_t shorts, size_t normals, size_t chars)
StringInfo(bool isShort, size_t gcSize, size_t mallocSize)
: numCopies(1),
shortGCHeap(shorts),
normalGCHeap(normals),
normalMallocHeap(chars)
isShort(isShort),
gcHeap(gcSize),
mallocHeap(mallocSize)
{}
void add(size_t shorts, size_t normals, size_t chars) {
shortGCHeap += shorts;
normalGCHeap += normals;
normalMallocHeap += chars;
void add(bool isShort, size_t gcSize, size_t mallocSize) {
numCopies++;
MOZ_ASSERT(isShort == this->isShort);
gcHeap += gcSize;
mallocHeap += mallocSize;
}
void add(const StringInfo& info) {
shortGCHeap += info.shortGCHeap;
normalGCHeap += info.normalGCHeap;
normalMallocHeap += info.normalMallocHeap;
numCopies += info.numCopies;
MOZ_ASSERT(info.isShort == isShort);
gcHeap += info.gcHeap;
mallocHeap += info.mallocHeap;
}
size_t totalSizeOf() const {
return shortGCHeap + normalGCHeap + normalMallocHeap;
}
size_t totalGCHeapSizeOf() const {
return shortGCHeap + normalGCHeap;
}
// How many copies of the string have we seen?
size_t numCopies;
uint32_t numCopies:31; // How many copies of the string have we seen?
uint32_t isShort:1; // Is it a short string?
// These are all totals across all copies of the string we've seen.
size_t shortGCHeap;
size_t normalGCHeap;
size_t normalMallocHeap;
size_t gcHeap;
size_t mallocHeap;
};
// Holds data about a notable string (one which uses more than
@ -353,7 +349,7 @@ struct ZoneStats : js::ZoneStatsPod
size_t n = ZoneStatsPod::sizeOfLiveGCThings();
for (size_t i = 0; i < notableStrings.length(); i++) {
const JS::NotableStringInfo& info = notableStrings[i];
n += info.totalGCHeapSizeOf();
n += info.gcHeap;
}
return n;
}

View File

@ -56,7 +56,15 @@ InefficientNonFlatteningStringHashPolicy::hash(const Lookup &l)
chars = ownedChars;
}
return mozilla::HashString(chars, l->length());
// We include the result of isShort() in the hash. This is because it is
// possible for a particular string (i.e. unique char sequence) to have one
// or more copies as short strings and one or more copies as non-short
// strings, and treating them separately for the purposes of notable string
// detection makes things simpler. In practice, although such collisions
// do happen, they are sufficiently rare that they are unlikely to have a
// significant effect on which strings are considered notable.
return mozilla::AddToHash(mozilla::HashString(chars, l->length()),
l->isShort());
}
/* static */ bool
@ -66,6 +74,10 @@ InefficientNonFlatteningStringHashPolicy::match(const JSString *const &k, const
if (k->length() != l->length())
return false;
// Just like in hash(), we must consider isShort() for the two strings.
if (k->isShort() != l->isShort())
return false;
const jschar *c1;
ScopedJSFreePtr<jschar> ownedChars1;
if (k->hasPureChars()) {
@ -277,11 +289,17 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
case JSTRACE_STRING: {
JSString *str = static_cast<JSString *>(thing);
bool isShort = str->isShort();
size_t strCharsSize = str->sizeOfExcludingThis(rtStats->mallocSizeOf_);
MOZ_ASSERT_IF(str->isShort(), strCharsSize == 0);
size_t shortStringThingSize = str->isShort() ? thingSize : 0;
size_t normalStringThingSize = !str->isShort() ? thingSize : 0;
if (isShort) {
zStats->stringsShortGCHeap += thingSize;
MOZ_ASSERT(strCharsSize == 0);
} else {
zStats->stringsNormalGCHeap += thingSize;
zStats->stringsNormalMallocHeap += strCharsSize;
}
// This string hashing is expensive. Its results are unused when doing
// coarse-grained measurements, and skipping it more than doubles the
@ -289,18 +307,13 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
if (granularity == FineGrained) {
ZoneStats::StringsHashMap::AddPtr p = zStats->strings.lookupForAdd(str);
if (!p) {
JS::StringInfo info(shortStringThingSize,
normalStringThingSize, strCharsSize);
JS::StringInfo info(isShort, thingSize, strCharsSize);
zStats->strings.add(p, str, info);
} else {
p->value().add(shortStringThingSize, normalStringThingSize, strCharsSize);
p->value().add(isShort, thingSize, strCharsSize);
}
}
zStats->stringsShortGCHeap += shortStringThingSize;
zStats->stringsNormalGCHeap += normalStringThingSize;
zStats->stringsNormalMallocHeap += strCharsSize;
break;
}
@ -402,7 +415,7 @@ FindNotableStrings(ZoneStats &zStats)
// If this string is too small, or if we can't grow the notableStrings
// vector, skip this string.
if (info.totalSizeOf() < NotableStringInfo::notableSize() ||
if (info.gcHeap + info.mallocHeap < NotableStringInfo::notableSize() ||
!zStats.notableStrings.growBy(1))
continue;
@ -410,12 +423,16 @@ FindNotableStrings(ZoneStats &zStats)
// We're moving this string from a non-notable to a notable bucket, so
// subtract it out of the non-notable tallies.
MOZ_ASSERT(zStats.stringsShortGCHeap >= info.shortGCHeap);
MOZ_ASSERT(zStats.stringsNormalGCHeap >= info.normalGCHeap);
MOZ_ASSERT(zStats.stringsNormalMallocHeap >= info.normalMallocHeap);
zStats.stringsShortGCHeap -= info.shortGCHeap;
zStats.stringsNormalGCHeap -= info.normalGCHeap;
zStats.stringsNormalMallocHeap -= info.normalMallocHeap;
if (info.isShort) {
MOZ_ASSERT(zStats.stringsShortGCHeap >= info.gcHeap);
zStats.stringsShortGCHeap -= info.gcHeap;
MOZ_ASSERT(info.mallocHeap == 0);
} else {
MOZ_ASSERT(zStats.stringsNormalGCHeap >= info.gcHeap);
MOZ_ASSERT(zStats.stringsNormalMallocHeap >= info.mallocHeap);
zStats.stringsNormalGCHeap -= info.gcHeap;
zStats.stringsNormalMallocHeap -= info.mallocHeap;
}
}
// zStats.strings holds unrooted JSString pointers, which we don't want to

View File

@ -1864,8 +1864,8 @@ ReportZoneStats(const JS::ZoneStats &zStats,
// bucket.
# define STRING_LENGTH "string(length="
if (FindInReadable(NS_LITERAL_CSTRING(STRING_LENGTH), notableString)) {
stringsNotableAboutMemoryGCHeap += info.totalGCHeapSizeOf();
stringsNotableAboutMemoryMallocHeap += info.normalMallocHeap;
stringsNotableAboutMemoryGCHeap += info.gcHeap;
stringsNotableAboutMemoryMallocHeap += info.mallocHeap;
continue;
}
@ -1884,7 +1884,7 @@ ReportZoneStats(const JS::ZoneStats &zStats,
REPORT_BYTES2(path + NS_LITERAL_CSTRING("gc-heap"),
KIND_NONHEAP,
info.totalGCHeapSizeOf(),
info.gcHeap,
nsPrintfCString("Memory allocated to hold headers for copies of "
"the given notable string. A string is notable if all of its copies "
"together use more than %d bytes total of JS GC heap and malloc heap "
@ -1893,12 +1893,12 @@ ReportZoneStats(const JS::ZoneStats &zStats,
"is short enough. If so, the string won't have any memory reported "
"under 'string-chars'.",
JS::NotableStringInfo::notableSize()));
gcTotal += info.totalGCHeapSizeOf();
gcTotal += info.gcHeap;
if (info.normalMallocHeap > 0) {
if (info.mallocHeap > 0) {
REPORT_BYTES2(path + NS_LITERAL_CSTRING("malloc-heap"),
KIND_HEAP,
info.normalMallocHeap,
info.mallocHeap,
nsPrintfCString("Memory allocated on the malloc heap to hold "
"string data for copies of the given notable string. A string is "
"notable if all of its copies together use more than %d bytes "