Bug 709653 - Fix GC heap memory reporters. r=bhackett.

--HG--
extra : rebase_source : 6805671750bd6a9e9661e70832a3837d4064f6ea
This commit is contained in:
Nicholas Nethercote 2011-12-11 21:21:18 -08:00
parent 5e5a2b9464
commit 41607c5826
3 changed files with 73 additions and 41 deletions

View File

@ -537,7 +537,7 @@ ChunkPool::expire(JSRuntime *rt, bool releaseAll)
}
JS_FRIEND_API(int64_t)
ChunkPool::countDecommittedArenas(JSRuntime *rt)
ChunkPool::countCleanDecommittedArenas(JSRuntime *rt)
{
JS_ASSERT(this == &rt->gcChunkPool);

View File

@ -786,7 +786,7 @@ class ChunkPool {
void expire(JSRuntime *rt, bool releaseAll);
/* Must be called either during the GC or with the GC lock taken. */
JS_FRIEND_API(int64_t) countDecommittedArenas(JSRuntime *rt);
JS_FRIEND_API(int64_t) countCleanDecommittedArenas(JSRuntime *rt);
};
inline uintptr_t

View File

@ -1265,6 +1265,8 @@ CompartmentCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
void
ChunkCallback(JSContext *cx, void *vdata, js::gc::Chunk *chunk)
{
// Nb: This function is only called for dirty chunks, which is why we
// increment gcHeapChunkDirtyDecommitted.
IterateData *data = static_cast<IterateData *>(vdata);
for (uint32 i = 0; i < js::gc::ArenasPerChunk; i++)
if (chunk->decommittedArenas.get(i))
@ -1395,6 +1397,29 @@ ReportMemoryBytes0(const nsCString &path, PRInt32 kind, PRInt64 amount,
ReportMemoryBytes(path, kind, amount, desc, callback, closure);
}
template <int N>
inline void
ReportGCHeapBytes(const nsACString &path, PRInt64 *total, PRInt64 amount,
const char (&desc)[N],
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
ReportMemory(path, nsIMemoryReporter::KIND_NONHEAP, nsIMemoryReporter::UNITS_BYTES, amount,
desc, callback, closure);
*total += amount;
}
template <int N>
inline void
ReportGCHeapBytes0(const nsCString &path, PRInt64 *total, PRInt64 amount,
const char (&desc)[N],
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
if (amount)
return ReportGCHeapBytes(path, total, amount, desc, callback, closure);
}
template <int N>
inline void
ReportMemoryPercentage(const nsACString &path, PRInt32 kind, PRInt64 amount,
@ -1418,8 +1443,6 @@ MakeMemoryReporterPath(const nsACString &pathPrefix,
} // anonymous namespace
#define JS_GC_HEAP_KIND nsIMemoryReporter::KIND_NONHEAP
// We have per-compartment GC heap totals, so we can't put the total GC heap
// size in the explicit allocations tree. But it's a useful figure, so put it
// in the "others" list.
@ -1548,7 +1571,7 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
data->compartmentStatsVector.SetCapacity(rt->compartments.length());
data->gcHeapChunkCleanDecommitted =
rt->gcChunkPool.countDecommittedArenas(rt) *
rt->gcChunkPool.countCleanDecommittedArenas(rt) *
js::gc::ArenaSize;
data->gcHeapChunkCleanUnused =
PRInt64(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
@ -1629,6 +1652,7 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
stats.gcHeapStrings +
stats.gcHeapShapesTree +
stats.gcHeapShapesDict +
stats.gcHeapShapesBase +
stats.gcHeapScripts +
stats.gcHeapTypeObjects +
stats.gcHeapXML;
@ -1683,51 +1707,53 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
#define SLOP_BYTES_STRING \
" The measurement includes slop bytes caused by the heap allocator rounding up request sizes."
static void
static PRInt64
ReportCompartmentStats(const CompartmentStats &stats,
const nsACString &pathPrefix,
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
PRInt64 gcTotal = 0;
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/arena/headers"),
JS_GC_HEAP_KIND, stats.gcHeapArenaHeaders,
&gcTotal, stats.gcHeapArenaHeaders,
"Memory on the compartment's garbage-collected JavaScript heap, within "
"arenas, that is used to hold internal book-keeping information.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/arena/padding"),
JS_GC_HEAP_KIND, stats.gcHeapArenaPadding,
&gcTotal, stats.gcHeapArenaPadding,
"Memory on the compartment's garbage-collected JavaScript heap, within "
"arenas, that is unused and present only so that other data is aligned. "
"This constitutes internal fragmentation.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/arena/unused"),
JS_GC_HEAP_KIND, stats.gcHeapArenaUnused,
&gcTotal, stats.gcHeapArenaUnused,
"Memory on the compartment's garbage-collected JavaScript heap, within "
"arenas, that could be holding useful data but currently isn't.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/objects/non-function"),
JS_GC_HEAP_KIND, stats.gcHeapObjectsNonFunction,
&gcTotal, stats.gcHeapObjectsNonFunction,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"non-function objects.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/objects/function"),
JS_GC_HEAP_KIND, stats.gcHeapObjectsFunction,
&gcTotal, stats.gcHeapObjectsFunction,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"function objects.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/strings"),
JS_GC_HEAP_KIND, stats.gcHeapStrings,
&gcTotal, stats.gcHeapStrings,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"string headers. String headers contain various pieces of information "
"about a string, but do not contain (except in the case of very short "
@ -1735,45 +1761,45 @@ ReportCompartmentStats(const CompartmentStats &stats,
"under 'gc-heap/string-chars' instead.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/scripts"),
JS_GC_HEAP_KIND, stats.gcHeapScripts,
&gcTotal, stats.gcHeapScripts,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"JSScript instances. A JSScript is created for each user-defined function "
"in a script. One is also created for the top-level code in a script.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/shapes/tree"),
JS_GC_HEAP_KIND, stats.gcHeapShapesTree,
&gcTotal, stats.gcHeapShapesTree,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"shapes that are in a property tree.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/shapes/dict"),
JS_GC_HEAP_KIND, stats.gcHeapShapesDict,
&gcTotal, stats.gcHeapShapesDict,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"shapes that are in dictionary mode.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/shapes/base"),
JS_GC_HEAP_KIND, stats.gcHeapShapesBase,
&gcTotal, stats.gcHeapShapesBase,
"Memory on the compartment's garbage-collected JavaScript heap that collates "
"data common to many shapes.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/type-objects"),
JS_GC_HEAP_KIND, stats.gcHeapTypeObjects,
&gcTotal, stats.gcHeapTypeObjects,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"type inference information.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/xml"),
JS_GC_HEAP_KIND, stats.gcHeapXML,
&gcTotal, stats.gcHeapXML,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"E4X XML objects.",
callback, closure);
@ -1858,7 +1884,7 @@ ReportCompartmentStats(const CompartmentStats &stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"type-inference/object-main"),
JS_GC_HEAP_KIND,
nsIMemoryReporter::KIND_HEAP,
stats.typeInferenceMemory.objects,
"Memory used during type inference to store types and possible "
"property types of JS objects.",
@ -1878,6 +1904,8 @@ ReportCompartmentStats(const CompartmentStats &stats,
"Memory used during type inference and compilation to hold transient "
"analysis information. Cleared on GC.",
callback, closure);
return gcTotal;
}
void
@ -1885,11 +1913,12 @@ ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
PRInt64 gcTotal = 0;
for (PRUint32 index = 0;
index < data.compartmentStatsVector.Length();
index++) {
ReportCompartmentStats(data.compartmentStatsVector[index], pathPrefix,
callback, closure);
gcTotal += ReportCompartmentStats(data.compartmentStatsVector[index], pathPrefix,
callback, closure);
}
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
@ -1939,39 +1968,42 @@ ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
"Memory used by XPConnect." SLOP_BYTES_STRING,
callback, closure);
ReportMemoryBytes(pathPrefix +
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
JS_GC_HEAP_KIND, data.gcHeapChunkDirtyUnused,
&gcTotal, data.gcHeapChunkDirtyUnused,
"Memory on the garbage-collected JavaScript heap, within chunks with at "
"least one allocated GC thing, that could be holding useful data but "
"currently isn't. Memory here is mutually exclusive with memory reported"
"under gc-heap-decommitted.",
callback, closure);
ReportMemoryBytes(pathPrefix +
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-chunk-clean-unused"),
JS_GC_HEAP_KIND, data.gcHeapChunkCleanUnused,
&gcTotal, data.gcHeapChunkCleanUnused,
"Memory on the garbage-collected JavaScript heap taken by completely empty "
"chunks, that soon will be released unless claimed for new allocations. "
"Memory here is mutually exclusive with memory reported under "
"gc-heap-decommitted.",
callback, closure);
ReportMemoryBytes(pathPrefix +
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-decommitted"),
JS_GC_HEAP_KIND,
&gcTotal,
data.gcHeapChunkCleanDecommitted + data.gcHeapChunkDirtyDecommitted,
"Memory in the address space of the garbage-collected JavaScript heap that "
"is currently returned to the OS.",
callback, closure);
ReportMemoryBytes(pathPrefix +
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-chunk-admin"),
JS_GC_HEAP_KIND, data.gcHeapChunkAdmin,
&gcTotal, data.gcHeapChunkAdmin,
"Memory on the garbage-collected JavaScript heap, within chunks, that is "
"used to hold internal book-keeping information.",
callback, closure);
// gcTotal is the sum of everything we've reported for the GC heap. It
// should equal data.gcHeapChunkTotal.
JS_ASSERT(gcTotal == data.gcHeapChunkTotal);
}
} // namespace memory