Allow IdleNotification to trigger Scavenges.
authorhpayer@chromium.org <hpayer@chromium.org>
Tue, 16 Sep 2014 13:00:05 +0000 (13:00 +0000)
committerhpayer@chromium.org <hpayer@chromium.org>
Tue, 16 Sep 2014 13:00:05 +0000 (13:00 +0000)
BUG=
R=ulan@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23979 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/heap/gc-idle-time-handler-unittest.cc
src/heap/gc-idle-time-handler.cc
src/heap/gc-idle-time-handler.h
src/heap/heap.cc
src/heap/spaces.h

index 24438ae..6a3a00b 100644 (file)
@@ -28,12 +28,17 @@ class GCIdleTimeHandlerTest : public ::testing::Test {
     result.sweeping_in_progress = false;
     result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed;
     result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed;
+    result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed;
+    result.available_new_space_memory = kNewSpaceCapacity;
+    result.new_space_capacity = kNewSpaceCapacity;
     return result;
   }
 
   static const size_t kSizeOfObjects = 100 * MB;
   static const size_t kMarkCompactSpeed = 200 * KB;
   static const size_t kMarkingSpeed = 200 * KB;
+  static const size_t kScavengeSpeed = 100 * KB;
+  static const size_t kNewSpaceCapacity = 1 * MB;
 
  private:
   GCIdleTimeHandler handler_;
@@ -101,6 +106,21 @@ TEST(GCIdleTimeHandler, EstimateMarkCompactTimeMax) {
 }
 
 
+TEST(GCIdleTimeHandler, EstimateScavengeTimeInitial) {
+  size_t size = 1 * MB;
+  size_t time = GCIdleTimeHandler::EstimateScavengeTime(size, 0);
+  EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeScavengeSpeed, time);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateScavengeTimeNonZero) {
+  size_t size = 1 * MB;
+  size_t speed = 1 * MB;
+  size_t time = GCIdleTimeHandler::EstimateScavengeTime(size, speed);
+  EXPECT_EQ(size / speed, time);
+}
+
+
 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeIdleTime) {
   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
   heap_state.contexts_disposed = 1;
index 93be16c..068ff33 100644 (file)
@@ -71,9 +71,40 @@ size_t GCIdleTimeHandler::EstimateMarkCompactTime(
 }
 
 
+size_t GCIdleTimeHandler::EstimateScavengeTime(
+    size_t new_space_size, size_t scavenge_speed_in_bytes_per_ms) {
+  if (scavenge_speed_in_bytes_per_ms == 0) {
+    scavenge_speed_in_bytes_per_ms = kInitialConservativeScavengeSpeed;
+  }
+  return new_space_size / scavenge_speed_in_bytes_per_ms;
+}
+
+
+// The following logic is implemented by the controller:
+// (1) If the new space is almost full and we can effort a Scavenge, then a
+// Scavenge is performed.
+// (2) If there is currently no MarkCompact idle round going on, we start a
+// new idle round if enough garbage was created or we received a context
+// disposal event. Otherwise we do not perform garbage collection to keep
+// system utilization low.
+// (3) If incremental marking is done, we perform a full garbage collection
+// if context was disposed or if we are allowed to still do full garbage
+// collections during this idle round or if we are not allowed to start
+// incremental marking. Otherwise we do not perform garbage collection to
+// keep system utilization low.
+// (4) If sweeping is in progress and we received a large enough idle time
+// request, we finalize sweeping here.
+// (5) If incremental marking is in progress, we perform a marking step. Note,
+// that this currently may trigger a full garbage collection.
 GCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
                                             HeapState heap_state) {
-  if (IsIdleRoundFinished()) {
+  if (heap_state.available_new_space_memory < kNewSpaceAlmostFullTreshold &&
+      idle_time_in_ms >=
+          EstimateScavengeTime(heap_state.new_space_capacity,
+                               heap_state.scavenge_speed_in_bytes_per_ms)) {
+    return GCIdleTimeAction::Scavenge();
+  }
+  if (IsMarkCompactIdleRoundFinished()) {
     if (EnoughGarbageSinceLastIdleRound() || heap_state.contexts_disposed > 0) {
       StartIdleRound();
     } else {
index 2d557df..bdae3ca 100644 (file)
@@ -113,6 +113,14 @@ class GCIdleTimeHandler {
   // That is the maximum idle time we will have during frame rendering.
   static const size_t kMaxFrameRenderingIdleTime = 16;
 
+  // If less than that much memory is left in the new space, we consider it
+  // as almost full and force a new space collection earlier in the idle time.
+  static const size_t kNewSpaceAlmostFullTreshold = 100 * KB;
+
+  // If we haven't recorded any scavenger events yet, we use a conservative
+  // lower bound for the scavenger speed.
+  static const size_t kInitialConservativeScavengeSpeed = 100 * KB;
+
   struct HeapState {
     int contexts_disposed;
     size_t size_of_objects;
@@ -121,6 +129,9 @@ class GCIdleTimeHandler {
     bool sweeping_in_progress;
     size_t mark_compact_speed_in_bytes_per_ms;
     size_t incremental_marking_speed_in_bytes_per_ms;
+    size_t scavenge_speed_in_bytes_per_ms;
+    size_t available_new_space_memory;
+    size_t new_space_capacity;
   };
 
   GCIdleTimeHandler()
@@ -147,9 +158,12 @@ class GCIdleTimeHandler {
   static size_t EstimateMarkCompactTime(
       size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms);
 
+  static size_t EstimateScavengeTime(size_t new_space_size,
+                                     size_t scavenger_speed_in_bytes_per_ms);
+
  private:
   void StartIdleRound() { mark_compacts_since_idle_round_started_ = 0; }
-  bool IsIdleRoundFinished() {
+  bool IsMarkCompactIdleRoundFinished() {
     return mark_compacts_since_idle_round_started_ ==
            kMaxMarkCompactsInIdleRound;
   }
index 2bcd583..c96ea97 100644 (file)
@@ -4311,6 +4311,10 @@ bool Heap::IdleNotification(int idle_time_in_ms) {
       static_cast<size_t>(tracer()->MarkCompactSpeedInBytesPerMillisecond());
   heap_state.incremental_marking_speed_in_bytes_per_ms = static_cast<size_t>(
       tracer()->IncrementalMarkingSpeedInBytesPerMillisecond());
+  heap_state.scavenge_speed_in_bytes_per_ms =
+      static_cast<size_t>(tracer()->ScavengeSpeedInBytesPerMillisecond());
+  heap_state.available_new_space_memory = new_space_.Available();
+  heap_state.new_space_capacity = new_space_.Capacity();
 
   GCIdleTimeAction action =
       gc_idle_time_handler_.Compute(idle_time_in_ms, heap_state);
index cc7e630..7a11902 100644 (file)
@@ -2013,7 +2013,7 @@ class NewSpacePage : public MemoryChunk {
 
   Address address() { return reinterpret_cast<Address>(this); }
 
-  // Finds the NewSpacePage containg the given address.
+  // Finds the NewSpacePage containing the given address.
   static inline NewSpacePage* FromAddress(Address address_in_page) {
     Address page_start =
         reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address_in_page) &