Commit fe8c8c3b authored by ulan's avatar ulan Committed by Commit bot

Start incremental marking in long idle notification for background tab

disregarding the allocation throughput.

BUG=chromium:506132
LOG=NO

Review URL: https://codereview.chromium.org/1213313004

Cr-Commit-Position: refs/heads/master@{#29515}
parent ca7feba7
...@@ -4956,6 +4956,19 @@ void Heap::IdleNotificationEpilogue(GCIdleTimeAction action, ...@@ -4956,6 +4956,19 @@ void Heap::IdleNotificationEpilogue(GCIdleTimeAction action,
} }
void Heap::CheckAndNotifyBackgroundIdleNotification(double idle_time_in_ms,
double now_ms) {
if (idle_time_in_ms >= GCIdleTimeHandler::kMinBackgroundIdleTime) {
MemoryReducer::Event event;
event.type = MemoryReducer::kBackgroundIdleNotification;
event.time_ms = now_ms;
event.can_start_incremental_gc = incremental_marking()->IsStopped() &&
incremental_marking()->CanBeActivated();
memory_reducer_.NotifyBackgroundIdleNotification(event);
}
}
double Heap::MonotonicallyIncreasingTimeInMs() { double Heap::MonotonicallyIncreasingTimeInMs() {
return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() * return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
static_cast<double>(base::Time::kMillisecondsPerSecond); static_cast<double>(base::Time::kMillisecondsPerSecond);
...@@ -4980,6 +4993,8 @@ bool Heap::IdleNotification(double deadline_in_seconds) { ...@@ -4980,6 +4993,8 @@ bool Heap::IdleNotification(double deadline_in_seconds) {
double start_ms = MonotonicallyIncreasingTimeInMs(); double start_ms = MonotonicallyIncreasingTimeInMs();
double idle_time_in_ms = deadline_in_ms - start_ms; double idle_time_in_ms = deadline_in_ms - start_ms;
CheckAndNotifyBackgroundIdleNotification(idle_time_in_ms, start_ms);
tracer()->SampleAllocation(start_ms, NewSpaceAllocationCounter(), tracer()->SampleAllocation(start_ms, NewSpaceAllocationCounter(),
OldGenerationAllocationCounter()); OldGenerationAllocationCounter());
......
...@@ -2279,6 +2279,8 @@ class Heap { ...@@ -2279,6 +2279,8 @@ class Heap {
void IdleNotificationEpilogue(GCIdleTimeAction action, void IdleNotificationEpilogue(GCIdleTimeAction action,
GCIdleTimeHandler::HeapState heap_state, GCIdleTimeHandler::HeapState heap_state,
double start_ms, double deadline_in_ms); double start_ms, double deadline_in_ms);
void CheckAndNotifyBackgroundIdleNotification(double idle_time_in_ms,
double now_ms);
void ClearObjectStats(bool clear_last_time_stats = false); void ClearObjectStats(bool clear_last_time_stats = false);
......
...@@ -82,6 +82,26 @@ void MemoryReducer::NotifyContextDisposed(const Event& event) { ...@@ -82,6 +82,26 @@ void MemoryReducer::NotifyContextDisposed(const Event& event) {
} }
void MemoryReducer::NotifyBackgroundIdleNotification(const Event& event) {
DCHECK_EQ(kBackgroundIdleNotification, event.type);
Action old_action = state_.action;
int old_started_gcs = state_.started_gcs;
state_ = Step(state_, event);
if (old_action == kWait && state_.action == kWait &&
old_started_gcs + 1 == state_.started_gcs) {
DCHECK(heap()->incremental_marking()->IsStopped());
DCHECK(FLAG_incremental_marking);
heap()->StartIdleIncrementalMarking();
if (FLAG_trace_gc_verbose) {
PrintIsolate(heap()->isolate(),
"Memory reducer: started GC #%d"
" (background idle)\n",
state_.started_gcs);
}
}
}
// For specification of this function see the comment for MemoryReducer class. // For specification of this function see the comment for MemoryReducer class.
MemoryReducer::State MemoryReducer::Step(const State& state, MemoryReducer::State MemoryReducer::Step(const State& state,
const Event& event) { const Event& event) {
...@@ -90,24 +110,40 @@ MemoryReducer::State MemoryReducer::Step(const State& state, ...@@ -90,24 +110,40 @@ MemoryReducer::State MemoryReducer::Step(const State& state,
} }
switch (state.action) { switch (state.action) {
case kDone: case kDone:
if (event.type == kTimer) { if (event.type == kTimer || event.type == kBackgroundIdleNotification) {
return state; return state;
} else { } else {
DCHECK(event.type == kContextDisposed || event.type == kMarkCompact); DCHECK(event.type == kContextDisposed || event.type == kMarkCompact);
return State(kWait, 0, event.time_ms + kLongDelayMs); return State(kWait, 0, event.time_ms + kLongDelayMs);
} }
case kWait: case kWait:
if (event.type == kContextDisposed) { switch (event.type) {
return state; case kContextDisposed:
} else if (event.type == kTimer && event.can_start_incremental_gc &&
event.low_allocation_rate) {
if (state.next_gc_start_ms <= event.time_ms) {
return State(kRun, state.started_gcs + 1, 0.0);
} else {
return state; return state;
} case kTimer:
} else { if (state.started_gcs >= kMaxNumberOfGCs) {
return State(kWait, state.started_gcs, event.time_ms + kLongDelayMs); return State(kDone, 0, 0.0);
} else if (event.can_start_incremental_gc &&
event.low_allocation_rate) {
if (state.next_gc_start_ms <= event.time_ms) {
return State(kRun, state.started_gcs + 1, 0.0);
} else {
return state;
}
} else {
return State(kWait, state.started_gcs,
event.time_ms + kLongDelayMs);
}
case kBackgroundIdleNotification:
if (event.can_start_incremental_gc &&
state.started_gcs < kMaxNumberOfGCs) {
return State(kWait, state.started_gcs + 1,
event.time_ms + kLongDelayMs);
} else {
return state;
}
case kMarkCompact:
return State(kWait, state.started_gcs, event.time_ms + kLongDelayMs);
} }
case kRun: case kRun:
if (event.type != kMarkCompact) { if (event.type != kMarkCompact) {
......
...@@ -48,6 +48,15 @@ class Heap; ...@@ -48,6 +48,15 @@ class Heap;
// - in the timer callback if the mutator allocation rate is high or // - in the timer callback if the mutator allocation rate is high or
// incremental GC is in progress. // incremental GC is in progress.
// //
// WAIT n x -> WAIT (n+1) happens:
// - on background idle notification, which signals that we can start
// incremental marking even if the allocation rate is high.
// The MemoryReducer starts incremental marking on this transition but still
// has a pending timer task.
//
// WAIT n x -> DONE happens:
// - in the timer callback if n >= kMaxNumberOfGCs.
//
// WAIT n x -> RUN (n+1) happens: // WAIT n x -> RUN (n+1) happens:
// - in the timer callback if the mutator allocation rate is low // - in the timer callback if the mutator allocation rate is low
// and now_ms >= x and there is no incremental GC in progress. // and now_ms >= x and there is no incremental GC in progress.
...@@ -81,6 +90,7 @@ class MemoryReducer { ...@@ -81,6 +90,7 @@ class MemoryReducer {
kTimer, kTimer,
kMarkCompact, kMarkCompact,
kContextDisposed, kContextDisposed,
kBackgroundIdleNotification
}; };
struct Event { struct Event {
...@@ -95,8 +105,8 @@ class MemoryReducer { ...@@ -95,8 +105,8 @@ class MemoryReducer {
// Callbacks. // Callbacks.
void NotifyTimer(const Event& event); void NotifyTimer(const Event& event);
void NotifyMarkCompact(const Event& event); void NotifyMarkCompact(const Event& event);
void NotifyScavenge(const Event& event);
void NotifyContextDisposed(const Event& event); void NotifyContextDisposed(const Event& event);
void NotifyBackgroundIdleNotification(const Event& event);
// The step function that computes the next state from the current state and // The step function that computes the next state from the current state and
// the incoming event. // the incoming event.
static State Step(const State& state, const Event& event); static State Step(const State& state, const Event& event);
......
...@@ -82,6 +82,16 @@ MemoryReducer::Event ContextDisposedEvent(double time_ms) { ...@@ -82,6 +82,16 @@ MemoryReducer::Event ContextDisposedEvent(double time_ms) {
} }
MemoryReducer::Event BackgroundIdleNotificationEvent(
double time_ms, bool can_start_incremental_gc = true) {
MemoryReducer::Event event;
event.type = MemoryReducer::kBackgroundIdleNotification;
event.time_ms = time_ms;
event.can_start_incremental_gc = can_start_incremental_gc;
return event;
}
TEST(MemoryReducer, FromDoneToDone) { TEST(MemoryReducer, FromDoneToDone) {
MemoryReducer::State state0(DoneState()), state1(DoneState()); MemoryReducer::State state0(DoneState()), state1(DoneState());
...@@ -93,6 +103,9 @@ TEST(MemoryReducer, FromDoneToDone) { ...@@ -93,6 +103,9 @@ TEST(MemoryReducer, FromDoneToDone) {
state1 = MemoryReducer::Step(state0, TimerEventPendingGC(0)); state1 = MemoryReducer::Step(state0, TimerEventPendingGC(0));
EXPECT_EQ(MemoryReducer::kDone, state1.action); EXPECT_EQ(MemoryReducer::kDone, state1.action);
state1 = MemoryReducer::Step(state0, BackgroundIdleNotificationEvent(0));
EXPECT_EQ(MemoryReducer::kDone, state1.action);
} }
...@@ -153,6 +166,23 @@ TEST(MemoryReducer, FromWaitToWait) { ...@@ -153,6 +166,23 @@ TEST(MemoryReducer, FromWaitToWait) {
EXPECT_EQ(MemoryReducer::kWait, state1.action); EXPECT_EQ(MemoryReducer::kWait, state1.action);
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
EXPECT_EQ(state0.started_gcs, state1.started_gcs); EXPECT_EQ(state0.started_gcs, state1.started_gcs);
state1 = MemoryReducer::Step(state0, BackgroundIdleNotificationEvent(2000));
EXPECT_EQ(MemoryReducer::kWait, state1.action);
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs);
state1 =
MemoryReducer::Step(state0, BackgroundIdleNotificationEvent(2000, false));
EXPECT_EQ(MemoryReducer::kWait, state1.action);
EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms);
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
state0.started_gcs = MemoryReducer::kMaxNumberOfGCs;
state1 = MemoryReducer::Step(state0, BackgroundIdleNotificationEvent(2000));
EXPECT_EQ(MemoryReducer::kWait, state1.action);
EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms);
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
} }
...@@ -169,6 +199,30 @@ TEST(MemoryReducer, FromWaitToRun) { ...@@ -169,6 +199,30 @@ TEST(MemoryReducer, FromWaitToRun) {
} }
TEST(MemoryReducer, FromWaitToDone) {
if (!FLAG_incremental_marking) return;
MemoryReducer::State state0(WaitState(2, 0.0)), state1(DoneState());
state0.started_gcs = MemoryReducer::kMaxNumberOfGCs;
state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(2000));
EXPECT_EQ(MemoryReducer::kDone, state1.action);
EXPECT_EQ(0, state1.next_gc_start_ms);
EXPECT_EQ(0, state1.started_gcs);
state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000));
EXPECT_EQ(MemoryReducer::kDone, state1.action);
EXPECT_EQ(0, state1.next_gc_start_ms);
EXPECT_EQ(0, state1.started_gcs);
state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000));
EXPECT_EQ(MemoryReducer::kDone, state1.action);
EXPECT_EQ(0, state1.next_gc_start_ms);
EXPECT_EQ(0, state1.started_gcs);
}
TEST(MemoryReducer, FromRunToRun) { TEST(MemoryReducer, FromRunToRun) {
if (!FLAG_incremental_marking) return; if (!FLAG_incremental_marking) return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment