Reviewers: Hannes Payer, rmcilroy,

Message:
PTAL

Description:
Restore NothingOrDone action in idle time handler.

This also adjusts transitioning between modes so that crbug.com/460090 remains
fixed.

BUG=chromium:489323, chromium:460090
LOG=NO

Please review this at https://codereview.chromium.org/1141393002/

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+63, -24 lines):
  M src/heap/gc-idle-time-handler.h
  M src/heap/gc-idle-time-handler.cc
  M test/unittests/heap/gc-idle-time-handler-unittest.cc


Index: src/heap/gc-idle-time-handler.cc
diff --git a/src/heap/gc-idle-time-handler.cc b/src/heap/gc-idle-time-handler.cc index 40c2eff3f96c56ff8e63cc815029a13704545b82..352593e6c42605b3194e8eb22717614bf1399b48 100644
--- a/src/heap/gc-idle-time-handler.cc
+++ b/src/heap/gc-idle-time-handler.cc
@@ -192,6 +192,17 @@ bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure(
 }


+GCIdleTimeAction GCIdleTimeHandler::NothingOrDone() {
+  if (idle_times_which_made_no_progress_per_mode_ >=
+      kMaxNoProgressIdleTimesPerMode) {
+    return GCIdleTimeAction::Done();
+  } else {
+    idle_times_which_made_no_progress_per_mode_++;
+    return GCIdleTimeAction::Nothing();
+  }
+}
+
+
 // The idle time handler has three modes and transitions between them
 // as shown in the diagram:
 //
@@ -306,13 +317,13 @@ GCIdleTimeAction GCIdleTimeHandler::Action(double idle_time_in_ms,
     if (heap_state.sweeping_completed) {
       return GCIdleTimeAction::FinalizeSweeping();
     } else {
-      return GCIdleTimeAction::Nothing();
+      return NothingOrDone();
     }
   }

   if (heap_state.incremental_marking_stopped &&
       !heap_state.can_start_incremental_marking && !reduce_memory) {
-    return GCIdleTimeAction::Nothing();
+    return NothingOrDone();
   }

   size_t step_size = EstimateMarkingStepSize(
@@ -324,19 +335,20 @@ GCIdleTimeAction GCIdleTimeHandler::Action(double idle_time_in_ms,

 void GCIdleTimeHandler::UpdateCounters(double idle_time_in_ms) {
   if (mode_ == kReduceLatency) {
-    int mutator_gcs = scavenges_ + mark_compacts_ - idle_mark_compacts_;
-    if (mutator_gcs > 0) {
+    int gcs = scavenges_ + mark_compacts_;
+    if (gcs > 0) {
       // There was a mutator GC since the last notification.
       long_idle_notifications_ = 0;
     }
     idle_mark_compacts_ = 0;
     mark_compacts_ = 0;
     scavenges_ = 0;
+    // Go to reduce memory mode after two large idle notifications.
+    const int kLargeIdleIncrement =
+        kLongIdleNotificationsBeforeMutatorIsIdle / 2;
     if (idle_time_in_ms >= kMinLongIdleTime) {
       long_idle_notifications_ +=
-          (idle_time_in_ms >= kLargeLongIdleTime)
-              ? kLongIdleNotificationsBeforeMutatorIsIdle
-              : 1;
+ (idle_time_in_ms >= kLargeLongIdleTime) ? kLargeIdleIncrement : 1;
     }
   }
 }
@@ -347,11 +359,14 @@ void GCIdleTimeHandler::ResetCounters() {
   idle_mark_compacts_ = 0;
   mark_compacts_ = 0;
   scavenges_ = 0;
+  idle_times_which_made_no_progress_per_mode_ = 0;
 }


-bool GCIdleTimeHandler::IsMutatorActive(int contexts_disposed, int gcs) {
-  return contexts_disposed > 0 || gcs >= kGCsBeforeMutatorIsActive;
+bool GCIdleTimeHandler::IsMutatorActive(int contexts_disposed,
+                                        int mark_compacts) {
+  return contexts_disposed > 0 ||
+         mark_compacts >= kMarkCompactsBeforeMutatorIsActive;
 }


@@ -368,7 +383,7 @@ GCIdleTimeHandler::Mode GCIdleTimeHandler::NextMode(
   switch (mode_) {
     case kDone:
       DCHECK(idle_mark_compacts_ == 0);
-      if (IsMutatorActive(heap_state.contexts_disposed, mutator_gcs)) {
+      if (IsMutatorActive(heap_state.contexts_disposed, mark_compacts_)) {
         return kReduceLatency;
       }
       break;
Index: src/heap/gc-idle-time-handler.h
diff --git a/src/heap/gc-idle-time-handler.h b/src/heap/gc-idle-time-handler.h index e76178b7e676b547dcddf4d4b0e5b0d83f23cde4..137621f78995b7ec48ab724df443168b8cf2f00b 100644
--- a/src/heap/gc-idle-time-handler.h
+++ b/src/heap/gc-idle-time-handler.h
@@ -151,8 +151,9 @@ class GCIdleTimeHandler {
   // the kDone mode.
   static const int kMaxIdleMarkCompacts = 3;

- // The number of mutator GCs before transitioning to the kReduceLatency mode.
-  static const int kGCsBeforeMutatorIsActive = 7;
+  // The number of mutator MarkCompact GCs before transitioning to the
+  // kReduceLatency mode.
+  static const int kMarkCompactsBeforeMutatorIsActive = 1;

   // Mutator is considered idle if
   // 1) there is an idle notification with time >= kLargeLongIdleTime,
@@ -161,8 +162,11 @@ class GCIdleTimeHandler {
// with time >= kMinLongIdleTime and without any mutator GC in between.
   static const int kMinLongIdleTime = kMaxFrameRenderingIdleTime + 1;
   static const int kLargeLongIdleTime = 900;
-  static const int kLongIdleNotificationsBeforeMutatorIsIdle = 600;
-
+  static const int kLongIdleNotificationsBeforeMutatorIsIdle = 50;
+  // Number of times we will return a Nothing action in the current mode
+ // despite having idle time available before we returning a Done action to
+  // ensure we don't keep scheduling idle tasks and making no progress.
+  static const int kMaxNoProgressIdleTimesPerMode = 10;

   class HeapState {
    public:
@@ -189,6 +193,7 @@ class GCIdleTimeHandler {
         mark_compacts_(0),
         scavenges_(0),
         long_idle_notifications_(0),
+        idle_times_which_made_no_progress_per_mode_(0),
         mode_(kReduceLatency) {}

   GCIdleTimeAction Compute(double idle_time_in_ms, HeapState heap_state);
@@ -238,6 +243,7 @@ class GCIdleTimeHandler {
   Mode NextMode(const HeapState& heap_state);
GCIdleTimeAction Action(double idle_time_in_ms, const HeapState& heap_state,
                           bool reduce_memory);
+  GCIdleTimeAction NothingOrDone();

   int idle_mark_compacts_;
   int mark_compacts_;
@@ -245,6 +251,8 @@ class GCIdleTimeHandler {
   // The number of long idle notifications with no mutator GC happening
   // between the notifications.
   int long_idle_notifications_;
+  // Idle notifications with no progress in the current mode.
+  int idle_times_which_made_no_progress_per_mode_;

   Mode mode_;

Index: test/unittests/heap/gc-idle-time-handler-unittest.cc
diff --git a/test/unittests/heap/gc-idle-time-handler-unittest.cc b/test/unittests/heap/gc-idle-time-handler-unittest.cc index 357b08f88108117d8c74d91ddbf6c42df215708c..2a1aeb44959792199aae6b1e6d9f82ca70b3dad9 100644
--- a/test/unittests/heap/gc-idle-time-handler-unittest.cc
+++ b/test/unittests/heap/gc-idle-time-handler-unittest.cc
@@ -48,7 +48,11 @@ class GCIdleTimeHandlerTest : public ::testing::Test {
                        heap_state.can_start_incremental_marking;
     for (int i = 0; i < limit; i++) {
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(incremental ? DO_INCREMENTAL_MARKING : DO_NOTHING, action.type);
+      if (incremental) {
+        EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+      } else {
+        EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type);
+      }
     }
     handler()->Compute(idle_time_ms, heap_state);
     EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode());
@@ -73,16 +77,12 @@ class GCIdleTimeHandlerTest : public ::testing::Test {
   void TransitionToReduceLatencyMode(
       const GCIdleTimeHandler::HeapState& heap_state) {
     EXPECT_EQ(GCIdleTimeHandler::kDone, handler()->mode());
-    int limit = GCIdleTimeHandler::kGCsBeforeMutatorIsActive;
+    int limit = GCIdleTimeHandler::kMarkCompactsBeforeMutatorIsActive;
     double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime;
     for (int i = 0; i < limit; i++) {
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
       EXPECT_EQ(DONE, action.type);
-      if (i % 2 == 0) {
-        handler()->NotifyScavenge();
-      } else {
-        handler()->NotifyMarkCompact();
-      }
+      handler()->NotifyMarkCompact();
     }
     handler()->Compute(idle_time_ms, heap_state);
     EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode());
@@ -550,7 +550,7 @@ TEST_F(GCIdleTimeHandlerTest, SmallIdleTimeNothingToDo) {
   heap_state.can_start_incremental_marking = false;
   for (int i = 0; i < kMaxNotifications; i++) {
     GCIdleTimeAction action = handler()->Compute(10, heap_state);
-    EXPECT_EQ(DO_NOTHING, action.type);
+    EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type);
   }
 }

@@ -563,7 +563,7 @@ TEST_F(GCIdleTimeHandlerTest, StayInReduceLatencyModeBecauseOfScavenges) {
   int limit = GCIdleTimeHandler::kLongIdleNotificationsBeforeMutatorIsIdle;
   for (int i = 0; i < kMaxNotifications; i++) {
     GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-    EXPECT_EQ(DO_NOTHING, action.type);
+    EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type);
     if ((i + 1) % limit == 0) handler()->NotifyScavenge();
     EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode());
   }
@@ -578,7 +578,7 @@ TEST_F(GCIdleTimeHandlerTest, StayInReduceLatencyModeBecauseOfMarkCompacts) {
   int limit = GCIdleTimeHandler::kLongIdleNotificationsBeforeMutatorIsIdle;
   for (int i = 0; i < kMaxNotifications; i++) {
     GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-    EXPECT_EQ(DO_NOTHING, action.type);
+    EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type);
     if ((i + 1) % limit == 0) handler()->NotifyMarkCompact();
     EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode());
   }
@@ -643,5 +643,21 @@ TEST_F(GCIdleTimeHandlerTest, ReduceMemoryToDone) {
 }


+TEST_F(GCIdleTimeHandlerTest, Regress489323) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  // Simulate incremental marking stopped and not eligible to start.
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  double idle_time_ms = 10.0;
+ for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerMode; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    EXPECT_EQ(DO_NOTHING, action.type);
+  }
+  // We should return DONE after not making progress for some time.
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+}
+
+
 }  // namespace internal
 }  // namespace v8


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to