mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 771720 - Improve GC data collection (r=terrence)
This commit is contained in:
parent
560a0f014c
commit
76ac85af05
@ -276,20 +276,26 @@ static PhaseInfo phases[] = {
|
||||
{ PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread" },
|
||||
{ PHASE_PURGE, "Purge" },
|
||||
{ PHASE_MARK, "Mark" },
|
||||
{ PHASE_MARK_DISCARD_CODE, "Mark Discard Code" },
|
||||
{ PHASE_MARK_ROOTS, "Mark Roots" },
|
||||
{ PHASE_MARK_TYPES, "Mark Types" },
|
||||
{ PHASE_MARK_DELAYED, "Mark Delayed" },
|
||||
{ PHASE_MARK_OTHER, "Mark Other" },
|
||||
{ PHASE_MARK_WEAK, "Mark Weak" },
|
||||
{ PHASE_MARK_GRAY, "Mark Gray" },
|
||||
{ PHASE_MARK_GRAY_WEAK, "Mark Gray and Weak" },
|
||||
{ PHASE_FINALIZE_START, "Finalize Start Callback" },
|
||||
{ PHASE_SWEEP, "Sweep" },
|
||||
{ PHASE_SWEEP_ATOMS, "Sweep Atoms" },
|
||||
{ PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments" },
|
||||
{ PHASE_SWEEP_TABLES, "Sweep Tables" },
|
||||
{ PHASE_SWEEP_OBJECT, "Sweep Object" },
|
||||
{ PHASE_SWEEP_STRING, "Sweep String" },
|
||||
{ PHASE_SWEEP_SCRIPT, "Sweep Script" },
|
||||
{ PHASE_SWEEP_SHAPE, "Sweep Shape" },
|
||||
{ PHASE_DISCARD_CODE, "Discard Code" },
|
||||
{ PHASE_SWEEP_DISCARD_CODE, "Sweep Discard Code" },
|
||||
{ PHASE_DISCARD_ANALYSIS, "Discard Analysis" },
|
||||
{ PHASE_DISCARD_TI, "Discard TI" },
|
||||
{ PHASE_FREE_TI_ARENA, "Free TI Arena" },
|
||||
{ PHASE_SWEEP_TYPES, "Sweep Types" },
|
||||
{ PHASE_CLEAR_SCRIPT_ANALYSIS, "Clear Script Analysis" },
|
||||
{ PHASE_FINALIZE_END, "Finalize End Callback" },
|
||||
@ -307,15 +313,6 @@ FormatPhaseTimes(StatisticsSerializer &ss, const char *name, int64_t *times)
|
||||
ss.endObject();
|
||||
}
|
||||
|
||||
static void
|
||||
FormatPhaseFaults(StatisticsSerializer &ss, const char *name, size_t *faults)
|
||||
{
|
||||
ss.beginObject(name);
|
||||
for (unsigned i = 0; phases[i].name; i++)
|
||||
ss.appendNumber(phases[i].name, "%u", "", unsigned(faults[phases[i].index]));
|
||||
ss.endObject();
|
||||
}
|
||||
|
||||
bool
|
||||
Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
|
||||
{
|
||||
@ -367,12 +364,14 @@ Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
|
||||
ss.extra(" (");
|
||||
ss.appendDecimal("When", "ms", t(slices[i].start - slices[0].start));
|
||||
ss.appendString("Reason", ExplainReason(slices[i].reason));
|
||||
if (ss.isJSON()) {
|
||||
ss.appendDecimal("Page Faults", "",
|
||||
double(slices[i].endFaults - slices[i].startFaults));
|
||||
}
|
||||
if (slices[i].resetReason)
|
||||
ss.appendString("Reset", slices[i].resetReason);
|
||||
ss.extra("): ");
|
||||
FormatPhaseTimes(ss, "Times", slices[i].phaseTimes);
|
||||
if (ss.isJSON())
|
||||
FormatPhaseFaults(ss, "Page Faults", slices[i].phaseFaults);
|
||||
ss.endLine();
|
||||
ss.endObject();
|
||||
}
|
||||
@ -380,8 +379,6 @@ Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
|
||||
}
|
||||
ss.extra(" Totals: ");
|
||||
FormatPhaseTimes(ss, "Totals", phaseTimes);
|
||||
if (ss.isJSON())
|
||||
FormatPhaseFaults(ss, "Total Page Faults", phaseFaults);
|
||||
ss.endObject();
|
||||
|
||||
return !ss.isOOM();
|
||||
@ -484,9 +481,7 @@ void
|
||||
Statistics::beginGC()
|
||||
{
|
||||
PodArrayZero(phaseStartTimes);
|
||||
PodArrayZero(phaseStartFaults);
|
||||
PodArrayZero(phaseTimes);
|
||||
PodArrayZero(phaseFaults);
|
||||
|
||||
slices.clearAndFree();
|
||||
nonincrementalReason = NULL;
|
||||
@ -531,7 +526,7 @@ Statistics::beginSlice(int collectedCount, int compartmentCount, gcreason::Reaso
|
||||
if (first)
|
||||
beginGC();
|
||||
|
||||
SliceData data(reason, PRMJ_Now());
|
||||
SliceData data(reason, PRMJ_Now(), gc::GetPageFaultCount());
|
||||
(void) slices.append(data); /* Ignore any OOMs here. */
|
||||
|
||||
if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback)
|
||||
@ -549,6 +544,7 @@ void
|
||||
Statistics::endSlice()
|
||||
{
|
||||
slices.back().end = PRMJ_Now();
|
||||
slices.back().endFaults = gc::GetPageFaultCount();
|
||||
|
||||
if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
|
||||
(*cb)(JS_TELEMETRY_GC_SLICE_MS, t(slices.back().end - slices.back().start));
|
||||
@ -578,7 +574,6 @@ Statistics::beginPhase(Phase phase)
|
||||
JS_ASSERT(!phaseStartTimes[phase]);
|
||||
|
||||
phaseStartTimes[phase] = PRMJ_Now();
|
||||
phaseStartFaults[phase] = gc::GetPageFaultCount();
|
||||
|
||||
if (phase == gcstats::PHASE_MARK)
|
||||
Probes::GCStartMarkPhase();
|
||||
@ -594,10 +589,6 @@ Statistics::endPhase(Phase phase)
|
||||
phaseTimes[phase] += t;
|
||||
phaseStartTimes[phase] = 0;
|
||||
|
||||
size_t faults = gc::GetPageFaultCount() - phaseStartFaults[phase];
|
||||
slices.back().phaseFaults[phase] += faults;
|
||||
phaseFaults[phase] += faults;
|
||||
|
||||
if (phase == gcstats::PHASE_MARK)
|
||||
Probes::GCEndMarkPhase();
|
||||
else if (phase == gcstats::PHASE_SWEEP)
|
||||
|
@ -24,20 +24,26 @@ enum Phase {
|
||||
PHASE_WAIT_BACKGROUND_THREAD,
|
||||
PHASE_PURGE,
|
||||
PHASE_MARK,
|
||||
PHASE_MARK_DISCARD_CODE,
|
||||
PHASE_MARK_ROOTS,
|
||||
PHASE_MARK_TYPES,
|
||||
PHASE_MARK_DELAYED,
|
||||
PHASE_MARK_OTHER,
|
||||
PHASE_MARK_WEAK,
|
||||
PHASE_MARK_GRAY,
|
||||
PHASE_MARK_GRAY_WEAK,
|
||||
PHASE_FINALIZE_START,
|
||||
PHASE_SWEEP,
|
||||
PHASE_SWEEP_ATOMS,
|
||||
PHASE_SWEEP_COMPARTMENTS,
|
||||
PHASE_SWEEP_TABLES,
|
||||
PHASE_SWEEP_OBJECT,
|
||||
PHASE_SWEEP_STRING,
|
||||
PHASE_SWEEP_SCRIPT,
|
||||
PHASE_SWEEP_SHAPE,
|
||||
PHASE_DISCARD_CODE,
|
||||
PHASE_SWEEP_DISCARD_CODE,
|
||||
PHASE_DISCARD_ANALYSIS,
|
||||
PHASE_DISCARD_TI,
|
||||
PHASE_FREE_TI_ARENA,
|
||||
PHASE_SWEEP_TYPES,
|
||||
PHASE_CLEAR_SCRIPT_ANALYSIS,
|
||||
PHASE_FINALIZE_END,
|
||||
@ -96,18 +102,17 @@ struct Statistics {
|
||||
const char *nonincrementalReason;
|
||||
|
||||
struct SliceData {
|
||||
SliceData(gcreason::Reason reason, int64_t start)
|
||||
: reason(reason), resetReason(NULL), start(start)
|
||||
SliceData(gcreason::Reason reason, int64_t start, size_t startFaults)
|
||||
: reason(reason), resetReason(NULL), start(start), startFaults(startFaults)
|
||||
{
|
||||
PodArrayZero(phaseTimes);
|
||||
PodArrayZero(phaseFaults);
|
||||
}
|
||||
|
||||
gcreason::Reason reason;
|
||||
const char *resetReason;
|
||||
int64_t start, end;
|
||||
size_t startFaults, endFaults;
|
||||
int64_t phaseTimes[PHASE_LIMIT];
|
||||
size_t phaseFaults[PHASE_LIMIT];
|
||||
|
||||
int64_t duration() const { return end - start; }
|
||||
};
|
||||
@ -116,11 +121,9 @@ struct Statistics {
|
||||
|
||||
/* Most recent time when the given phase started. */
|
||||
int64_t phaseStartTimes[PHASE_LIMIT];
|
||||
size_t phaseStartFaults[PHASE_LIMIT];
|
||||
|
||||
/* Total time in a given phase for this GC. */
|
||||
int64_t phaseTimes[PHASE_LIMIT];
|
||||
size_t phaseFaults[PHASE_LIMIT];
|
||||
|
||||
/* Total time in a given phase over all GCs. */
|
||||
int64_t phaseTotals[PHASE_LIMIT];
|
||||
|
@ -472,30 +472,35 @@ JSCompartment::discardJitCode(FreeOp *fop)
|
||||
void
|
||||
JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
|
||||
{
|
||||
sweepCrossCompartmentWrappers();
|
||||
|
||||
/* Remove dead references held weakly by the compartment. */
|
||||
|
||||
sweepBaseShapeTable();
|
||||
sweepInitialShapeTable();
|
||||
sweepNewTypeObjectTable(newTypeObjects);
|
||||
sweepNewTypeObjectTable(lazyTypeObjects);
|
||||
|
||||
if (emptyTypeObject && !IsTypeObjectMarked(emptyTypeObject.unsafeGet()))
|
||||
emptyTypeObject = NULL;
|
||||
|
||||
sweepBreakpoints(fop);
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE);
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_DISCARD_CODE);
|
||||
discardJitCode(fop);
|
||||
}
|
||||
|
||||
if (global_ && !IsObjectMarked(&global_))
|
||||
global_ = NULL;
|
||||
/* This function includes itself in PHASE_SWEEP_TABLES. */
|
||||
sweepCrossCompartmentWrappers();
|
||||
|
||||
/* JIT code can hold references on RegExpShared, so sweep regexps after clearing code. */
|
||||
regExps.sweep(rt);
|
||||
{
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_TABLES);
|
||||
|
||||
/* Remove dead references held weakly by the compartment. */
|
||||
|
||||
sweepBaseShapeTable();
|
||||
sweepInitialShapeTable();
|
||||
sweepNewTypeObjectTable(newTypeObjects);
|
||||
sweepNewTypeObjectTable(lazyTypeObjects);
|
||||
|
||||
if (emptyTypeObject && !IsTypeObjectMarked(emptyTypeObject.unsafeGet()))
|
||||
emptyTypeObject = NULL;
|
||||
|
||||
sweepBreakpoints(fop);
|
||||
|
||||
if (global_ && !IsObjectMarked(&global_))
|
||||
global_ = NULL;
|
||||
|
||||
/* JIT code can hold references on RegExpShared, so sweep regexps after clearing code. */
|
||||
regExps.sweep(rt);
|
||||
}
|
||||
|
||||
if (!activeAnalysis && !gcPreserveCode) {
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
|
||||
@ -548,6 +553,11 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
|
||||
script->clearAnalysis();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_FREE_TI_ARENA);
|
||||
oldAlloc.freeAll();
|
||||
}
|
||||
}
|
||||
|
||||
active = false;
|
||||
@ -561,6 +571,8 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
|
||||
void
|
||||
JSCompartment::sweepCrossCompartmentWrappers()
|
||||
{
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_TABLES);
|
||||
|
||||
/* Remove dead wrappers from the table. */
|
||||
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
|
||||
CrossCompartmentKey key = e.front().key;
|
||||
|
@ -3052,7 +3052,7 @@ BeginMarkPhase(JSRuntime *rt, bool isIncremental)
|
||||
/* For non-incremental GC the following sweep discards the jit code. */
|
||||
if (isIncremental) {
|
||||
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE);
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_DISCARD_CODE);
|
||||
c->discardJitCode(rt->defaultFreeOp());
|
||||
}
|
||||
}
|
||||
@ -3110,19 +3110,30 @@ MarkGrayAndWeak(JSRuntime *rt)
|
||||
{
|
||||
GCMarker *gcmarker = &rt->gcMarker;
|
||||
|
||||
JS_ASSERT(gcmarker->isDrained());
|
||||
MarkWeakReferences(gcmarker);
|
||||
|
||||
gcmarker->setMarkColorGray();
|
||||
if (gcmarker->hasBufferedGrayRoots()) {
|
||||
gcmarker->markBufferedGrayRoots();
|
||||
} else {
|
||||
if (JSTraceDataOp op = rt->gcGrayRootsTraceOp)
|
||||
(*op)(gcmarker, rt->gcGrayRootsData);
|
||||
{
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_WEAK);
|
||||
JS_ASSERT(gcmarker->isDrained());
|
||||
MarkWeakReferences(gcmarker);
|
||||
}
|
||||
SliceBudget budget;
|
||||
gcmarker->drainMarkStack(budget);
|
||||
MarkWeakReferences(gcmarker);
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_GRAY);
|
||||
gcmarker->setMarkColorGray();
|
||||
if (gcmarker->hasBufferedGrayRoots()) {
|
||||
gcmarker->markBufferedGrayRoots();
|
||||
} else {
|
||||
if (JSTraceDataOp op = rt->gcGrayRootsTraceOp)
|
||||
(*op)(gcmarker, rt->gcGrayRootsData);
|
||||
}
|
||||
SliceBudget budget;
|
||||
gcmarker->drainMarkStack(budget);
|
||||
}
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_GRAY_WEAK);
|
||||
MarkWeakReferences(gcmarker);
|
||||
}
|
||||
|
||||
JS_ASSERT(gcmarker->isDrained());
|
||||
}
|
||||
|
||||
@ -3136,7 +3147,6 @@ EndMarkPhase(JSRuntime *rt, bool isIncremental)
|
||||
{
|
||||
{
|
||||
gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_MARK);
|
||||
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_MARK_OTHER);
|
||||
MarkGrayAndWeak(rt);
|
||||
}
|
||||
|
||||
@ -3315,6 +3325,7 @@ SweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool *startBackgroundSweep)
|
||||
c->arenas.purge();
|
||||
|
||||
FreeOp fop(rt, *startBackgroundSweep, false);
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_FINALIZE_START);
|
||||
if (rt->gcFinalizeCallback)
|
||||
@ -3325,7 +3336,10 @@ SweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool *startBackgroundSweep)
|
||||
WeakMapBase::sweepAll(&rt->gcMarker);
|
||||
rt->debugScopes->sweep();
|
||||
|
||||
SweepAtomState(rt);
|
||||
{
|
||||
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_ATOMS);
|
||||
SweepAtomState(rt);
|
||||
}
|
||||
|
||||
/* Collect watch points associated with unreachable objects. */
|
||||
WatchpointMap::sweepAll(rt);
|
||||
|
Loading…
Reference in New Issue
Block a user