Revision: 24790
Author:   [email protected]
Date:     Wed Oct 22 06:58:38 2014 UTC
Log:      Add support for a target new space size

When this flag is set, we will commit additional pages up until the
target size before doing a scavenge.

I made sure that all tests pass when a target size of 16MB is set.

BUG=v8:3626
[email protected]
LOG=n

Review URL: https://codereview.chromium.org/652543007
https://code.google.com/p/v8/source/detail?r=24790

Modified:
 /branches/bleeding_edge/src/flag-definitions.h
 /branches/bleeding_edge/src/heap/heap.cc
 /branches/bleeding_edge/src/heap/heap.h
 /branches/bleeding_edge/src/heap/spaces.cc
 /branches/bleeding_edge/src/heap/spaces.h
 /branches/bleeding_edge/test/cctest/cctest.h
 /branches/bleeding_edge/test/cctest/test-spaces.cc

=======================================
--- /branches/bleeding_edge/src/flag-definitions.h Tue Oct 21 17:21:32 2014 UTC +++ /branches/bleeding_edge/src/flag-definitions.h Wed Oct 22 06:58:38 2014 UTC
@@ -509,6 +509,8 @@
 DEFINE_INT(min_semi_space_size, 0,
"min size of a semi-space (in MBytes), the new space consists of two"
            "semi-spaces")
+DEFINE_INT(target_semi_space_size, 0,
+ "target size of a semi-space (in MBytes) before triggering a GC")
 DEFINE_INT(max_semi_space_size, 0,
"max size of a semi-space (in MBytes), the new space consists of two"
            "semi-spaces")
=======================================
--- /branches/bleeding_edge/src/heap/heap.cc    Mon Oct 20 12:12:51 2014 UTC
+++ /branches/bleeding_edge/src/heap/heap.cc    Wed Oct 22 06:58:38 2014 UTC
@@ -61,6 +61,7 @@
       reserved_semispace_size_(8 * (kPointerSize / 4) * MB),
       max_semi_space_size_(8 * (kPointerSize / 4) * MB),
       initial_semispace_size_(Page::kPageSize),
+      target_semispace_size_(Page::kPageSize),
       max_old_generation_size_(700ul * (kPointerSize / 4) * MB),
       max_executable_size_(256ul * (kPointerSize / 4) * MB),
       // Variables set based on semispace_size_ and old_generation_size_ in
@@ -4944,9 +4945,9 @@
       initial_semispace_size_ = max_semi_space_size_;
       if (FLAG_trace_gc) {
         PrintPID(
-            "Min semi-space size cannot be more than the maximum"
+            "Min semi-space size cannot be more than the maximum "
             "semi-space size of %d MB\n",
-            max_semi_space_size_);
+            max_semi_space_size_ / MB);
       }
     } else {
       initial_semispace_size_ = initial_semispace_size;
@@ -4955,6 +4956,31 @@

initial_semispace_size_ = Min(initial_semispace_size_, max_semi_space_size_);

+  if (FLAG_target_semi_space_size > 0) {
+    int target_semispace_size = FLAG_target_semi_space_size * MB;
+    if (target_semispace_size < initial_semispace_size_) {
+      target_semispace_size_ = initial_semispace_size_;
+      if (FLAG_trace_gc) {
+        PrintPID(
+            "Target semi-space size cannot be less than the minimum "
+            "semi-space size of %d MB\n",
+            initial_semispace_size_ / MB);
+      }
+    } else if (target_semispace_size > max_semi_space_size_) {
+      target_semispace_size_ = max_semi_space_size_;
+      if (FLAG_trace_gc) {
+        PrintPID(
+            "Target semi-space size cannot be less than the maximum "
+            "semi-space size of %d MB\n",
+            max_semi_space_size_ / MB);
+      }
+    } else {
+      target_semispace_size_ = target_semispace_size;
+    }
+  }
+
+ target_semispace_size_ = Max(initial_semispace_size_, target_semispace_size_);
+
// The old generation is paged and needs at least one page for each space.
   int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
   max_old_generation_size_ =
=======================================
--- /branches/bleeding_edge/src/heap/heap.h     Tue Oct 21 17:21:32 2014 UTC
+++ /branches/bleeding_edge/src/heap/heap.h     Wed Oct 22 06:58:38 2014 UTC
@@ -570,6 +570,7 @@
   int MaxSemiSpaceSize() { return max_semi_space_size_; }
   int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
   int InitialSemiSpaceSize() { return initial_semispace_size_; }
+  int TargetSemiSpaceSize() { return target_semispace_size_; }
   intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
   intptr_t MaxExecutableSize() { return max_executable_size_; }

@@ -1472,6 +1473,7 @@
   int reserved_semispace_size_;
   int max_semi_space_size_;
   int initial_semispace_size_;
+  int target_semispace_size_;
   intptr_t max_old_generation_size_;
   intptr_t max_executable_size_;
   intptr_t maximum_committed_;
=======================================
--- /branches/bleeding_edge/src/heap/spaces.cc  Tue Oct 14 09:59:24 2014 UTC
+++ /branches/bleeding_edge/src/heap/spaces.cc  Wed Oct 22 06:58:38 2014 UTC
@@ -1195,6 +1195,8 @@
   // this chunk must be a power of two and it must be aligned to its size.
   int initial_semispace_capacity = heap()->InitialSemiSpaceSize();

+  int target_semispace_capacity = heap()->TargetSemiSpaceSize();
+
   size_t size = 2 * reserved_semispace_capacity;
Address base = heap()->isolate()->memory_allocator()->ReserveAlignedMemory(
       size, size, &reservation_);
@@ -1223,9 +1225,10 @@
DCHECK(IsAddressAligned(chunk_base_, 2 * reserved_semispace_capacity, 0));

   to_space_.SetUp(chunk_base_, initial_semispace_capacity,
-                  maximum_semispace_capacity);
+                  target_semispace_capacity, maximum_semispace_capacity);
   from_space_.SetUp(chunk_base_ + reserved_semispace_capacity,
- initial_semispace_capacity, maximum_semispace_capacity);
+                    initial_semispace_capacity, target_semispace_capacity,
+                    maximum_semispace_capacity);
   if (!to_space_.Commit()) {
     return false;
   }
@@ -1285,12 +1288,42 @@
       if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) {
         // We are in an inconsistent state because we could not
         // commit/uncommit memory from new space.
-        V8::FatalProcessOutOfMemory("Failed to grow new space.");
+        CHECK(false);
       }
     }
   }
   DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
 }
+
+
+bool NewSpace::GrowOnePage() {
+  if (TotalCapacity() == MaximumCapacity()) return false;
+  int new_capacity = static_cast<int>(TotalCapacity()) + Page::kPageSize;
+  if (to_space_.GrowTo(new_capacity)) {
+ // Only grow from space if we managed to grow to-space and the from space
+    // is actually committed.
+    if (from_space_.is_committed()) {
+      if (!from_space_.GrowTo(new_capacity)) {
+        // If we managed to grow to-space but couldn't grow from-space,
+        // attempt to shrink to-space.
+        if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) {
+          // We are in an inconsistent state because we could not
+          // commit/uncommit memory from new space.
+          CHECK(false);
+        }
+        return false;
+      }
+    } else {
+      if (!from_space_.SetTotalCapacity(new_capacity)) {
+        // Can't really happen, but better safe than sorry.
+        CHECK(false);
+      }
+    }
+    DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
+    return true;
+  }
+  return false;
+}


 void NewSpace::Shrink() {
@@ -1306,7 +1339,7 @@
       if (!to_space_.GrowTo(from_space_.TotalCapacity())) {
         // We are in an inconsistent state because we could not
         // commit/uncommit memory from new space.
-        V8::FatalProcessOutOfMemory("Failed to shrink new space.");
+        CHECK(false);
       }
     }
   }
@@ -1367,8 +1400,19 @@
     return false;
   }
   if (!to_space_.AdvancePage()) {
-    // Failed to get a new page in to-space.
-    return false;
+ // Check if we reached the target capacity yet. If not, try to commit a page
+    // and continue.
+    if ((to_space_.TotalCapacity() < to_space_.TargetCapacity()) &&
+        GrowOnePage()) {
+      if (!to_space_.AdvancePage()) {
+ // It doesn't make sense that we managed to commit a page, but can't use
+        // it.
+        CHECK(false);
+      }
+    } else {
+      // Failed to get a new page in to-space.
+      return false;
+    }
   }

   // Clear remainder of current page.
@@ -1472,7 +1516,7 @@
// -----------------------------------------------------------------------------
 // SemiSpace implementation

-void SemiSpace::SetUp(Address start, int initial_capacity,
+void SemiSpace::SetUp(Address start, int initial_capacity, int target_capacity,
                       int maximum_capacity) {
   // Creates a space in the young generation. The constructor does not
// allocate memory from the OS. A SemiSpace is given a contiguous chunk of
@@ -1481,8 +1525,11 @@
   // space is used as the marking stack. It requires contiguous memory
   // addresses.
   DCHECK(maximum_capacity >= Page::kPageSize);
+  DCHECK(initial_capacity <= target_capacity);
+  DCHECK(target_capacity <= maximum_capacity);
   initial_total_capacity_ = RoundDown(initial_capacity, Page::kPageSize);
   total_capacity_ = initial_capacity;
+  target_capacity_ = RoundDown(target_capacity, Page::kPageSize);
   maximum_total_capacity_ = RoundDown(maximum_capacity, Page::kPageSize);
   maximum_committed_ = 0;
   committed_ = false;
@@ -1609,6 +1656,17 @@

   return true;
 }
+
+
+bool SemiSpace::SetTotalCapacity(int new_capacity) {
+  CHECK(!is_committed());
+  if (new_capacity >= initial_total_capacity_ &&
+      new_capacity <= maximum_total_capacity_) {
+    total_capacity_ = new_capacity;
+    return true;
+  }
+  return false;
+}


 void SemiSpace::FlipPages(intptr_t flags, intptr_t mask) {
=======================================
--- /branches/bleeding_edge/src/heap/spaces.h   Mon Sep 29 12:17:31 2014 UTC
+++ /branches/bleeding_edge/src/heap/spaces.h   Wed Oct 22 06:58:38 2014 UTC
@@ -2075,7 +2075,8 @@
         current_page_(NULL) {}

   // Sets up the semispace using the given chunk.
-  void SetUp(Address start, int initial_capacity, int maximum_capacity);
+  void SetUp(Address start, int initial_capacity, int target_capacity,
+             int maximum_capacity);

// Tear down the space. Heap memory was not allocated by the space, so it
   // is not deallocated here.
@@ -2094,6 +2095,9 @@
   // semispace and less than the current capacity.
   bool ShrinkTo(int new_capacity);

+ // Sets the total capacity. Only possible when the space is not committed.
+  bool SetTotalCapacity(int new_capacity);
+
   // Returns the start address of the first page of the space.
   Address space_start() {
     DCHECK(anchor_.next_page() != &anchor_);
@@ -2167,6 +2171,9 @@

   // Returns the current total capacity of the semispace.
   int TotalCapacity() { return total_capacity_; }
+
+  // Returns the target for total capacity of the semispace.
+  int TargetCapacity() { return target_capacity_; }

   // Returns the maximum total capacity of the semispace.
   int MaximumTotalCapacity() { return maximum_total_capacity_; }
@@ -2196,6 +2203,7 @@

   // The current and maximum total capacity of the space.
   int total_capacity_;
+  int target_capacity_;
   int maximum_total_capacity_;
   int initial_total_capacity_;

@@ -2341,6 +2349,9 @@
   // their maximum capacity.
   void Grow();

+  // Grow the capacity of the semispaces by one page.
+  bool GrowOnePage();
+
   // Shrink the capacity of the semispaces.
   void Shrink();

=======================================
--- /branches/bleeding_edge/test/cctest/cctest.h Wed Oct 8 09:34:40 2014 UTC +++ /branches/bleeding_edge/test/cctest/cctest.h Wed Oct 22 06:58:38 2014 UTC
@@ -481,15 +481,31 @@


 // Helper function that simulates a full new-space in the heap.
-static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
-  int new_linear_size = static_cast<int>(
- *space->allocation_limit_address() - *space->allocation_top_address());
-  if (new_linear_size == 0) return;
+static inline bool FillUpOnePage(v8::internal::NewSpace* space) {
   v8::internal::AllocationResult allocation =
-      space->AllocateRaw(new_linear_size);
+      space->AllocateRaw(v8::internal::Page::kMaxRegularHeapObjectSize);
+  if (allocation.IsRetry()) return false;
   v8::internal::FreeListNode* node =
       v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
-  node->set_size(space->heap(), new_linear_size);
+ node->set_size(space->heap(), v8::internal::Page::kMaxRegularHeapObjectSize);
+  return true;
+}
+
+
+static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
+ int new_linear_size = static_cast<int>(*space->allocation_limit_address() -
+                                         *space->allocation_top_address());
+  if (new_linear_size > 0) {
+    // Fill up the current page.
+    v8::internal::AllocationResult allocation =
+        space->AllocateRaw(new_linear_size);
+    v8::internal::FreeListNode* node =
+        v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+    node->set_size(space->heap(), new_linear_size);
+  }
+  // Fill up all remaining pages.
+  while (FillUpOnePage(space))
+    ;
 }


=======================================
--- /branches/bleeding_edge/test/cctest/test-spaces.cc Wed Oct 1 11:54:47 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-spaces.cc Wed Oct 22 06:58:38 2014 UTC
@@ -456,3 +456,54 @@
   // No large objects required to perform the above steps.
   CHECK(isolate->heap()->lo_space()->IsEmpty());
 }
+
+
+static inline void FillCurrentPage(v8::internal::NewSpace* space) {
+ int new_linear_size = static_cast<int>(*space->allocation_limit_address() -
+                                         *space->allocation_top_address());
+  if (new_linear_size == 0) return;
+  v8::internal::AllocationResult allocation =
+      space->AllocateRaw(new_linear_size);
+  v8::internal::FreeListNode* node =
+      v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+  node->set_size(space->heap(), new_linear_size);
+}
+
+
+UNINITIALIZED_TEST(NewSpaceGrowsToTargetCapacity) {
+  FLAG_target_semi_space_size = 2;
+
+  v8::Isolate* isolate = v8::Isolate::New();
+  {
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::HandleScope handle_scope(isolate);
+    v8::Context::New(isolate)->Enter();
+
+    Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
+
+    NewSpace* new_space = i_isolate->heap()->new_space();
+
+    // This test doesn't work if we start with a non-default new space
+    // configuration.
+    if (new_space->InitialTotalCapacity() == Page::kPageSize) {
+ CHECK(new_space->CommittedMemory() == new_space->InitialTotalCapacity());
+
+      // Fill up the first (and only) page of the semi space.
+      FillCurrentPage(new_space);
+
+ // Try to allocate out of the new space. A new page should be added and
+      // the
+      // allocation should succeed.
+ v8::internal::AllocationResult allocation = new_space->AllocateRaw(80);
+      CHECK(!allocation.IsRetry());
+      CHECK(new_space->CommittedMemory() == 2 * Page::kPageSize);
+
+      // Turn the allocation into a proper object so isolate teardown won't
+      // crash.
+      v8::internal::FreeListNode* node =
+          v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+      node->set_size(new_space->heap(), 80);
+    }
+  }
+  isolate->Dispose();
+}

--
--
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