зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1125412 - Expose an object for inspecting GC memory values, r=terrence
--HG-- extra : rebase_source : c98affaa7f01beb0757256cbe4d63bd78e297dac
This commit is contained in:
Родитель
218e7e26ba
Коммит
9c855788fb
|
@ -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 */
|
||||
|
|
213
js/src/jsgc.cpp
213
js/src/jsgc.cpp
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче