[heap] Reland "Add a guard for restarting the memory reducer after mark-compact."
This reverts commit 3c96c5e232
.
The CL was reverted to see its impact on UMA memory counters.
There was no impact, so we can safely reland the CL.
BUG=
Review-Url: https://codereview.chromium.org/2507293004
Cr-Commit-Position: refs/heads/master@{#41109}
This commit is contained in:
parent
d4f01b8a65
commit
b9f8ad002e
@ -1013,6 +1013,7 @@ bool Heap::CollectGarbage(GarbageCollector collector,
|
||||
(committed_memory_before > committed_memory_after + MB) ||
|
||||
HasHighFragmentation(used_memory_after, committed_memory_after) ||
|
||||
(detached_contexts()->length() > 0);
|
||||
event.committed_memory = committed_memory_after;
|
||||
if (deserialization_complete_) {
|
||||
memory_reducer_->NotifyMarkCompact(event);
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ const int MemoryReducer::kLongDelayMs = 8000;
|
||||
const int MemoryReducer::kShortDelayMs = 500;
|
||||
const int MemoryReducer::kWatchdogDelayMs = 100000;
|
||||
const int MemoryReducer::kMaxNumberOfGCs = 3;
|
||||
const double MemoryReducer::kCommittedMemoryFactor = 1.1;
|
||||
const size_t MemoryReducer::kCommittedMemoryDelta = 10 * MB;
|
||||
|
||||
MemoryReducer::TimerTask::TimerTask(MemoryReducer* memory_reducer)
|
||||
: CancelableTask(memory_reducer->heap()->isolate()),
|
||||
@ -47,6 +49,7 @@ void MemoryReducer::TimerTask::RunInternal() {
|
||||
event.can_start_incremental_gc =
|
||||
heap->incremental_marking()->IsStopped() &&
|
||||
(heap->incremental_marking()->CanBeActivated() || optimize_for_memory);
|
||||
event.committed_memory = heap->CommittedOldGenerationMemory();
|
||||
memory_reducer_->NotifyTimer(event);
|
||||
}
|
||||
|
||||
@ -128,17 +131,30 @@ bool MemoryReducer::WatchdogGC(const State& state, const Event& event) {
|
||||
MemoryReducer::State MemoryReducer::Step(const State& state,
|
||||
const Event& event) {
|
||||
if (!FLAG_incremental_marking || !FLAG_memory_reducer) {
|
||||
return State(kDone, 0, 0, state.last_gc_time_ms);
|
||||
return State(kDone, 0, 0, state.last_gc_time_ms, 0);
|
||||
}
|
||||
switch (state.action) {
|
||||
case kDone:
|
||||
if (event.type == kTimer) {
|
||||
return state;
|
||||
} else if (event.type == kMarkCompact) {
|
||||
if (event.committed_memory <
|
||||
Max(static_cast<size_t>(state.committed_memory_at_last_run *
|
||||
kCommittedMemoryFactor),
|
||||
state.committed_memory_at_last_run + kCommittedMemoryDelta)) {
|
||||
return state;
|
||||
} else {
|
||||
DCHECK(event.type == kPossibleGarbage || event.type == kMarkCompact);
|
||||
return State(kWait, 0, event.time_ms + kLongDelayMs,
|
||||
event.type == kMarkCompact ? event.time_ms
|
||||
: state.last_gc_time_ms,
|
||||
0);
|
||||
}
|
||||
} else {
|
||||
DCHECK_EQ(kPossibleGarbage, event.type);
|
||||
return State(
|
||||
kWait, 0, event.time_ms + kLongDelayMs,
|
||||
event.type == kMarkCompact ? event.time_ms : state.last_gc_time_ms);
|
||||
event.type == kMarkCompact ? event.time_ms : state.last_gc_time_ms,
|
||||
0);
|
||||
}
|
||||
case kWait:
|
||||
switch (event.type) {
|
||||
@ -146,23 +162,24 @@ MemoryReducer::State MemoryReducer::Step(const State& state,
|
||||
return state;
|
||||
case kTimer:
|
||||
if (state.started_gcs >= kMaxNumberOfGCs) {
|
||||
return State(kDone, kMaxNumberOfGCs, 0.0, state.last_gc_time_ms);
|
||||
return State(kDone, kMaxNumberOfGCs, 0.0, state.last_gc_time_ms,
|
||||
event.committed_memory);
|
||||
} else if (event.can_start_incremental_gc &&
|
||||
(event.should_start_incremental_gc ||
|
||||
WatchdogGC(state, event))) {
|
||||
if (state.next_gc_start_ms <= event.time_ms) {
|
||||
return State(kRun, state.started_gcs + 1, 0.0,
|
||||
state.last_gc_time_ms);
|
||||
state.last_gc_time_ms, 0);
|
||||
} else {
|
||||
return state;
|
||||
}
|
||||
} else {
|
||||
return State(kWait, state.started_gcs, event.time_ms + kLongDelayMs,
|
||||
state.last_gc_time_ms);
|
||||
state.last_gc_time_ms, 0);
|
||||
}
|
||||
case kMarkCompact:
|
||||
return State(kWait, state.started_gcs, event.time_ms + kLongDelayMs,
|
||||
event.time_ms);
|
||||
event.time_ms, 0);
|
||||
}
|
||||
case kRun:
|
||||
if (event.type != kMarkCompact) {
|
||||
@ -171,14 +188,15 @@ MemoryReducer::State MemoryReducer::Step(const State& state,
|
||||
if (state.started_gcs < kMaxNumberOfGCs &&
|
||||
(event.next_gc_likely_to_collect_more || state.started_gcs == 1)) {
|
||||
return State(kWait, state.started_gcs, event.time_ms + kShortDelayMs,
|
||||
event.time_ms);
|
||||
event.time_ms, 0);
|
||||
} else {
|
||||
return State(kDone, kMaxNumberOfGCs, 0.0, event.time_ms);
|
||||
return State(kDone, kMaxNumberOfGCs, 0.0, event.time_ms,
|
||||
event.committed_memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return State(kDone, 0, 0, 0.0); // Make the compiler happy.
|
||||
return State(kDone, 0, 0, 0.0, 0); // Make the compiler happy.
|
||||
}
|
||||
|
||||
|
||||
@ -192,7 +210,7 @@ void MemoryReducer::ScheduleTimer(double time_ms, double delay_ms) {
|
||||
isolate, timer_task, (delay_ms + kSlackMs) / 1000.0);
|
||||
}
|
||||
|
||||
void MemoryReducer::TearDown() { state_ = State(kDone, 0, 0, 0.0); }
|
||||
void MemoryReducer::TearDown() { state_ = State(kDone, 0, 0, 0.0, 0); }
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -86,15 +86,17 @@ class V8_EXPORT_PRIVATE MemoryReducer {
|
||||
|
||||
struct State {
|
||||
State(Action action, int started_gcs, double next_gc_start_ms,
|
||||
double last_gc_time_ms)
|
||||
double last_gc_time_ms, size_t committed_memory_at_last_run)
|
||||
: action(action),
|
||||
started_gcs(started_gcs),
|
||||
next_gc_start_ms(next_gc_start_ms),
|
||||
last_gc_time_ms(last_gc_time_ms) {}
|
||||
last_gc_time_ms(last_gc_time_ms),
|
||||
committed_memory_at_last_run(committed_memory_at_last_run) {}
|
||||
Action action;
|
||||
int started_gcs;
|
||||
double next_gc_start_ms;
|
||||
double last_gc_time_ms;
|
||||
size_t committed_memory_at_last_run;
|
||||
};
|
||||
|
||||
enum EventType { kTimer, kMarkCompact, kPossibleGarbage };
|
||||
@ -102,6 +104,7 @@ class V8_EXPORT_PRIVATE MemoryReducer {
|
||||
struct Event {
|
||||
EventType type;
|
||||
double time_ms;
|
||||
size_t committed_memory;
|
||||
bool next_gc_likely_to_collect_more;
|
||||
bool should_start_incremental_gc;
|
||||
bool can_start_incremental_gc;
|
||||
@ -109,7 +112,7 @@ class V8_EXPORT_PRIVATE MemoryReducer {
|
||||
|
||||
explicit MemoryReducer(Heap* heap)
|
||||
: heap_(heap),
|
||||
state_(kDone, 0, 0.0, 0.0),
|
||||
state_(kDone, 0, 0.0, 0.0, 0),
|
||||
js_calls_counter_(0),
|
||||
js_calls_sample_time_ms_(0.0) {}
|
||||
// Callbacks.
|
||||
@ -126,6 +129,12 @@ class V8_EXPORT_PRIVATE MemoryReducer {
|
||||
static const int kShortDelayMs;
|
||||
static const int kWatchdogDelayMs;
|
||||
static const int kMaxNumberOfGCs;
|
||||
// The committed memory has to increase by at least this factor since the
|
||||
// last run in order to trigger a new run after mark-compact.
|
||||
static const double kCommittedMemoryFactor;
|
||||
// The committed memory has to increase by at least this amount since the
|
||||
// last run in order to trigger a new run after mark-compact.
|
||||
static const size_t kCommittedMemoryDelta;
|
||||
|
||||
Heap* heap() { return heap_; }
|
||||
|
||||
|
@ -12,36 +12,44 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
MemoryReducer::State DoneState() {
|
||||
return MemoryReducer::State(MemoryReducer::kDone, 0, 0.0, 1.0);
|
||||
return MemoryReducer::State(MemoryReducer::kDone, 0, 0.0, 1.0, 0);
|
||||
}
|
||||
|
||||
MemoryReducer::State DoneState(size_t committed_memory) {
|
||||
return MemoryReducer::State(MemoryReducer::kDone, 0, 0.0, 1.0,
|
||||
committed_memory);
|
||||
}
|
||||
|
||||
MemoryReducer::State WaitState(int started_gcs, double next_gc_start_ms) {
|
||||
return MemoryReducer::State(MemoryReducer::kWait, started_gcs,
|
||||
next_gc_start_ms, 1.0);
|
||||
next_gc_start_ms, 1.0, 0);
|
||||
}
|
||||
|
||||
|
||||
MemoryReducer::State RunState(int started_gcs, double next_gc_start_ms) {
|
||||
return MemoryReducer::State(MemoryReducer::kRun, started_gcs,
|
||||
next_gc_start_ms, 1.0);
|
||||
next_gc_start_ms, 1.0, 0);
|
||||
}
|
||||
|
||||
MemoryReducer::Event MarkCompactEvent(double time_ms,
|
||||
bool next_gc_likely_to_collect_more) {
|
||||
bool next_gc_likely_to_collect_more,
|
||||
size_t committed_memory) {
|
||||
MemoryReducer::Event event;
|
||||
event.type = MemoryReducer::kMarkCompact;
|
||||
event.time_ms = time_ms;
|
||||
event.next_gc_likely_to_collect_more = next_gc_likely_to_collect_more;
|
||||
event.committed_memory = committed_memory;
|
||||
return event;
|
||||
}
|
||||
|
||||
MemoryReducer::Event MarkCompactEventGarbageLeft(double time_ms) {
|
||||
return MarkCompactEvent(time_ms, true);
|
||||
MemoryReducer::Event MarkCompactEventGarbageLeft(double time_ms,
|
||||
size_t committed_memory) {
|
||||
return MarkCompactEvent(time_ms, true, committed_memory);
|
||||
}
|
||||
|
||||
MemoryReducer::Event MarkCompactEventNoGarbageLeft(double time_ms) {
|
||||
return MarkCompactEvent(time_ms, false);
|
||||
MemoryReducer::Event MarkCompactEventNoGarbageLeft(double time_ms,
|
||||
size_t committed_memory) {
|
||||
return MarkCompactEvent(time_ms, false, committed_memory);
|
||||
}
|
||||
|
||||
|
||||
@ -90,6 +98,19 @@ TEST(MemoryReducer, FromDoneToDone) {
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventPendingGC(0));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
|
||||
state1 = MemoryReducer::Step(
|
||||
state0,
|
||||
MarkCompactEventGarbageLeft(0, MemoryReducer::kCommittedMemoryDelta - 1));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
|
||||
state0 = DoneState(1000 * MB);
|
||||
state1 = MemoryReducer::Step(
|
||||
state0, MarkCompactEventGarbageLeft(
|
||||
0, static_cast<size_t>(
|
||||
1000 * MB * MemoryReducer::kCommittedMemoryFactor) -
|
||||
1));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
}
|
||||
|
||||
|
||||
@ -98,13 +119,17 @@ TEST(MemoryReducer, FromDoneToWait) {
|
||||
|
||||
MemoryReducer::State state0(DoneState()), state1(DoneState());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2));
|
||||
state1 = MemoryReducer::Step(
|
||||
state0,
|
||||
MarkCompactEventGarbageLeft(2, MemoryReducer::kCommittedMemoryDelta));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kLongDelayMs + 2, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(0, state1.started_gcs);
|
||||
EXPECT_EQ(2, state1.last_gc_time_ms);
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2));
|
||||
state1 = MemoryReducer::Step(
|
||||
state0,
|
||||
MarkCompactEventNoGarbageLeft(2, MemoryReducer::kCommittedMemoryDelta));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kLongDelayMs + 2, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(0, state1.started_gcs);
|
||||
@ -115,6 +140,16 @@ TEST(MemoryReducer, FromDoneToWait) {
|
||||
EXPECT_EQ(MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(0, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
|
||||
state0 = DoneState(1000 * MB);
|
||||
state1 = MemoryReducer::Step(
|
||||
state0, MarkCompactEventGarbageLeft(
|
||||
2, static_cast<size_t>(
|
||||
1000 * MB * MemoryReducer::kCommittedMemoryFactor)));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kLongDelayMs + 2, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(0, state1.started_gcs);
|
||||
EXPECT_EQ(2, state1.last_gc_time_ms);
|
||||
}
|
||||
|
||||
|
||||
@ -144,13 +179,13 @@ TEST(MemoryReducer, FromWaitToWait) {
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000));
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms);
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000));
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
@ -259,7 +294,7 @@ TEST(MemoryReducer, FromRunToDone) {
|
||||
|
||||
MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000));
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(0, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs);
|
||||
@ -267,7 +302,7 @@ TEST(MemoryReducer, FromRunToDone) {
|
||||
|
||||
state0.started_gcs = MemoryReducer::kMaxNumberOfGCs;
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000));
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(0, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms);
|
||||
@ -279,7 +314,7 @@ TEST(MemoryReducer, FromRunToWait) {
|
||||
|
||||
MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000));
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
@ -287,7 +322,7 @@ TEST(MemoryReducer, FromRunToWait) {
|
||||
|
||||
state0.started_gcs = 1;
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000));
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
|
Loading…
Reference in New Issue
Block a user