Commit 778a486d authored by Paul Bone's avatar Paul Bone
Browse files

Bug 1392511 - Report the correct information for used bytes. r=jonco

Only use the promotion rate to make pre tenuring and nursery size decisions
(now that it is calculated correctly and not under-estimated) if the nursery
is at least 90% full.
parent a1f7ac50
Loading
Loading
Loading
Loading
+47 −23
Original line number Diff line number Diff line
@@ -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
{
@@ -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);

@@ -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
@@ -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) {
@@ -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
@@ -685,7 +703,7 @@ js::Nursery::collect(JS::gcreason::Reason reason)
    }
}

double
void
js::Nursery::doCollection(JS::gcreason::Reason reason,
                          TenureCountCache& tenureCounts)
{
@@ -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);
@@ -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
@@ -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;
@@ -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)
+15 −5
Original line number Diff line number Diff line
@@ -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_;
@@ -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
@@ -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);

    /*
@@ -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();