Bug 676732 - Measure and/or avoid slop in important JS memory reporters. r=dmandelin.

This commit is contained in:
Nicholas Nethercote 2011-09-04 18:32:50 -07:00
parent 59e8ad1ced
commit 5164fb3ecf
11 changed files with 62 additions and 40 deletions

View File

@ -2717,6 +2717,15 @@ obj_preventExtensions(JSContext *cx, uintN argc, Value *vp)
return obj->preventExtensions(cx, &props);
}
size_t
JSObject::sizeOfSlotsArray(size_t(*mus)(void *))
{
if (!hasSlotsArray())
return 0;
size_t usable = mus((void *)slots);
return usable ? usable : numSlots() * sizeof(js::Value);
}
bool
JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
{

View File

@ -478,6 +478,8 @@ struct JSObject : js::gc::Cell {
jsuword initializedLength;
};
size_t sizeOfSlotsArray(size_t(*mus)(void *));
JSObject *parent; /* object's parent */
void *privateData; /* private data */
jsuword capacity; /* total number of available slots */

View File

@ -251,7 +251,12 @@ struct PropertyTable {
/* Computes the size of the entries array for a given capacity. */
static size_t sizeOfEntries(size_t cap) { return cap * sizeof(Shape *); }
size_t sizeOf() const {
size_t sizeOf(size_t(*mus)(void *)) const {
if (mus) {
size_t usable = mus((void*)this) + mus(entries);
if (usable)
return usable;
}
return sizeOfEntries(capacity()) + sizeof(PropertyTable);
}

View File

@ -674,8 +674,9 @@ struct JSScript : public js::gc::Cell {
return JITScript_Valid;
}
// This method is implemented in MethodJIT.h.
JS_FRIEND_API(size_t) jitDataSize();/* Size of the JITScript and all sections */
/* Size of the JITScript and all sections. (This method is implemented in MethodJIT.h.) */
JS_FRIEND_API(size_t) jitDataSize(size_t(*mus)(void *));
#endif
jsbytecode *main() {

View File

@ -183,9 +183,9 @@ using namespace js::tjit;
*
* FIXME: Bug 624590 is open to get rid of all this.
*/
static const size_t DataReserveSize = 12500 * sizeof(uintptr_t);
static const size_t TraceReserveSize = 5000 * sizeof(uintptr_t);
static const size_t TempReserveSize = 1000 * sizeof(uintptr_t);
static const size_t DataReserveSize = 8192 * sizeof(uintptr_t);
static const size_t TraceReserveSize = 512 * sizeof(uintptr_t);
static const size_t TempReserveSize = 4096 * sizeof(uintptr_t);
void*
nanojit::Allocator::allocChunk(size_t nbytes, bool fallible)

View File

@ -1328,7 +1328,8 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
#endif
JS_ASSERT(size_t(cursor - (uint8*)jit) == dataSize);
JS_ASSERT(jit->scriptDataSize() == dataSize);
/* Pass in NULL here -- we don't want slop bytes to be counted. */
JS_ASSERT(jit->scriptDataSize(NULL) == dataSize);
/* Link fast and slow paths together. */
stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size());

View File

@ -1137,21 +1137,23 @@ mjit::JITScript::~JITScript()
}
size_t
JSScript::jitDataSize()
JSScript::jitDataSize(size_t(*mus)(void *))
{
size_t n = 0;
if (jitNormal)
n += jitNormal->scriptDataSize();
n += jitNormal->scriptDataSize(mus);
if (jitCtor)
n += jitCtor->scriptDataSize();
n += jitCtor->scriptDataSize(mus);
return n;
}
/* Please keep in sync with Compiler::finishThisUp! */
size_t
mjit::JITScript::scriptDataSize()
mjit::JITScript::scriptDataSize(size_t(*mus)(void *))
{
return sizeof(JITScript) +
size_t usable = mus ? mus(this) : 0;
return usable ? usable :
sizeof(JITScript) +
sizeof(NativeMapEntry) * nNmapPairs +
sizeof(InlineFrame) * nInlineFrames +
sizeof(CallSite) * nCallSites +

View File

@ -640,7 +640,7 @@ struct JITScript {
void trace(JSTracer *trc);
size_t scriptDataSize();
size_t scriptDataSize(size_t(*mus)(void *));
jsbytecode *nativeToPC(void *returnAddress, CallSite **pinline) const;

View File

@ -4070,13 +4070,13 @@ MJitCodeStats(JSContext *cx, uintN argc, jsval *vp)
#ifdef JS_METHODJIT
static void
SumJitDataSizeCallabck(JSContext *cx, void *data, void *thing,
SumJitDataSizeCallback(JSContext *cx, void *data, void *thing,
JSGCTraceKind traceKind, size_t thingSize)
{
size_t *sump = static_cast<size_t *>(data);
JS_ASSERT(traceKind == JSTRACE_SCRIPT);
JSScript *script = static_cast<JSScript *>(thing);
*sump += script->jitDataSize();
*sump += script->jitDataSize(NULL);
}
#endif
@ -4086,7 +4086,7 @@ MJitDataStats(JSContext *cx, uintN argc, jsval *vp)
{
#ifdef JS_METHODJIT
size_t n = 0;
IterateCells(cx, NULL, gc::FINALIZE_TYPE_OBJECT, &n, SumJitDataSizeCallabck);
IterateCells(cx, NULL, gc::FINALIZE_TYPE_OBJECT, &n, SumJitDataSizeCallback);
JS_SET_RVAL(cx, vp, INT_TO_JSVAL(n));
#else
JS_SET_RVAL(cx, vp, JSVAL_VOID);

View File

@ -1346,7 +1346,7 @@ CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
case JSTRACE_OBJECT:
{
JSObject *obj = static_cast<JSObject *>(thing);
curr->objectSlots += JS_ObjectCountDynamicSlots(obj) * sizeof(js::Value);
curr->objectSlots += obj->sizeOfSlotsArray(moz_malloc_usable_size);
break;
}
case JSTRACE_STRING:
@ -1359,15 +1359,19 @@ CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
{
js::Shape *shape = static_cast<js::Shape *>(thing);
if(shape->hasTable())
curr->propertyTables += shape->getTable()->sizeOf();
curr->propertyTables +=
shape->getTable()->sizeOf(moz_malloc_usable_size);
break;
}
case JSTRACE_SCRIPT:
{
JSScript *script = static_cast<JSScript *>(thing);
curr->scriptData += script->dataSize();
if (script->data != script->inlineData) {
size_t usable = moz_malloc_usable_size(script->data);
curr->scriptData += usable ? usable : script->dataSize();
}
#ifdef JS_METHODJIT
curr->mjitData += script->jitDataSize();
curr->mjitData += script->jitDataSize(moz_malloc_usable_size);
#endif
break;
}
@ -1628,6 +1632,8 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
for(js::ThreadDataIter i(rt); !i.empty(); i.popFront())
data->stackSize += i.threadData()->stackSpace.committedSize();
size_t usable = moz_malloc_usable_size(rt);
data->runtimeObjectSize += usable ? usable : sizeof(JSRuntime);
data->atomsTableSize += rt->atomState.atoms.tableSize();
}
@ -1674,6 +1680,9 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
return true;
}
#define SLOP_BYTES_STRING \
" The measurement includes slop bytes caused by the heap allocator rounding up request sizes."
static void
ReportCompartmentStats(const CompartmentStats &stats,
const nsACString &pathPrefix,
@ -1736,7 +1745,7 @@ ReportCompartmentStats(const CompartmentStats &stats,
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/shapes"),
"gc-heap/type-objects"),
JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_TYPE_OBJECT],
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"type inference information.",
@ -1756,7 +1765,7 @@ ReportCompartmentStats(const CompartmentStats &stats,
"which are used to represent object properties. Some objects also "
"contain a fixed number of slots which are stored on the compartment's "
"JavaScript heap; those slots are not counted here, but in "
"'gc-heap/objects' instead.",
"'gc-heap/objects' instead." SLOP_BYTES_STRING,
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
@ -1774,7 +1783,7 @@ ReportCompartmentStats(const CompartmentStats &stats,
nsIMemoryReporter::KIND_HEAP, stats.propertyTables,
"Memory allocated for the compartment's property tables. A property "
"table is an internal data structure that makes JavaScript property "
"accesses fast.",
"accesses fast." SLOP_BYTES_STRING,
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
@ -1784,20 +1793,11 @@ ReportCompartmentStats(const CompartmentStats &stats,
"Arrays attached to prototype JS objects managing shape information.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"scripts"),
nsIMemoryReporter::KIND_HEAP,
stats.gcHeapKinds[JSTRACE_SCRIPT],
"Memory allocated for the compartment's JSScripts. 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,
"script-data"),
nsIMemoryReporter::KIND_HEAP, stats.scriptData,
"Memory allocated for JSScript bytecode and various variable-length "
"tables.",
"tables." SLOP_BYTES_STRING,
callback, closure);
#ifdef JS_METHODJIT
@ -1824,7 +1824,7 @@ ReportCompartmentStats(const CompartmentStats &stats,
"mjit-data"),
nsIMemoryReporter::KIND_HEAP, stats.mjitData,
"Memory used by the method JIT for the compartment's compilation data: "
"JITScripts, native maps, and inline cache structs.",
"JITScripts, native maps, and inline cache structs." SLOP_BYTES_STRING,
callback, closure);
#endif
#ifdef JS_TRACER
@ -1884,11 +1884,11 @@ ReportCompartmentStats(const CompartmentStats &stats,
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"type-inference-temporary"),
"analysis-temporary"),
nsIMemoryReporter::KIND_HEAP,
stats.typeInferenceMemory.temporary,
"Memory used during type inference to hold transient analysis "
"information. Cleared on GC.",
"Memory used during type inference and compilation to hold transient "
"analysis information. Cleared on GC.",
callback, closure);
}
@ -1906,8 +1906,8 @@ ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
}
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
nsIMemoryReporter::KIND_NONHEAP, sizeof(JSRuntime),
"Memory used by the JSRuntime object.",
nsIMemoryReporter::KIND_NONHEAP, data.runtimeObjectSize,
"Memory used by the JSRuntime object." SLOP_BYTES_STRING,
callback, closure);
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/atoms-table"),

View File

@ -227,7 +227,8 @@ struct CompartmentStats
struct IterateData
{
IterateData()
: atomsTableSize(0),
: runtimeObjectSize(0),
atomsTableSize(0),
stackSize(0),
gcHeapChunkTotal(0),
gcHeapChunkCleanUnused(0),
@ -238,6 +239,7 @@ struct IterateData
compartmentStatsVector(),
currCompartmentStats(NULL) { }
PRInt64 runtimeObjectSize;
PRInt64 atomsTableSize;
PRInt64 stackSize;
PRInt64 gcHeapChunkTotal;