Bug 1367900 - Record the values and thresholds for GC triggers, r=jonco

--HG--
extra : rebase_source : 324a41ddd6a0f577c5f44611e5fcdd092ef05d2d
extra : amend_source : 34470a4ff7d1591811bd6d8f757c71747fd86f99
This commit is contained in:
Steve Fink 2017-05-25 14:05:34 -07:00
Родитель a6d47c0012
Коммит d08266fbd1
5 изменённых файлов: 42 добавлений и 13 удалений

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

@ -688,7 +688,8 @@ class GCRuntime
MOZ_MUST_USE bool triggerGC(JS::gcreason::Reason reason);
void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
// The return value indicates if we were able to do the GC.
bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason);
bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason,
size_t usedBytes, size_t thresholdBytes);
void maybeGC(Zone* zone);
// The return value indicates whether a major GC was performed.
bool gcIfRequested();
@ -796,7 +797,10 @@ class GCRuntime
MOZ_MUST_USE bool addBlackRootsTracer(JSTraceDataOp traceOp, void* data);
void removeBlackRootsTracer(JSTraceDataOp traceOp, void* data);
bool triggerGCForTooMuchMalloc() { return triggerGC(JS::gcreason::TOO_MUCH_MALLOC); }
bool triggerGCForTooMuchMalloc() {
stats().recordTrigger(mallocCounter.bytes(), mallocCounter.maxBytes());
return triggerGC(JS::gcreason::TOO_MUCH_MALLOC);
}
int32_t getMallocBytes() const { return mallocCounter.bytes(); }
size_t maxMallocBytesAllocated() const { return mallocCounter.maxBytes(); }
bool isTooMuchMalloc() const { return mallocCounter.isTooMuchMalloc(); }

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

@ -617,6 +617,11 @@ Statistics::formatJsonSliceDescription(unsigned i, const SliceData& slice, JSONP
json.property("initial_state", gc::StateName(slice.initialState));
json.property("final_state", gc::StateName(slice.finalState));
json.property("budget", budgetDescription);
json.property("major_gc_number", startingMajorGCNumber);
if (thresholdTriggered) {
json.floatProperty("trigger_amount", triggerAmount, 0);
json.floatProperty("trigger_threshold", triggerThreshold, 0);
}
json.property("page_faults", int64_t(slice.endFaults - slice.startFaults));
json.property("start_timestamp", slice.start - originTime, JSONPrinter::SECONDS);
json.property("end_timestamp", slice.end - originTime, JSONPrinter::SECONDS);
@ -637,6 +642,9 @@ Statistics::Statistics(JSRuntime* rt)
fp(nullptr),
nonincrementalReason_(gc::AbortReason::None),
preBytes(0),
thresholdTriggered(false),
triggerAmount(0.0),
triggerThreshold(0.0),
maxPauseInInterval(0),
sliceCallback(nullptr),
nurseryCollectionCallback(nullptr),
@ -891,6 +899,7 @@ Statistics::endGC()
// Clear the OOM flag.
aborted = false;
thresholdTriggered = false;
}
void

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

@ -187,6 +187,12 @@ struct Statistics
return uint32_t(counts[s]);
}
void recordTrigger(double amount, double threshold) {
triggerAmount = amount;
triggerThreshold = threshold;
thresholdTriggered = true;
}
void beginNurseryCollection(JS::gcreason::Reason reason);
void endNurseryCollection(JS::gcreason::Reason reason);
@ -296,6 +302,12 @@ struct Statistics
/* Allocated space before the GC started. */
size_t preBytes;
/* If the GC was triggered by exceeding some threshold, record the
* threshold and the value that exceeded it. */
bool thresholdTriggered;
double triggerAmount;
double triggerThreshold;
/* GC numbers as of the beginning of the collection. */
uint64_t startingMinorGCNumber;
uint64_t startingMajorGCNumber;

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

@ -407,10 +407,11 @@ struct Zone : public JS::shadow::Zone,
bool triggerGCForTooMuchMalloc() {
JSRuntime* rt = runtimeFromAnyThread();
if (CurrentThreadCanAccessRuntime(rt))
return rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC);
else
return false;
if (CurrentThreadCanAccessRuntime(rt)) {
return rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC,
gcMallocCounter.bytes(), gcMallocCounter.maxBytes());
}
return false;
}
void resetGCMallocBytes() { gcMallocCounter.reset(); }

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

@ -3030,7 +3030,7 @@ GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock)
* The threshold has been surpassed, immediately trigger a GC,
* which will be done non-incrementally.
*/
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, thresholdBytes);
} else {
bool wouldInterruptCollection;
size_t igcThresholdBytes;
@ -3056,7 +3056,7 @@ GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock)
// to try to avoid performing non-incremental GCs on zones
// which allocate a lot of data, even when incremental slices
// can't be triggered via scheduling in the event loop.
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, igcThresholdBytes);
// Delay the next slice until a certain amount of allocation
// has been performed.
@ -3067,7 +3067,7 @@ GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock)
}
bool
GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason)
GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason, size_t used, size_t threshold)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
@ -3090,10 +3090,12 @@ GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason)
fullGCForAtomsRequested_ = true;
return false;
}
stats().recordTrigger(used, threshold);
MOZ_RELEASE_ASSERT(triggerGC(reason));
return true;
}
stats().recordTrigger(used, threshold);
PrepareZoneForGC(zone);
requestMajorGC(reason);
return true;
@ -3115,11 +3117,12 @@ GCRuntime::maybeGC(Zone* zone)
if (gcIfRequested())
return;
if (zone->usage.gcBytes() > 1024 * 1024 &&
zone->usage.gcBytes() >= zone->threshold.allocTrigger(schedulingState.inHighFrequencyGCMode()) &&
!isIncrementalGCInProgress() &&
!isBackgroundSweeping())
double threshold = zone->threshold.allocTrigger(schedulingState.inHighFrequencyGCMode());
double usedBytes = zone->usage.gcBytes();
if (usedBytes > 1024 * 1024 && usedBytes >= threshold &&
!isIncrementalGCInProgress() && !isBackgroundSweeping())
{
stats().recordTrigger(usedBytes, threshold);
PrepareZoneForGC(zone);
startGC(GC_NORMAL, JS::gcreason::EAGER_ALLOC_TRIGGER);
}