Bug 1580883 - Use TimeDuration for constants in nsJSEnvironment.cpp r=mccr8

Differential Revision: https://phabricator.services.mozilla.com/D45695

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jon Coppeard 2019-09-18 12:48:23 +00:00
Родитель 559e2c332d
Коммит 99e7fae124
1 изменённых файлов: 87 добавлений и 65 удалений

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

@ -106,34 +106,40 @@ const size_t gStackSize = 8192;
// The amount of time we wait between a request to CC (after GC ran) // The amount of time we wait between a request to CC (after GC ran)
// and doing the actual CC. // and doing the actual CC.
static const uint32_t kCCDelay = 6000; // ms static const TimeDuration kCCDelay = TimeDuration::FromSeconds(6);
static const int32_t kCCSkippableDelay = 250; // ms static const TimeDuration kCCSkippableDelay =
TimeDuration::FromMilliseconds(250);
// In case the cycle collector isn't run at all, we don't want // In case the cycle collector isn't run at all, we don't want forget skippables
// forget skippables to run too often. So limit the forget skippable cycle to // to run too often. So limit the forget skippable cycle to start at earliest 2
// start at earliest 2000 ms after the end of the previous cycle. // seconds after the end of the previous cycle.
static const uint32_t kTimeBetweenForgetSkippableCycles = 2000; // ms static const TimeDuration kTimeBetweenForgetSkippableCycles =
TimeDuration::FromSeconds(2);
// ForgetSkippable is usually fast, so we can use small budgets. // ForgetSkippable is usually fast, so we can use small budgets.
// This isn't a real budget but a hint to IdleTaskRunner whether there // This isn't a real budget but a hint to IdleTaskRunner whether there
// is enough time to call ForgetSkippable. // is enough time to call ForgetSkippable.
static const int64_t kForgetSkippableSliceDuration = 2; static const TimeDuration kForgetSkippableSliceDuration =
TimeDuration::FromMilliseconds(2);
// Maximum amount of time that should elapse between incremental CC slices // Maximum amount of time that should elapse between incremental CC slices
static const int64_t kICCIntersliceDelay = 64; // ms static const TimeDuration kICCIntersliceDelay =
TimeDuration::FromMilliseconds(64);
// Time budget for an incremental CC slice when using timer to run it. // Time budget for an incremental CC slice when using timer to run it.
static const int64_t kICCSliceBudget = 3; // ms static const TimeDuration kICCSliceBudget = TimeDuration::FromMilliseconds(3);
// Minimum budget for an incremental CC slice when using idle time to run it. // Minimum budget for an incremental CC slice when using idle time to run it.
static const int64_t kIdleICCSliceBudget = 2; // ms static const TimeDuration kIdleICCSliceBudget =
TimeDuration::FromMilliseconds(2);
// Maximum total duration for an ICC // Maximum total duration for an ICC
static const uint32_t kMaxICCDuration = 2000; // ms static const TimeDuration kMaxICCDuration = TimeDuration::FromSeconds(2);
// Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT // Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT
// objects in the purple buffer. // objects in the purple buffer.
static const uint32_t kCCForced = (2 * 60 * PR_USEC_PER_SEC); // 2 min static const TimeDuration kCCForced =
TimeDuration::FromSeconds(2 * 60); // 2 min
static const uint32_t kCCForcedPurpleLimit = 10; static const uint32_t kCCForcedPurpleLimit = 10;
// Don't allow an incremental GC to lock out the CC for too long. // Don't allow an incremental GC to lock out the CC for too long.
@ -1138,6 +1144,10 @@ static void FinishAnyIncrementalGC() {
} }
} }
static inline js::SliceBudget BudgetFromDuration(TimeDuration duration) {
return js::SliceBudget(js::TimeBudget(duration.ToMilliseconds()));
}
static void FireForgetSkippable(uint32_t aSuspected, bool aRemoveChildless, static void FireForgetSkippable(uint32_t aSuspected, bool aRemoveChildless,
TimeStamp aDeadline) { TimeStamp aDeadline) {
AUTO_PROFILER_TRACING( AUTO_PROFILER_TRACING(
@ -1177,11 +1187,10 @@ static void FireForgetSkippable(uint32_t aSuspected, bool aRemoveChildless,
FinishAnyIncrementalGC(); FinishAnyIncrementalGC();
bool earlyForgetSkippable = sCleanupsSinceLastGC < kMajorForgetSkippableCalls; bool earlyForgetSkippable = sCleanupsSinceLastGC < kMajorForgetSkippableCalls;
int64_t budgetMs = TimeDuration budgetTime = aDeadline ? (aDeadline - TimeStamp::Now())
aDeadline.IsNull() : kForgetSkippableSliceDuration;
? kForgetSkippableSliceDuration
: int64_t((aDeadline - TimeStamp::Now()).ToMilliseconds()); js::SliceBudget budget = BudgetFromDuration(budgetTime);
js::SliceBudget budget = js::SliceBudget(js::TimeBudget(budgetMs));
nsCycleCollector_forgetSkippable(budget, aRemoveChildless, nsCycleCollector_forgetSkippable(budget, aRemoveChildless,
earlyForgetSkippable); earlyForgetSkippable);
@ -1223,18 +1232,28 @@ static void FireForgetSkippable(uint32_t aSuspected, bool aRemoveChildless,
} }
MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE
static uint32_t TimeBetween(TimeStamp start, TimeStamp end) { static TimeDuration TimeBetween(TimeStamp start, TimeStamp end) {
MOZ_ASSERT(end >= start); MOZ_ASSERT(end >= start);
return (uint32_t)((end - start).ToMilliseconds()); return end - start;
} }
static uint32_t TimeUntilNow(TimeStamp start) { MOZ_ALWAYS_INLINE
static uint32_t TimeBetweenInMillis(TimeStamp start, TimeStamp end) {
return uint32_t(TimeBetween(start, end).ToMilliseconds());
}
static TimeDuration TimeUntilNow(TimeStamp start) {
if (start.IsNull()) { if (start.IsNull()) {
return 0; return TimeDuration();
} }
return TimeBetween(start, TimeStamp::Now()); return TimeBetween(start, TimeStamp::Now());
} }
MOZ_ALWAYS_INLINE
static uint32_t TimeUntilNowInMillis(TimeStamp start) {
return uint32_t(TimeUntilNow(start).ToMilliseconds());
}
struct CycleCollectorStats { struct CycleCollectorStats {
constexpr CycleCollectorStats() constexpr CycleCollectorStats()
: mMaxGCDuration(0), : mMaxGCDuration(0),
@ -1315,7 +1334,7 @@ struct CycleCollectorStats {
percent); percent);
} }
uint32_t sliceTime = TimeBetween(mBeginSliceTime, mEndSliceTime); uint32_t sliceTime = TimeBetweenInMillis(mBeginSliceTime, mEndSliceTime);
mMaxSliceTime = std::max(mMaxSliceTime, sliceTime); mMaxSliceTime = std::max(mMaxSliceTime, sliceTime);
mMaxSliceTimeSinceClear = std::max(mMaxSliceTimeSinceClear, sliceTime); mMaxSliceTimeSinceClear = std::max(mMaxSliceTimeSinceClear, sliceTime);
mTotalSliceTime += sliceTime; mTotalSliceTime += sliceTime;
@ -1376,7 +1395,7 @@ void CycleCollectorStats::PrepareForCycleCollectionSlice(TimeStamp aDeadline) {
if (sCCLockedOut) { if (sCCLockedOut) {
mAnyLockedOut = true; mAnyLockedOut = true;
FinishAnyIncrementalGC(); FinishAnyIncrementalGC();
uint32_t gcTime = TimeBetween(mBeginSliceTime, TimeStamp::Now()); uint32_t gcTime = TimeBetweenInMillis(mBeginSliceTime, TimeStamp::Now());
mMaxGCDuration = std::max(mMaxGCDuration, gcTime); mMaxGCDuration = std::max(mMaxGCDuration, gcTime);
} }
} }
@ -1392,8 +1411,8 @@ void CycleCollectorStats::RunForgetSkippable() {
} }
if (ranSyncForgetSkippable) { if (ranSyncForgetSkippable) {
mMaxSkippableDuration = mMaxSkippableDuration = std::max(
std::max(mMaxSkippableDuration, TimeUntilNow(beginForgetSkippable)); mMaxSkippableDuration, TimeUntilNowInMillis(beginForgetSkippable));
mRanSyncForgetSkippable = true; mRanSyncForgetSkippable = true;
} }
} }
@ -1429,44 +1448,44 @@ void nsJSContext::RunCycleCollectorSlice(TimeStamp aDeadline) {
js::SliceBudget budget = js::SliceBudget::unlimited(); js::SliceBudget budget = js::SliceBudget::unlimited();
if (sIncrementalCC) { if (sIncrementalCC) {
int64_t baseBudget = kICCSliceBudget; TimeDuration baseBudget = kICCSliceBudget;
if (!aDeadline.IsNull()) { if (!aDeadline.IsNull()) {
baseBudget = int64_t((aDeadline - TimeStamp::Now()).ToMilliseconds()); baseBudget = aDeadline - TimeStamp::Now();
} }
if (gCCStats.mBeginTime.IsNull()) { if (gCCStats.mBeginTime.IsNull()) {
// If no CC is in progress, use the standard slice time. // If no CC is in progress, use the standard slice time.
budget = js::SliceBudget(js::TimeBudget(baseBudget)); budget = BudgetFromDuration(baseBudget);
} else { } else {
TimeStamp now = TimeStamp::Now(); TimeStamp now = TimeStamp::Now();
// Only run a limited slice if we're within the max running time. // Only run a limited slice if we're within the max running time.
uint32_t runningTime = TimeBetween(gCCStats.mBeginTime, now); TimeDuration runningTime = TimeBetween(gCCStats.mBeginTime, now);
if (runningTime < kMaxICCDuration) { if (runningTime < kMaxICCDuration) {
const float maxSlice = MainThreadIdlePeriod::GetLongIdlePeriod(); const TimeDuration maxSlice = TimeDuration::FromMilliseconds(
MainThreadIdlePeriod::GetLongIdlePeriod());
// Try to make up for a delay in running this slice. // Try to make up for a delay in running this slice.
float sliceDelayMultiplier = TimeBetween(gCCStats.mEndSliceTime, now) / double sliceDelayMultiplier =
(float)kICCIntersliceDelay; TimeBetween(gCCStats.mEndSliceTime, now) / kICCIntersliceDelay;
float delaySliceBudget = TimeDuration delaySliceBudget =
std::min(baseBudget * sliceDelayMultiplier, maxSlice); std::min(baseBudget.MultDouble(sliceDelayMultiplier), maxSlice);
// Increase slice budgets up to |maxSlice| as we approach // Increase slice budgets up to |maxSlice| as we approach
// half way through the ICC, to avoid large sync CCs. // half way through the ICC, to avoid large sync CCs.
float percentToHalfDone = double percentToHalfDone =
std::min(2.0f * runningTime / kMaxICCDuration, 1.0f); std::min(2.0 * (runningTime / kMaxICCDuration), 1.0);
float laterSliceBudget = maxSlice * percentToHalfDone; TimeDuration laterSliceBudget = maxSlice.MultDouble(percentToHalfDone);
budget = js::SliceBudget(js::TimeBudget( budget = BudgetFromDuration(
std::max({delaySliceBudget, laterSliceBudget, (float)baseBudget}))); std::max({delaySliceBudget, laterSliceBudget, baseBudget}));
} }
} }
} }
nsCycleCollector_collectSlice( nsCycleCollector_collectSlice(
budget, budget,
aDeadline.IsNull() || aDeadline.IsNull() || (aDeadline - TimeStamp::Now()) < kICCSliceBudget);
(aDeadline - TimeStamp::Now()).ToMilliseconds() < kICCSliceBudget);
gCCStats.FinishCycleCollectionSlice(); gCCStats.FinishCycleCollectionSlice();
} }
@ -1543,8 +1562,9 @@ void nsJSContext::BeginCycleCollectionCallback() {
// finish it. // finish it.
sICCRunner = IdleTaskRunner::Create( sICCRunner = IdleTaskRunner::Create(
ICCRunnerFired, "BeginCycleCollectionCallback::ICCRunnerFired", ICCRunnerFired, "BeginCycleCollectionCallback::ICCRunnerFired",
kICCIntersliceDelay, kIdleICCSliceBudget, true, kICCIntersliceDelay.ToMilliseconds(),
[] { return sShuttingDown; }, TaskCategory::GarbageCollection); kIdleICCSliceBudget.ToMilliseconds(), true, [] { return sShuttingDown; },
TaskCategory::GarbageCollection);
} }
// static // static
@ -1562,15 +1582,16 @@ void nsJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) {
sCCollectedZonesWaitingForGC += aResults.mFreedJSZones; sCCollectedZonesWaitingForGC += aResults.mFreedJSZones;
TimeStamp endCCTimeStamp = TimeStamp::Now(); TimeStamp endCCTimeStamp = TimeStamp::Now();
uint32_t ccNowDuration = TimeBetween(gCCStats.mBeginTime, endCCTimeStamp); TimeDuration ccNowDuration = TimeBetween(gCCStats.mBeginTime, endCCTimeStamp);
if (NeedsGCAfterCC()) { if (NeedsGCAfterCC()) {
MOZ_ASSERT(StaticPrefs::javascript_options_gc_delay() > kMaxICCDuration, MOZ_ASSERT(StaticPrefs::javascript_options_gc_delay() >
kMaxICCDuration.ToMilliseconds(),
"A max duration ICC shouldn't reduce GC delay to 0"); "A max duration ICC shouldn't reduce GC delay to 0");
PokeGC(JS::GCReason::CC_WAITING, nullptr, PokeGC(JS::GCReason::CC_WAITING, nullptr,
StaticPrefs::javascript_options_gc_delay() - StaticPrefs::javascript_options_gc_delay() -
std::min(ccNowDuration, kMaxICCDuration)); std::min(ccNowDuration, kMaxICCDuration).ToMilliseconds());
} }
// Log information about the CC via telemetry, JSON and the console. // Log information about the CC via telemetry, JSON and the console.
@ -1578,15 +1599,15 @@ void nsJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) {
gCCStats.mAnyLockedOut); gCCStats.mAnyLockedOut);
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE, Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE,
gCCStats.mRanSyncForgetSkippable); gCCStats.mRanSyncForgetSkippable);
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL, ccNowDuration); Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL,
ccNowDuration.ToMilliseconds());
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_MAX_PAUSE, Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_MAX_PAUSE,
gCCStats.mMaxSliceTime); gCCStats.mMaxSliceTime);
if (!sLastCCEndTime.IsNull()) { if (!sLastCCEndTime.IsNull()) {
// TimeBetween returns milliseconds, but we want to report seconds. TimeDuration timeBetween = TimeBetween(sLastCCEndTime, gCCStats.mBeginTime);
uint32_t timeBetween = Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN,
TimeBetween(sLastCCEndTime, gCCStats.mBeginTime) / 1000; timeBetween.ToSeconds());
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN, timeBetween);
} }
sLastCCEndTime = endCCTimeStamp; sLastCCEndTime = endCCTimeStamp;
@ -1643,7 +1664,7 @@ void nsJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) {
if (StaticPrefs::javascript_options_mem_notify()) { if (StaticPrefs::javascript_options_mem_notify()) {
const char16_t* kJSONFmt = const char16_t* kJSONFmt =
u"{ \"timestamp\": %llu, " u"{ \"timestamp\": %llu, "
u"\"duration\": %lu, " u"\"duration\": %.f, "
u"\"max_slice_pause\": %lu, " u"\"max_slice_pause\": %lu, "
u"\"total_slice_pause\": %lu, " u"\"total_slice_pause\": %lu, "
u"\"max_finish_gc_duration\": %lu, " u"\"max_finish_gc_duration\": %lu, "
@ -1670,10 +1691,10 @@ void nsJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) {
nsString json; nsString json;
nsTextFormatter::ssprintf( nsTextFormatter::ssprintf(
json, kJSONFmt, PR_Now(), ccNowDuration, gCCStats.mMaxSliceTime, json, kJSONFmt, PR_Now(), ccNowDuration.ToMilliseconds(),
gCCStats.mTotalSliceTime, gCCStats.mMaxGCDuration, gCCStats.mMaxSliceTime, gCCStats.mTotalSliceTime,
gCCStats.mMaxSkippableDuration, gCCStats.mSuspected, gCCStats.mMaxGCDuration, gCCStats.mMaxSkippableDuration,
aResults.mVisitedRefCounted, aResults.mVisitedGCed, gCCStats.mSuspected, aResults.mVisitedRefCounted, aResults.mVisitedGCed,
aResults.mFreedRefCounted, aResults.mFreedGCed, sCCollectedWaitingForGC, aResults.mFreedRefCounted, aResults.mFreedGCed, sCCollectedWaitingForGC,
sCCollectedZonesWaitingForGC, sLikelyShortLivingObjectsNeedingGC, sCCollectedZonesWaitingForGC, sLikelyShortLivingObjectsNeedingGC,
aResults.mForcedGC, sForgetSkippableBeforeCC, aResults.mForcedGC, sForgetSkippableBeforeCC,
@ -1798,9 +1819,9 @@ static bool CCRunnerFired(TimeStamp aDeadline) {
return false; return false;
} }
static uint32_t ccDelay = kCCDelay; static TimeDuration ccDelay = kCCDelay;
if (sCCLockedOut) { if (sCCLockedOut) {
ccDelay = kCCDelay / 3; ccDelay = kCCDelay / int64_t(3);
TimeStamp now = TimeStamp::Now(); TimeStamp now = TimeStamp::Now();
if (!sCCLockedOutTime) { if (!sCCLockedOutTime) {
@ -1827,7 +1848,7 @@ static bool CCRunnerFired(TimeStamp aDeadline) {
// late timer fire, where we may begin to run the CC. Should run at least one // late timer fire, where we may begin to run the CC. Should run at least one
// early timer fire to allow cleanup before the CC. // early timer fire to allow cleanup before the CC.
int32_t numEarlyTimerFires = int32_t numEarlyTimerFires =
std::max((int32_t)ccDelay / kCCSkippableDelay - 2, 1); std::max(int32_t(ccDelay / kCCSkippableDelay) - 2, 1);
bool isLateTimerFire = sCCRunnerFireCount > numEarlyTimerFires; bool isLateTimerFire = sCCRunnerFireCount > numEarlyTimerFires;
uint32_t suspected = nsCycleCollector_suspectedCount(); uint32_t suspected = nsCycleCollector_suspectedCount();
if (isLateTimerFire && ShouldTriggerCC(suspected)) { if (isLateTimerFire && ShouldTriggerCC(suspected)) {
@ -2055,7 +2076,7 @@ void nsJSContext::MaybePokeCC() {
// Don't run consecutive CCs too often. // Don't run consecutive CCs too often.
if (sCleanupsSinceLastGC && !sLastCCEndTime.IsNull()) { if (sCleanupsSinceLastGC && !sLastCCEndTime.IsNull()) {
uint32_t sinceLastCCEnd = TimeUntilNow(sLastCCEndTime); TimeDuration sinceLastCCEnd = TimeUntilNow(sLastCCEndTime);
if (sinceLastCCEnd < kCCDelay) { if (sinceLastCCEnd < kCCDelay) {
return; return;
} }
@ -2065,7 +2086,7 @@ void nsJSContext::MaybePokeCC() {
// don't start a new cycle too soon. // don't start a new cycle too soon.
if ((sCleanupsSinceLastGC > kMajorForgetSkippableCalls) && if ((sCleanupsSinceLastGC > kMajorForgetSkippableCalls) &&
!sLastForgetSkippableCycleEndTime.IsNull()) { !sLastForgetSkippableCycleEndTime.IsNull()) {
uint32_t sinceLastForgetSkippableCycle = TimeDuration sinceLastForgetSkippableCycle =
TimeUntilNow(sLastForgetSkippableCycleEndTime); TimeUntilNow(sLastForgetSkippableCycleEndTime);
if (sinceLastForgetSkippableCycle < kTimeBetweenForgetSkippableCycles) { if (sinceLastForgetSkippableCycle < kTimeBetweenForgetSkippableCycles) {
return; return;
@ -2079,9 +2100,10 @@ void nsJSContext::MaybePokeCC() {
nsCycleCollector_dispatchDeferredDeletion(); nsCycleCollector_dispatchDeferredDeletion();
sCCRunner = IdleTaskRunner::Create( sCCRunner = IdleTaskRunner::Create(
CCRunnerFired, "MaybePokeCC::CCRunnerFired", kCCSkippableDelay, CCRunnerFired, "MaybePokeCC::CCRunnerFired",
kForgetSkippableSliceDuration, true, [] { return sShuttingDown; }, kCCSkippableDelay.ToMilliseconds(),
TaskCategory::GarbageCollection); kForgetSkippableSliceDuration.ToMilliseconds(), true,
[] { return sShuttingDown; }, TaskCategory::GarbageCollection);
} }
} }
@ -2240,7 +2262,7 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
} }
Telemetry::Accumulate(Telemetry::GC_IN_PROGRESS_MS, Telemetry::Accumulate(Telemetry::GC_IN_PROGRESS_MS,
TimeBetween(sCurrentGCStartTime, TimeStamp::Now())); TimeUntilNow(sCurrentGCStartTime).ToMilliseconds());
break; break;
} }