Bug 1522187 - Decide string pretenuring base on pretenure rate. r=jonco

Choose the string pretenuring threshold as 0.55, as it's the most common
pretured rate when the number of strings pretenured exceeds 30,000 in JetStream2
benchmark.  (about 0.55~0.57 in my tests).

However this threshold shouldn't have any major impact on benchmarks like Octane,
JetStream2 and Kraken, as in these benchmarks when the pretenuring condition is
met, the tenured rate is 99%.

Differential Revision: https://phabricator.services.mozilla.com/D92762
This commit is contained in:
Yoshi Cheng-Hao Huang 2020-10-15 10:02:21 +00:00
Родитель 76c3e94c96
Коммит 8c9a4c00bb
10 изменённых файлов: 60 добавлений и 5 удалений

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

@ -379,6 +379,12 @@ typedef enum JSGCParamKey {
*/
JSGC_HELPER_THREAD_COUNT = 41,
/**
* If the percentage of the tenured strings exceeds this threshold, string
* will be allocated in tenured heap instead. (Default is allocated in
* nursery.)
*/
JSGC_PRETENURE_STRING_THRESHOLD = 42,
} JSGCParamKey;
/*

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

@ -1527,6 +1527,8 @@ uint32_t GCRuntime::getParameter(JSGCParamKey key, const AutoLockGC& lock) {
return uint32_t(tunables.pretenureThreshold() * 100);
case JSGC_PRETENURE_GROUP_THRESHOLD:
return tunables.pretenureGroupThreshold();
case JSGC_PRETENURE_STRING_THRESHOLD:
return uint32_t(tunables.pretenureStringThreshold() * 100);
case JSGC_MIN_LAST_DITCH_GC_PERIOD:
return tunables.minLastDitchGCPeriod().ToSeconds();
case JSGC_ZONE_ALLOC_DELAY_KB:

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

@ -475,6 +475,14 @@ Cell* js::Nursery::allocateCell(Zone* zone, size_t size, JS::TraceKind kind) {
return cell;
}
Cell* js::Nursery::allocateString(JS::Zone* zone, size_t size) {
Cell* cell = allocateCell(zone, size, JS::TraceKind::String);
if (cell) {
zone->nurseryAllocatedStrings++;
}
return cell;
}
inline void* js::Nursery::allocate(size_t size) {
MOZ_ASSERT(isEnabled());
MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
@ -1274,8 +1282,18 @@ size_t js::Nursery::doPretenuring(JSRuntime* rt, JS::GCReason reason,
uint32_t numBigIntsTenured = 0;
uint32_t numNurseryBigIntRealmsDisabled = 0;
for (ZonesIter zone(gc, SkipAtoms); !zone.done(); zone.next()) {
bool disableNurseryStrings = pretenureStr && zone->allocNurseryStrings &&
zone->tenuredStrings >= 30 * 1000;
// For some tests in JetStream2 and Kranken, the tenuredRate is high but the
// number of allocated strings is low. So we calculate the tenuredRate only
// if the number of string allocations is enough.
bool allocThreshold = zone->nurseryAllocatedStrings > 30000;
double tenuredRate = allocThreshold
? double(zone->tenuredStrings) /
double(zone->nurseryAllocatedStrings)
: 0.0;
bool disableNurseryStrings =
pretenureStr && zone->allocNurseryStrings &&
tenuredRate > tunables().pretenureStringThreshold();
bool disableNurseryBigInts = pretenureBigInt && zone->allocNurseryBigInts &&
zone->tenuredBigInts >= 30 * 1000;
if (disableNurseryStrings || disableNurseryBigInts) {
@ -1310,6 +1328,7 @@ size_t js::Nursery::doPretenuring(JSRuntime* rt, JS::GCReason reason,
zone->tenuredStrings = 0;
numBigIntsTenured += zone->tenuredBigInts;
zone->tenuredBigInts = 0;
zone->nurseryAllocatedStrings = 0;
}
session.reset(); // End the minor GC session, if running one.
stats().setStat(gcstats::STAT_NURSERY_STRING_REALMS_DISABLED,

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

@ -246,9 +246,7 @@ class Nursery {
gc::Cell* allocateBigInt(JS::Zone* zone, size_t size) {
return allocateCell(zone, size, JS::TraceKind::BigInt);
}
gc::Cell* allocateString(JS::Zone* zone, size_t size) {
return allocateCell(zone, size, JS::TraceKind::String);
}
gc::Cell* allocateString(JS::Zone* zone, size_t size);
static size_t nurseryCellHeaderSize() {
return sizeof(gc::NurseryCellHeader);

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

@ -63,6 +63,7 @@ GCSchedulingTunables::GCSchedulingTunables()
TuningDefaults::NurseryFreeThresholdForIdleCollectionFraction),
pretenureThreshold_(TuningDefaults::PretenureThreshold),
pretenureGroupThreshold_(TuningDefaults::PretenureGroupThreshold),
pretenureStringThreshold_(TuningDefaults::PretenureStringThreshold),
minLastDitchGCPeriod_(
TimeDuration::FromSeconds(TuningDefaults::MinLastDitchGCPeriod)),
mallocThresholdBase_(TuningDefaults::MallocThresholdBase),
@ -192,6 +193,13 @@ bool GCSchedulingTunables::setParameter(JSGCParamKey key, uint32_t value,
}
pretenureGroupThreshold_ = value;
break;
case JSGC_PRETENURE_STRING_THRESHOLD:
// 100 disables pretenuring
if (value == 0 || value > 100) {
return false;
}
pretenureStringThreshold_ = value / 100.0;
break;
case JSGC_MIN_LAST_DITCH_GC_PERIOD:
minLastDitchGCPeriod_ = TimeDuration::FromSeconds(value);
break;
@ -333,6 +341,9 @@ void GCSchedulingTunables::resetParameter(JSGCParamKey key,
case JSGC_PRETENURE_GROUP_THRESHOLD:
pretenureGroupThreshold_ = TuningDefaults::PretenureGroupThreshold;
break;
case JSGC_PRETENURE_STRING_THRESHOLD:
pretenureStringThreshold_ = TuningDefaults::PretenureStringThreshold;
break;
case JSGC_MIN_LAST_DITCH_GC_PERIOD:
minLastDitchGCPeriod_ =
TimeDuration::FromSeconds(TuningDefaults::MinLastDitchGCPeriod);

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

@ -412,6 +412,9 @@ static const double PretenureThreshold = 0.6;
/* JSGC_PRETENURE_GROUP_THRESHOLD */
static const double PretenureGroupThreshold = 3000;
/* JSGC_PRETENURE_STRING_THRESHOLD */
static const double PretenureStringThreshold = 0.55;
/* JSGC_MIN_LAST_DITCH_GC_PERIOD */
static const auto MinLastDitchGCPeriod = 60; // in seconds
@ -549,6 +552,15 @@ class GCSchedulingTunables {
*/
UnprotectedData<uint32_t> pretenureGroupThreshold_;
/*
* JSGC_PRETENURE_STRING_THRESHOLD
*
* If the percentage of the tenured strings exceeds this threshold, string
* will be allocated in tenured heap instead. (Default is allocated in
* nursery.)
*/
MainThreadData<double> pretenureStringThreshold_;
/*
* JSGC_MIN_LAST_DITCH_GC_PERIOD
*
@ -611,6 +623,7 @@ class GCSchedulingTunables {
bool attemptPretenuring() const { return pretenureThreshold_ < 1.0; }
double pretenureThreshold() const { return pretenureThreshold_; }
uint32_t pretenureGroupThreshold() const { return pretenureGroupThreshold_; }
double pretenureStringThreshold() const { return pretenureStringThreshold_; }
mozilla::TimeDuration minLastDitchGCPeriod() const {
return minLastDitchGCPeriod_;

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

@ -150,6 +150,7 @@ JS::Zone::Zone(JSRuntime* rt)
data(this, nullptr),
tenuredStrings(this, 0),
tenuredBigInts(this, 0),
nurseryAllocatedStrings(this, 0),
allocNurseryStrings(this, true),
allocNurseryBigInts(this, true),
suppressAllocationMetadataBuilder(this, false),

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

@ -202,6 +202,8 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
js::ZoneData<uint32_t> tenuredStrings;
js::ZoneData<uint32_t> tenuredBigInts;
js::ZoneOrIonCompileData<uint64_t> nurseryAllocatedStrings;
js::ZoneData<bool> allocNurseryStrings;
js::ZoneData<bool> allocNurseryBigInts;

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

@ -90,6 +90,7 @@ class CompileRuntime {
};
class CompileZone {
friend class MacroAssembler;
JS::Zone* zone();
public:

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

@ -823,6 +823,8 @@ void MacroAssembler::nurseryAllocateString(Register result, Register temp,
// with the nursery's end will always fail in such cases.
CompileZone* zone = GetJitContext()->realm()->zone();
uint64_t* allocStrsPtr = &zone->zone()->nurseryAllocatedStrings.ref();
inc64(AbsoluteAddress(allocStrsPtr));
size_t thingSize = gc::Arena::thingSize(allocKind);
bumpPointerAllocate(result, temp, fail, zone,