Loading js/src/gc/Nursery.cpp +47 −23 Original line number Diff line number Diff line Loading @@ -465,6 +465,22 @@ js::TenuringTracer::TenuringTracer(JSRuntime* rt, Nursery* nursery) { } inline float js::Nursery::calcPromotionRate(bool *validForTenuring) const { float used = float(previousGC.nurseryUsedBytes); float capacity = float(previousGC.nurseryCapacity); float tenured = float(previousGC.tenuredBytes); if (validForTenuring) { /* * We can only use promotion rates if they're likely to be valid, * they're only valid if the nursury was at least 90% full. */ *validForTenuring = used > capacity * 0.9f; } return tenured / used; } void js::Nursery::renderProfileJSON(JSONPrinter& json) const { Loading @@ -490,8 +506,7 @@ js::Nursery::renderProfileJSON(JSONPrinter& json) const json.property("reason", JS::gcreason::ExplainReason(previousGC.reason)); json.property("bytes_tenured", previousGC.tenuredBytes); json.floatProperty("promotion_rate", 100.0 * previousGC.tenuredBytes / double(previousGC.nurseryUsedBytes), 2); json.floatProperty("promotion_rate", calcPromotionRate(nullptr), 0); json.property("nursery_bytes", previousGC.nurseryUsedBytes); json.property("new_nursery_bytes", numChunks() * ChunkSize); Loading Loading @@ -609,14 +624,13 @@ js::Nursery::collect(JS::gcreason::Reason reason) JS::AutoSuppressGCAnalysis nogc; TenureCountCache tenureCounts; double promotionRate = 0; previousGC.reason = JS::gcreason::NO_REASON; if (!isEmpty()) promotionRate = doCollection(reason, tenureCounts); doCollection(reason, tenureCounts); // Resize the nursery. startProfile(ProfileKey::Resize); maybeResizeNursery(reason, promotionRate); maybeResizeNursery(reason); endProfile(ProfileKey::Resize); // If we are promoting the nursery, or exhausted the store buffer with Loading @@ -624,7 +638,10 @@ js::Nursery::collect(JS::gcreason::Reason reason) // the nursery is full, look for object groups that are getting promoted // excessively and try to pretenure them. startProfile(ProfileKey::Pretenure); bool validPromotionRate; const float promotionRate = calcPromotionRate(&validPromotionRate); uint32_t pretenureCount = 0; if (validPromotionRate) { if (promotionRate > 0.8 || IsFullStoreBufferReason(reason)) { JSContext* cx = TlsContext.get(); for (auto& entry : tenureCounts.entries) { Loading @@ -638,6 +655,7 @@ js::Nursery::collect(JS::gcreason::Reason reason) } } } } endProfile(ProfileKey::Pretenure); // We ignore gcMaxBytes when allocating for minor collection. However, if we Loading Loading @@ -685,7 +703,7 @@ js::Nursery::collect(JS::gcreason::Reason reason) } } double void js::Nursery::doCollection(JS::gcreason::Reason reason, TenureCountCache& tenureCounts) { Loading @@ -696,7 +714,8 @@ js::Nursery::doCollection(JS::gcreason::Reason reason, AutoDisableProxyCheck disableStrictProxyChecking; mozilla::DebugOnly<AutoEnterOOMUnsafeRegion> oomUnsafeRegion; size_t initialNurserySize = spaceToEnd(); const size_t initialNurseryCapacity = spaceToEnd(); const size_t initialNurseryUsedBytes = initialNurseryCapacity - freeSpace(); // Move objects pointed to by roots from the nursery to the major heap. TenuringTracer mover(rt, this); Loading Loading @@ -793,11 +812,9 @@ js::Nursery::doCollection(JS::gcreason::Reason reason, endProfile(ProfileKey::CheckHashTables); previousGC.reason = reason; previousGC.nurseryUsedBytes = initialNurserySize; previousGC.nurseryCapacity = initialNurseryCapacity; previousGC.nurseryUsedBytes = initialNurseryUsedBytes; previousGC.tenuredBytes = mover.tenuredSize; // Calculate and return the promotion rate. return mover.tenuredSize / double(initialNurserySize); } void Loading Loading @@ -923,7 +940,7 @@ js::Nursery::setStartPosition() } void js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason, double promotionRate) js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason) { static const double GrowThreshold = 0.05; static const double ShrinkThreshold = 0.01; Loading @@ -942,20 +959,27 @@ js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason, double promotionRat return; #endif bool canUsePromotionRate; const float promotionRate = calcPromotionRate(&canUsePromotionRate); newMaxNurseryChunks = runtime()->gc.tunables.gcMaxNurseryBytes() >> ChunkShift; if (newMaxNurseryChunks != maxNurseryChunks_) { maxNurseryChunks_ = newMaxNurseryChunks; /* The configured maximum nursery size is changing */ int extraChunks = numChunks() - newMaxNurseryChunks; const int extraChunks = numChunks() - newMaxNurseryChunks; if (extraChunks > 0) { /* We need to shrink the nursery */ shrinkAllocableSpace(extraChunks); if (canUsePromotionRate) previousPromotionRate_ = promotionRate; return; } } if (!canUsePromotionRate) return; if (promotionRate > GrowThreshold) growAllocableSpace(); else if (promotionRate < ShrinkThreshold && previousPromotionRate_ < ShrinkThreshold) Loading js/src/gc/Nursery.h +15 −5 Original line number Diff line number Diff line Loading @@ -316,7 +316,7 @@ class Nursery unsigned maxNurseryChunks_; /* Promotion rate for the previous minor collection. */ double previousPromotionRate_; float previousPromotionRate_; /* Report minor collections taking at least this long, if enabled. */ mozilla::TimeDuration profileThreshold_; Loading Loading @@ -355,10 +355,20 @@ class Nursery struct { JS::gcreason::Reason reason; uint64_t nurseryUsedBytes; uint64_t tenuredBytes; size_t nurseryCapacity; size_t nurseryUsedBytes; size_t tenuredBytes; } previousGC; /* * Calculate the promotion rate of the most recent minor GC. * The valid_for_tenuring parameter is used to return whether this * promotion rate is accurate enough (the nursery was full enough) to be * used for tenuring and other decisions. */ float calcPromotionRate(bool *validForTenuring) const; /* * The set of externally malloced buffers potentially kept live by objects * stored in the nursery. Any external buffers that do not belong to a Loading Loading @@ -438,7 +448,7 @@ class Nursery /* Common internal allocator function. */ void* allocate(size_t size); double doCollection(JS::gcreason::Reason reason, void doCollection(JS::gcreason::Reason reason, gc::TenureCountCache& tenureCounts); /* Loading Loading @@ -466,7 +476,7 @@ class Nursery void sweepDictionaryModeObjects(); /* Change the allocable space provided by the nursery. */ void maybeResizeNursery(JS::gcreason::Reason reason, double promotionRate); void maybeResizeNursery(JS::gcreason::Reason reason); void growAllocableSpace(); void shrinkAllocableSpace(unsigned removeNumChunks); void minimizeAllocableSpace(); Loading Loading
js/src/gc/Nursery.cpp +47 −23 Original line number Diff line number Diff line Loading @@ -465,6 +465,22 @@ js::TenuringTracer::TenuringTracer(JSRuntime* rt, Nursery* nursery) { } inline float js::Nursery::calcPromotionRate(bool *validForTenuring) const { float used = float(previousGC.nurseryUsedBytes); float capacity = float(previousGC.nurseryCapacity); float tenured = float(previousGC.tenuredBytes); if (validForTenuring) { /* * We can only use promotion rates if they're likely to be valid, * they're only valid if the nursury was at least 90% full. */ *validForTenuring = used > capacity * 0.9f; } return tenured / used; } void js::Nursery::renderProfileJSON(JSONPrinter& json) const { Loading @@ -490,8 +506,7 @@ js::Nursery::renderProfileJSON(JSONPrinter& json) const json.property("reason", JS::gcreason::ExplainReason(previousGC.reason)); json.property("bytes_tenured", previousGC.tenuredBytes); json.floatProperty("promotion_rate", 100.0 * previousGC.tenuredBytes / double(previousGC.nurseryUsedBytes), 2); json.floatProperty("promotion_rate", calcPromotionRate(nullptr), 0); json.property("nursery_bytes", previousGC.nurseryUsedBytes); json.property("new_nursery_bytes", numChunks() * ChunkSize); Loading Loading @@ -609,14 +624,13 @@ js::Nursery::collect(JS::gcreason::Reason reason) JS::AutoSuppressGCAnalysis nogc; TenureCountCache tenureCounts; double promotionRate = 0; previousGC.reason = JS::gcreason::NO_REASON; if (!isEmpty()) promotionRate = doCollection(reason, tenureCounts); doCollection(reason, tenureCounts); // Resize the nursery. startProfile(ProfileKey::Resize); maybeResizeNursery(reason, promotionRate); maybeResizeNursery(reason); endProfile(ProfileKey::Resize); // If we are promoting the nursery, or exhausted the store buffer with Loading @@ -624,7 +638,10 @@ js::Nursery::collect(JS::gcreason::Reason reason) // the nursery is full, look for object groups that are getting promoted // excessively and try to pretenure them. startProfile(ProfileKey::Pretenure); bool validPromotionRate; const float promotionRate = calcPromotionRate(&validPromotionRate); uint32_t pretenureCount = 0; if (validPromotionRate) { if (promotionRate > 0.8 || IsFullStoreBufferReason(reason)) { JSContext* cx = TlsContext.get(); for (auto& entry : tenureCounts.entries) { Loading @@ -638,6 +655,7 @@ js::Nursery::collect(JS::gcreason::Reason reason) } } } } endProfile(ProfileKey::Pretenure); // We ignore gcMaxBytes when allocating for minor collection. However, if we Loading Loading @@ -685,7 +703,7 @@ js::Nursery::collect(JS::gcreason::Reason reason) } } double void js::Nursery::doCollection(JS::gcreason::Reason reason, TenureCountCache& tenureCounts) { Loading @@ -696,7 +714,8 @@ js::Nursery::doCollection(JS::gcreason::Reason reason, AutoDisableProxyCheck disableStrictProxyChecking; mozilla::DebugOnly<AutoEnterOOMUnsafeRegion> oomUnsafeRegion; size_t initialNurserySize = spaceToEnd(); const size_t initialNurseryCapacity = spaceToEnd(); const size_t initialNurseryUsedBytes = initialNurseryCapacity - freeSpace(); // Move objects pointed to by roots from the nursery to the major heap. TenuringTracer mover(rt, this); Loading Loading @@ -793,11 +812,9 @@ js::Nursery::doCollection(JS::gcreason::Reason reason, endProfile(ProfileKey::CheckHashTables); previousGC.reason = reason; previousGC.nurseryUsedBytes = initialNurserySize; previousGC.nurseryCapacity = initialNurseryCapacity; previousGC.nurseryUsedBytes = initialNurseryUsedBytes; previousGC.tenuredBytes = mover.tenuredSize; // Calculate and return the promotion rate. return mover.tenuredSize / double(initialNurserySize); } void Loading Loading @@ -923,7 +940,7 @@ js::Nursery::setStartPosition() } void js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason, double promotionRate) js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason) { static const double GrowThreshold = 0.05; static const double ShrinkThreshold = 0.01; Loading @@ -942,20 +959,27 @@ js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason, double promotionRat return; #endif bool canUsePromotionRate; const float promotionRate = calcPromotionRate(&canUsePromotionRate); newMaxNurseryChunks = runtime()->gc.tunables.gcMaxNurseryBytes() >> ChunkShift; if (newMaxNurseryChunks != maxNurseryChunks_) { maxNurseryChunks_ = newMaxNurseryChunks; /* The configured maximum nursery size is changing */ int extraChunks = numChunks() - newMaxNurseryChunks; const int extraChunks = numChunks() - newMaxNurseryChunks; if (extraChunks > 0) { /* We need to shrink the nursery */ shrinkAllocableSpace(extraChunks); if (canUsePromotionRate) previousPromotionRate_ = promotionRate; return; } } if (!canUsePromotionRate) return; if (promotionRate > GrowThreshold) growAllocableSpace(); else if (promotionRate < ShrinkThreshold && previousPromotionRate_ < ShrinkThreshold) Loading
js/src/gc/Nursery.h +15 −5 Original line number Diff line number Diff line Loading @@ -316,7 +316,7 @@ class Nursery unsigned maxNurseryChunks_; /* Promotion rate for the previous minor collection. */ double previousPromotionRate_; float previousPromotionRate_; /* Report minor collections taking at least this long, if enabled. */ mozilla::TimeDuration profileThreshold_; Loading Loading @@ -355,10 +355,20 @@ class Nursery struct { JS::gcreason::Reason reason; uint64_t nurseryUsedBytes; uint64_t tenuredBytes; size_t nurseryCapacity; size_t nurseryUsedBytes; size_t tenuredBytes; } previousGC; /* * Calculate the promotion rate of the most recent minor GC. * The valid_for_tenuring parameter is used to return whether this * promotion rate is accurate enough (the nursery was full enough) to be * used for tenuring and other decisions. */ float calcPromotionRate(bool *validForTenuring) const; /* * The set of externally malloced buffers potentially kept live by objects * stored in the nursery. Any external buffers that do not belong to a Loading Loading @@ -438,7 +448,7 @@ class Nursery /* Common internal allocator function. */ void* allocate(size_t size); double doCollection(JS::gcreason::Reason reason, void doCollection(JS::gcreason::Reason reason, gc::TenureCountCache& tenureCounts); /* Loading Loading @@ -466,7 +476,7 @@ class Nursery void sweepDictionaryModeObjects(); /* Change the allocable space provided by the nursery. */ void maybeResizeNursery(JS::gcreason::Reason reason, double promotionRate); void maybeResizeNursery(JS::gcreason::Reason reason); void growAllocableSpace(); void shrinkAllocableSpace(unsigned removeNumChunks); void minimizeAllocableSpace(); Loading