Measure type inference memory usage, bug 669958. r=njn

This commit is contained in:
Brian Hackett 2011-07-07 20:04:47 -07:00
parent 8853bbc4cc
commit 752b11eaa2
5 changed files with 147 additions and 0 deletions

View File

@ -286,6 +286,18 @@ ArenaNew(JSArenaPool &pool, const A &a, const B &b, const C &c, const D &d, cons
return v ? new (v) T(a, b, c, d, e) : NULL;
}
inline uintN
ArenaAllocatedSize(const JSArenaPool &pool)
{
uintN res = 0;
const JSArena *a = &pool.first;
while (a) {
res += (a->limit - (jsuword)a);
a = a->next;
}
return res;
}
} /* namespace js */
#endif /* __cplusplus */

View File

@ -394,6 +394,18 @@ struct JS_FRIEND_API(JSCompartment) {
bool condenseTypes(JSContext *cx);
/* Data for tracking analysis/inference memory usage. */
struct TypeInferenceMemoryStats
{
int64 scriptMain;
int64 scriptSets;
int64 objectMain;
int64 objectSets;
int64 poolMain;
};
void getTypeInferenceMemoryStats(TypeInferenceMemoryStats *stats);
#ifdef JS_TRACER
private:
/*

View File

@ -516,6 +516,8 @@ public:
}
TypeObject * persistentObject() { return object; }
size_t allocatedSize() { return sizeof(TypeConstraintBaseSubset); }
};
void
@ -556,6 +558,8 @@ public:
void newObjectState(JSContext *cx, TypeObject*, bool) { checkAnalysis(cx); }
bool condensed() { return true; }
size_t allocatedSize() { return sizeof(TypeConstraintCondensed); }
};
bool
@ -4288,6 +4292,8 @@ class TypeIntermediateClearDefinite : public TypeIntermediate
{
return object->marked;
}
size_t allocatedSize() { return sizeof(TypeIntermediateClearDefinite); }
};
static bool
@ -4829,6 +4835,8 @@ class TypeIntermediatePushed : public TypeIntermediate
return false;
}
size_t allocatedSize() { return sizeof(TypeIntermediatePushed); }
};
void
@ -5634,3 +5642,76 @@ JSScript::sweepAnalysis(JSContext *cx)
analysis_ = NULL;
}
}
size_t
TypeSet::dynamicSize()
{
size_t res = 0;
if (objectCount >= 2)
res += HashSetCapacity(objectCount) * sizeof(TypeObject *);
/* Get the total size of any heap-allocated constraints on this set. */
TypeConstraint *constraint = constraintList;
while (constraint) {
res += constraint->allocatedSize();
constraint = constraint->next;
}
return res;
}
static void
GetObjectListMemoryStats(TypeObject *object, JSCompartment::TypeInferenceMemoryStats *stats)
{
while (object) {
stats->objectMain += sizeof(TypeObject);
if (object->propertyCount >= 2)
stats->objectMain += HashSetCapacity(object->propertyCount) * sizeof(Property *);
unsigned count = object->getPropertyCount();
for (unsigned i = 0; i < count; i++) {
Property *prop = object->getProperty(i);
if (prop) {
stats->objectMain += sizeof(Property);
stats->objectSets += prop->types.dynamicSize();
}
}
object = object->next;
}
}
static void
GetScriptMemoryStats(JSScript *script, JSCompartment::TypeInferenceMemoryStats *stats)
{
GetObjectListMemoryStats(script->types.typeObjects, stats);
if (!script->types.typeArray)
return;
unsigned count = script->types.numTypeSets();
stats->scriptMain += count * sizeof(TypeSet);
for (unsigned i = 0; i < count; i++)
stats->scriptSets += script->types.typeArray[i].dynamicSize();
TypeIntermediate *intermediate = script->types.intermediateList;
while (intermediate) {
stats->scriptMain += intermediate->allocatedSize();
intermediate = intermediate->next;
}
}
void
JSCompartment::getTypeInferenceMemoryStats(TypeInferenceMemoryStats *stats)
{
GetObjectListMemoryStats(types.objects, stats);
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
JSScript *script = reinterpret_cast<JSScript *>(cursor);
GetScriptMemoryStats(script, stats);
}
stats->poolMain += ArenaAllocatedSize(pool);
}

View File

@ -209,6 +209,8 @@ public:
* of any script.
*/
virtual TypeObject * persistentObject() { return NULL; }
virtual size_t allocatedSize() { return 0; }
};
/* Coarse flags for the contents of a type set. */
@ -313,6 +315,7 @@ class TypeSet
void print(JSContext *cx);
inline void destroy(JSContext *cx);
size_t dynamicSize();
/* Whether this set contains a specific type. */
inline bool hasType(jstype type);
@ -487,6 +490,8 @@ class TypeIntermediate
/* Whether this subsumes a dynamic type pushed by the bytecode at offset. */
virtual bool hasDynamicResult(uint32 offset, jstype type) { return false; }
virtual size_t allocatedSize() = 0;
};
/*

View File

@ -1348,6 +1348,7 @@ private:
PRInt64 tjitDataAllocatorsMain;
PRInt64 tjitDataAllocatorsReserve;
#endif
JSCompartment::TypeInferenceMemoryStats typeInferenceMemory;
};
struct IterateData
@ -1428,6 +1429,13 @@ private:
: 0;
}
static void
GetCompartmentTypeInferenceMemorySize(JSCompartment *c,
JSCompartment::TypeInferenceMemoryStats *stats)
{
c->getTypeInferenceMemoryStats(stats);
}
#endif // JS_TRACER
static void
@ -1451,6 +1459,7 @@ private:
curr->tjitDataAllocatorsMain = GetCompartmentTjitDataAllocatorsMainSize(compartment);
curr->tjitDataAllocatorsReserve = GetCompartmentTjitDataAllocatorsReserveSize(compartment);
#endif
GetCompartmentTypeInferenceMemorySize(compartment, &curr->typeInferenceMemory);
}
static void
@ -1638,6 +1647,34 @@ public:
"Memory used by the trace JIT and held in reserve for VMAllocators "
"in case of OOM.");
#endif
DO(mkPath(name, "type-inference/script-main"),
nsIMemoryReporter::KIND_HEAP, stats->typeInferenceMemory.scriptMain,
"Memory used during type inference to store type sets of variables "
"and dynamically observed types.");
DO(mkPath(name, "type-inference/script-typesets"),
nsIMemoryReporter::KIND_HEAP, stats->typeInferenceMemory.scriptSets,
"Memory used during type inference to hold the contents of type "
"sets associated with scripts.");
DO(mkPath(name, "type-inference/object-main"),
nsIMemoryReporter::KIND_HEAP, stats->typeInferenceMemory.objectMain,
"Memory used during type inference to store types and possible "
"property types of JS objects.");
DO(mkPath(name, "type-inference/object-typesets"),
nsIMemoryReporter::KIND_HEAP, stats->typeInferenceMemory.objectSets,
"Memory used during type inference to hold the contents of type "
"sets associated with objects.");
/*
* This is in a different category from the rest of type inference
* data as this can be large but is volatile and cleared on GC.
*/
DO(mkPath(name, "type-inference-pools"),
nsIMemoryReporter::KIND_HEAP, stats->typeInferenceMemory.poolMain,
"Memory used during type inference to hold transient analysis information.");
}
JS_ASSERT(gcHeapChunkTotal % js::GC_CHUNK_SIZE == 0);