Bug 729403 (part 2, take 2) - Add js/runtime/gc-marker memory reporter. r=wmccloskey.
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -123,16 +123,17 @@ struct RuntimeStats
DestroyNameCallback destroyNameCb)
: runtimeObject(0)
, runtimeAtomsTable(0)
, runtimeContexts(0)
, runtimeNormal(0)
, runtimeTemporary(0)
, runtimeRegexpCode(0)
, runtimeStackCommitted(0)
+ , runtimeGCMarker(0)
, gcHeapChunkTotal(0)
, gcHeapChunkCleanUnused(0)
, gcHeapChunkDirtyUnused(0)
, gcHeapChunkCleanDecommitted(0)
, gcHeapChunkDirtyDecommitted(0)
, gcHeapArenaUnused(0)
, gcHeapChunkAdmin(0)
, gcHeapUnusedPercentage(0)
@@ -154,16 +155,17 @@ struct RuntimeStats
size_t runtimeObject;
size_t runtimeAtomsTable;
size_t runtimeContexts;
size_t runtimeNormal;
size_t runtimeTemporary;
size_t runtimeRegexpCode;
size_t runtimeStackCommitted;
+ size_t runtimeGCMarker;
size_t gcHeapChunkTotal;
size_t gcHeapChunkCleanUnused;
size_t gcHeapChunkDirtyUnused;
size_t gcHeapChunkCleanDecommitted;
size_t gcHeapChunkDirtyDecommitted;
size_t gcHeapArenaUnused;
size_t gcHeapChunkAdmin;
size_t gcHeapUnusedPercentage;
--- a/js/src/MemoryMetrics.cpp
+++ b/js/src/MemoryMetrics.cpp
@@ -206,20 +206,19 @@ CollectRuntimeStats(JSRuntime *rt, Runti
IterateChunks(cx, rtStats, StatsChunkCallback);
rtStats->runtimeObject = rtStats->mallocSizeOf(rt);
rt->sizeOfExcludingThis(rtStats->mallocSizeOf,
&rtStats->runtimeNormal,
&rtStats->runtimeTemporary,
&rtStats->runtimeRegexpCode,
- &rtStats->runtimeStackCommitted);
+ &rtStats->runtimeStackCommitted,
+ &rtStats->runtimeGCMarker);
- // Nb: we use sizeOfExcludingThis() because atomState.atoms is within
- // JSRuntime, and so counted when JSRuntime is counted.
rtStats->runtimeAtomsTable =
rt->atomState.atoms.sizeOfExcludingThis(rtStats->mallocSizeOf);
JSContext *acx, *iter = NULL;
while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL)
rtStats->runtimeContexts += acx->sizeOfIncludingThis(rtStats->mallocSizeOf);
}
@@ -330,17 +329,18 @@ GetExplicitNonHeapForRuntime(JSRuntime *
// explicit/runtime/regexp-code
// explicit/runtime/stack-committed
size_t regexpCode, stackCommitted;
rt->sizeOfExcludingThis(mallocSizeOf,
NULL,
NULL,
®expCode,
- &stackCommitted);
+ &stackCommitted,
+ NULL);
*amount += regexpCode;
*amount += stackCommitted;
}
JS_DestroyContextNoGC(cx);
return true;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -90,17 +90,17 @@
#include "jscompartment.h"
#include "jsobjinlines.h"
using namespace js;
using namespace js::gc;
void
JSRuntime::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary,
- size_t *regexpCode, size_t *stackCommitted)
+ size_t *regexpCode, size_t *stackCommitted, size_t *gcMarkerSize)
{
if (normal)
*normal = mallocSizeOf(dtoaState);
if (temporary)
*temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
if (regexpCode) {
@@ -108,16 +108,19 @@ JSRuntime::sizeOfExcludingThis(JSMallocS
if (execAlloc_)
execAlloc_->sizeOfCode(&method, ®exp, &unused);
JS_ASSERT(method == 0); /* this execAlloc is only used for regexp code */
*regexpCode = regexp + unused;
}
if (stackCommitted)
*stackCommitted = stackSpace.sizeOfCommitted();
+
+ if (gcMarkerSize)
+ *gcMarkerSize = gcMarker.sizeOfExcludingThis(mallocSizeOf);
}
JS_FRIEND_API(void)
JSRuntime::triggerOperationCallback()
{
/*
* Use JS_ATOMIC_SET in the hope that it ensures the write will become
* immediately visible to other processors polling the flag.
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -684,17 +684,17 @@ struct JSRuntime : js::RuntimeFriendFiel
JS_FRIEND_API(void) triggerOperationCallback();
void setJitHardening(bool enabled);
bool getJitHardening() const {
return jitHardening;
}
void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary,
- size_t *regexpCode, size_t *stackCommitted);
+ size_t *regexpCode, size_t *stackCommitted, size_t *gcMarker);
void purge(JSContext *cx);
};
/* Common macros to access thread-local caches in JSRuntime. */
#define JS_PROPERTY_CACHE(cx) (cx->runtime->propertyCache)
#define JS_KEEP_ATOMS(rt) (rt)->gcKeepAtoms++;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2113,16 +2113,23 @@ GCMarker::appendGrayRoot(void *thing, JS
void
GCMarker::GrayCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind)
{
GCMarker *gcmarker = static_cast<GCMarker *>(trc);
gcmarker->appendGrayRoot(*thingp, kind);
}
+size_t
+GCMarker::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const
+{
+ return stack.sizeOfExcludingThis(mallocSizeOf) +
+ grayRoots.sizeOfExcludingThis(mallocSizeOf);
+}
+
void
SetMarkStackLimit(JSRuntime *rt, size_t limit)
{
JS_ASSERT(!rt->gcRunning);
rt->gcMarker.setSizeLimit(limit);
for (CompartmentsIter c(rt); !c.done(); c.next())
c->barrierMarker_.setSizeLimit(limit);
}
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1685,16 +1685,24 @@ struct MarkStack {
if (!newStack)
return false;
}
stack = newStack;
tos = stack + tosIndex;
limit = newStack + newcap;
return true;
}
+
+ size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const {
+ size_t n = 0;
+ if (stack != ballast)
+ n += mallocSizeOf(stack);
+ n += mallocSizeOf(ballast);
+ return n;
+ }
};
/*
* This class records how much work has been done in a given GC slice, so that
* we can return before pausing for too long. Some slices are allowed to run for
* unlimited time, and others are bounded. To reduce the number of gettimeofday
* calls, we only check the time every 1000 operations.
*/
@@ -1822,16 +1830,18 @@ struct GCMarker : public JSTracer {
*/
bool hasBufferedGrayRoots() const;
void startBufferingGrayRoots();
void endBufferingGrayRoots();
void markBufferedGrayRoots();
static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind);
+ size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const;
+
MarkStack<uintptr_t> stack;
private:
#ifdef DEBUG
void checkCompartment(void *p);
#else
void checkCompartment(void *p) {}
#endif
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1680,16 +1680,21 @@ ReportJSRuntimeExplicitTreeStats(const J
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/stack-committed"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeStackCommitted,
"Memory used for the JS call stack. This is the committed portion "
"of the stack; the uncommitted portion is not measured because it "
"hardly costs anything.",
callback, closure);
+ ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/gc-marker"),
+ nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeGCMarker,
+ "Memory used for the GC mark stack and gray roots.",
+ callback, closure);
+
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
&gcTotal, rtStats.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 'explicit/js/gc-heap-decommitted'.",
callback, closure);