Bug 1125412 - Expose an object for inspecting GC memory values, r=terrence

--HG--
extra : rebase_source : c98affaa7f01beb0757256cbe4d63bd78e297dac
This commit is contained in:
Steve Fink 2015-01-26 15:32:54 -08:00
Родитель 218e7e26ba
Коммит 9c855788fb
8 изменённых файлов: 246 добавлений и 9 удалений

Просмотреть файл

@ -383,6 +383,14 @@ IsIncrementalBarrierNeededOnTenuredGCThing(JS::shadow::Runtime *rt, const JS::GC
return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier();
}
/*
* Create an object providing access to the garbage collector's internal notion
* of the current state of memory (both GC heap memory and GCthing-controlled
* malloc memory.
*/
extern JS_PUBLIC_API(JSObject *)
NewMemoryInfoObject(JSContext *cx);
} /* namespace gc */
} /* namespace js */

Просмотреть файл

@ -752,6 +752,7 @@ class GCRuntime
void removeBlackRootsTracer(JSTraceDataOp traceOp, void *data);
void setMaxMallocBytes(size_t value);
int32_t getMallocBytes() const { return mallocBytesUntilGC; }
void resetMallocBytes();
bool isTooMuchMalloc() const { return mallocBytesUntilGC <= 0; }
void updateMallocCounter(JS::Zone *zone, size_t nbytes);
@ -781,6 +782,12 @@ class GCRuntime
uint64_t gcNumber() { return number; }
void incGcNumber() { ++number; }
uint64_t minorGCCount() { return minorGCNumber; }
void incMinorGcNumber() { ++minorGCNumber; }
uint64_t majorGCCount() { return majorGCNumber; }
void incMajorGcNumber() { ++majorGCNumber; }
bool isIncrementalGc() { return isIncremental; }
bool isFullGc() { return isFull; }
@ -1062,6 +1069,9 @@ class GCRuntime
/* Perform full GC if rt->keepAtoms() becomes false. */
bool fullGCForAtomsRequested_;
/* Incremented at the start of every minor GC. */
uint64_t minorGCNumber;
/* Incremented at the start of every major GC. */
uint64_t majorGCNumber;

Просмотреть файл

@ -807,6 +807,8 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason, ObjectGroupList
return;
}
rt->gc.incMinorGcNumber();
rt->gc.stats.count(gcstats::STAT_MINOR_GC);
TraceMinorGCStart();

Просмотреть файл

@ -43,7 +43,7 @@ class ZoneHeapThreshold
double gcHeapGrowthFactor() const { return gcHeapGrowthFactor_; }
size_t gcTriggerBytes() const { return gcTriggerBytes_; }
bool isCloseToAllocTrigger(const js::gc::HeapUsage& usage, bool highFrequencyGC) const;
double allocTrigger(bool highFrequencyGC) const;
void updateAfterGC(size_t lastBytes, JSGCInvocationKind gckind,
const GCSchedulingTunables &tunables, const GCSchedulingState &state);

Просмотреть файл

@ -5257,7 +5257,6 @@ GetSavedFrameParent(JSContext *cx, HandleObject savedFrame, MutableHandleObject
extern JS_PUBLIC_API(bool)
StringifySavedFrameStack(JSContext *cx, HandleObject stack, MutableHandleString stringp);
} /* namespace JS */
#endif /* jsapi_h */

Просмотреть файл

@ -1068,6 +1068,7 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
majorGCTriggerReason(JS::gcreason::NO_REASON),
minorGCTriggerReason(JS::gcreason::NO_REASON),
fullGCForAtomsRequested_(false),
minorGCNumber(0),
majorGCNumber(0),
jitReleaseNumber(0),
number(0),
@ -1660,11 +1661,10 @@ GCRuntime::onTooMuchMalloc()
mallocGCTriggered = triggerGC(JS::gcreason::TOO_MUCH_MALLOC);
}
bool
ZoneHeapThreshold::isCloseToAllocTrigger(const js::gc::HeapUsage& usage, bool highFrequencyGC) const
double
ZoneHeapThreshold::allocTrigger(bool highFrequencyGC) const
{
double factor = highFrequencyGC ? 0.85 : 0.9;
return usage.gcBytes() >= factor * gcTriggerBytes();
return (highFrequencyGC ? 0.85 : 0.9) * gcTriggerBytes();
}
/* static */ double
@ -3071,7 +3071,7 @@ GCRuntime::maybeGC(Zone *zone)
return true;
if (zone->usage.gcBytes() > 1024 * 1024 &&
zone->threshold.isCloseToAllocTrigger(zone->usage, schedulingState.inHighFrequencyGCMode()) &&
zone->usage.gcBytes() >= zone->threshold.allocTrigger(schedulingState.inHighFrequencyGCMode()) &&
!isIncrementalGCInProgress() &&
!isBackgroundSweeping())
{
@ -5911,7 +5911,7 @@ GCRuntime::gcCycle(bool incremental, SliceBudget &budget, JS::gcreason::Reason r
number++;
if (!isIncrementalGCInProgress())
majorGCNumber++;
incMajorGcNumber();
// It's ok if threads other than the main thread have suppressGC set, as
// they are operating on zones which will not be collected from here.
@ -6013,7 +6013,7 @@ GCRuntime::scanZonesBeforeGC()
zone->scheduleGC();
/* This is a heuristic to reduce the total number of collections. */
if (zone->threshold.isCloseToAllocTrigger(zone->usage, schedulingState.inHighFrequencyGCMode()))
if (zone->usage.gcBytes() >= zone->threshold.allocTrigger(schedulingState.inHighFrequencyGCMode()))
zone->scheduleGC();
zoneStats.zoneCount++;
@ -7091,3 +7091,202 @@ JS::IsGenerationalGCEnabled(JSRuntime *rt)
{
return rt->gc.isGenerationalGCEnabled();
}
namespace js {
namespace gc {
namespace MemInfo {
static bool
GCBytesGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->runtime()->gc.usage.gcBytes()));
return true;
}
static bool
GCMaxBytesGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->runtime()->gc.tunables.gcMaxBytes()));
return true;
}
static bool
MallocBytesGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->runtime()->gc.getMallocBytes()));
return true;
}
static bool
MaxMallocGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->runtime()->gc.maxMallocBytesAllocated()));
return true;
}
static bool
GCHighFreqGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(cx->runtime()->gc.schedulingState.inHighFrequencyGCMode());
return true;
}
static bool
GCNumberGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->runtime()->gc.gcNumber()));
return true;
}
static bool
MajorGCCountGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->runtime()->gc.majorGCCount()));
return true;
}
static bool
MinorGCCountGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->runtime()->gc.minorGCCount()));
return true;
}
static bool
ZoneGCBytesGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->zone()->usage.gcBytes()));
return true;
}
static bool
ZoneGCTriggerBytesGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->zone()->threshold.gcTriggerBytes()));
return true;
}
static bool
ZoneGCAllocTriggerGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->zone()->threshold.allocTrigger(cx->runtime()->gc.schedulingState.inHighFrequencyGCMode())));
return true;
}
static bool
ZoneMallocBytesGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->zone()->gcMallocBytes));
return true;
}
static bool
ZoneMaxMallocGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->zone()->gcMaxMallocBytes));
return true;
}
static bool
ZoneGCDelayBytesGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->zone()->gcDelayBytes));
return true;
}
static bool
ZoneGCHeapGrowthFactorGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(cx->zone()->threshold.gcHeapGrowthFactor());
return true;
}
static bool
ZoneGCNumberGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(double(cx->zone()->gcNumber()));
return true;
}
} /* namespace MemInfo */
JSObject *
NewMemoryInfoObject(JSContext *cx)
{
RootedObject obj(cx, JS_NewObject(cx, nullptr));
using namespace MemInfo;
struct {
const char *name;
JSNative getter;
} getters[] = {
{ "gcBytes", GCBytesGetter },
{ "gcMaxBytes", GCMaxBytesGetter },
{ "mallocBytesRemaining", MallocBytesGetter },
{ "maxMalloc", MaxMallocGetter },
{ "gcIsHighFrequencyMode", GCHighFreqGetter },
{ "gcNumber", GCNumberGetter },
{ "majorGCCount", MajorGCCountGetter },
{ "minorGCCount", MinorGCCountGetter }
};
for (size_t i = 0; i < mozilla::ArrayLength(getters); i++) {
if (!JS_DefineProperty(cx, obj, getters[i].name, UndefinedHandleValue,
JSPROP_READONLY | JSPROP_SHARED | JSPROP_ENUMERATE,
getters[i].getter, nullptr))
{
return nullptr;
}
}
RootedObject zoneObj(cx, JS_NewObject(cx, nullptr));
if (!zoneObj)
return nullptr;
if (!JS_DefineProperty(cx, obj, "zone", zoneObj, JSPROP_ENUMERATE))
return nullptr;
struct {
const char *name;
JSNative getter;
} zoneGetters[] = {
{ "gcBytes", ZoneGCBytesGetter },
{ "gcTriggerBytes", ZoneGCTriggerBytesGetter },
{ "gcAllocTrigger", ZoneGCAllocTriggerGetter },
{ "mallocBytesRemaining", ZoneMallocBytesGetter },
{ "maxMalloc", ZoneMaxMallocGetter },
{ "delayBytes", ZoneGCDelayBytesGetter },
{ "heapGrowthFactor", ZoneGCHeapGrowthFactorGetter },
{ "gcNumber", ZoneGCNumberGetter }
};
for (size_t i = 0; i < mozilla::ArrayLength(zoneGetters); i++) {
if (!JS_DefineProperty(cx, zoneObj, zoneGetters[i].name, UndefinedHandleValue,
JSPROP_READONLY | JSPROP_SHARED | JSPROP_ENUMERATE,
zoneGetters[i].getter, nullptr))
{
return nullptr;
}
}
return obj;
}
} /* namespace gc */
} /* namespace js */

Просмотреть файл

@ -1395,6 +1395,9 @@ class ZoneList
ZoneList &operator=(const ZoneList &other) = delete;
};
JSObject *
NewMemoryStatisticsObject(JSContext *cx);
} /* namespace gc */
#ifdef DEBUG

Просмотреть файл

@ -5643,6 +5643,22 @@ NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options,
return nullptr;
}
RootedObject performanceObj(cx, JS_NewObject(cx, nullptr));
if (!performanceObj)
return nullptr;
RootedObject mozMemoryObj(cx, JS_NewObject(cx, nullptr));
if (!mozMemoryObj)
return nullptr;
RootedObject gcObj(cx, gc::NewMemoryInfoObject(cx));
if (!gcObj)
return nullptr;
if (!JS_DefineProperty(cx, glob, "performance", performanceObj, JSPROP_ENUMERATE))
return nullptr;
if (!JS_DefineProperty(cx, performanceObj, "mozMemory", mozMemoryObj, JSPROP_ENUMERATE))
return nullptr;
if (!JS_DefineProperty(cx, mozMemoryObj, "gc", gcObj, JSPROP_ENUMERATE))
return nullptr;
/* Initialize FakeDOMObject. */
static const js::DOMCallbacks DOMcallbacks = {
InstanceClassHasProtoAtDepth