Revision: 23282
Author:   [email protected]
Date:     Thu Aug 21 14:42:22 2014 UTC
Log:      Move idle notification handling to GCIdleTimeHandler.

BUG=
[email protected]

Review URL: https://codereview.chromium.org/492763002
http://code.google.com/p/v8/source/detail?r=23282

Modified:
 /branches/bleeding_edge/src/heap/gc-idle-time-handler.cc
 /branches/bleeding_edge/src/heap/gc-idle-time-handler.h
 /branches/bleeding_edge/src/heap/gc-tracer.cc
 /branches/bleeding_edge/src/heap/gc-tracer.h
 /branches/bleeding_edge/src/heap/heap.cc
 /branches/bleeding_edge/src/heap/heap.h
 /branches/bleeding_edge/test/heap-unittests/heap-unittest.cc

=======================================
--- /branches/bleeding_edge/src/heap/gc-idle-time-handler.cc Wed Aug 20 15:37:43 2014 UTC +++ /branches/bleeding_edge/src/heap/gc-idle-time-handler.cc Thu Aug 21 14:42:22 2014 UTC
@@ -3,12 +3,14 @@
 // found in the LICENSE file.

 #include "src/heap/gc-idle-time-handler.h"
+#include "src/heap/gc-tracer.h"
+#include "src/utils.h"

 namespace v8 {
 namespace internal {

-
 const double GCIdleTimeHandler::kConservativeTimeRatio = 0.9;
+const size_t GCIdleTimeHandler::kMaxMarkCompactTimeInMs = 1000000;


 size_t GCIdleTimeHandler::EstimateMarkingStepSize(
@@ -16,14 +18,13 @@
   DCHECK(idle_time_in_ms > 0);

   if (marking_speed_in_bytes_per_ms == 0) {
-    marking_speed_in_bytes_per_ms =
-        GCIdleTimeHandler::kInitialConservativeMarkingSpeed;
+    marking_speed_in_bytes_per_ms = kInitialConservativeMarkingSpeed;
   }

size_t marking_step_size = marking_speed_in_bytes_per_ms * idle_time_in_ms; if (marking_step_size / marking_speed_in_bytes_per_ms != idle_time_in_ms) {
     // In the case of an overflow we return maximum marking step size.
-    return GCIdleTimeHandler::kMaximumMarkingStepSize;
+    return kMaximumMarkingStepSize;
   }

   if (marking_step_size > kMaximumMarkingStepSize)
@@ -32,5 +33,51 @@
   return static_cast<size_t>(marking_step_size *
                              GCIdleTimeHandler::kConservativeTimeRatio);
 }
+
+
+size_t GCIdleTimeHandler::EstimateMarkCompactTime(
+    size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms) {
+  if (mark_compact_speed_in_bytes_per_ms == 0) {
+ mark_compact_speed_in_bytes_per_ms = kInitialConservativeMarkCompactSpeed;
+  }
+  size_t result = size_of_objects / mark_compact_speed_in_bytes_per_ms;
+  return Min(result, kMaxMarkCompactTimeInMs);
+}
+
+
+GCIdleTimeAction GCIdleTimeHandler::Compute(int idle_time_in_ms,
+                                            int contexts_disposed,
+                                            size_t size_of_objects,
+ bool incremental_marking_stopped,
+                                            GCTracer* gc_tracer) {
+  if (IsIdleRoundFinished()) {
+    if (EnoughGarbageSinceLastIdleRound() || contexts_disposed > 0) {
+      StartIdleRound();
+    } else {
+      return GCIdleTimeAction::Nothing();
+    }
+  }
+  if (incremental_marking_stopped) {
+    size_t speed =
+ static_cast<size_t>(gc_tracer->MarkCompactSpeedInBytesPerMillisecond());
+    if (idle_time_in_ms >=
+ static_cast<int>(EstimateMarkCompactTime(size_of_objects, speed))) { + // If there are no more than two GCs left in this idle round and we are + // allowed to do a full GC, then make those GCs full in order to compact
+      // the code space.
+ // TODO(ulan): Once we enable code compaction for incremental marking, we + // can get rid of this special case and always start incremental marking.
+      int remaining_mark_sweeps =
+ kMaxMarkCompactsInIdleRound - mark_compacts_since_idle_round_started_;
+      if (contexts_disposed > 0 || remaining_mark_sweeps <= 2) {
+        return GCIdleTimeAction::FullGC();
+      }
+    }
+  }
+ intptr_t speed = gc_tracer->IncrementalMarkingSpeedInBytesPerMillisecond();
+  size_t step_size =
+      static_cast<size_t>(EstimateMarkingStepSize(idle_time_in_ms, speed));
+  return GCIdleTimeAction::IncrementalMarking(step_size);
+}
 }
 }
=======================================
--- /branches/bleeding_edge/src/heap/gc-idle-time-handler.h Wed Aug 20 15:37:43 2014 UTC +++ /branches/bleeding_edge/src/heap/gc-idle-time-handler.h Thu Aug 21 14:42:22 2014 UTC
@@ -10,13 +10,51 @@
 namespace v8 {
 namespace internal {

+enum GCIdleTimeActionType {
+  DO_NOTHING,
+  DO_INCREMENTAL_MARKING,
+  DO_SCAVENGE,
+  DO_FULL_GC
+};
+
+
+class GCIdleTimeAction {
+ public:
+  static GCIdleTimeAction Nothing() {
+    GCIdleTimeAction result;
+    result.type = DO_NOTHING;
+    result.parameter = 0;
+    return result;
+  }
+  static GCIdleTimeAction IncrementalMarking(intptr_t step_size) {
+    GCIdleTimeAction result;
+    result.type = DO_INCREMENTAL_MARKING;
+    result.parameter = step_size;
+    return result;
+  }
+  static GCIdleTimeAction Scavenge() {
+    GCIdleTimeAction result;
+    result.type = DO_SCAVENGE;
+    result.parameter = 0;
+    return result;
+  }
+  static GCIdleTimeAction FullGC() {
+    GCIdleTimeAction result;
+    result.type = DO_FULL_GC;
+    result.parameter = 0;
+    return result;
+  }
+
+  GCIdleTimeActionType type;
+  intptr_t parameter;
+};
+
+class GCTracer;
+
 // The idle time handler makes decisions about which garbage collection
 // operations are executing during IdleNotification.
 class GCIdleTimeHandler {
  public:
-  static size_t EstimateMarkingStepSize(size_t idle_time_in_ms,
- size_t marking_speed_in_bytes_per_ms);
-
// If we haven't recorded any incremental marking events yet, we carefully
   // mark with a conservative lower bound for the marking speed.
   static const size_t kInitialConservativeMarkingSpeed = 100 * KB;
@@ -28,7 +66,55 @@
   // idle_time_in_ms. Hence, we conservatively prune our workload estimate.
   static const double kConservativeTimeRatio;

+  // If we haven't recorded any mark-compact events yet, we use
+  // conservative lower bound for the mark-compact speed.
+  static const size_t kInitialConservativeMarkCompactSpeed = 2 * MB;
+
+  // Maximum mark-compact time returned by EstimateMarkCompactTime.
+  static const size_t kMaxMarkCompactTimeInMs;
+
+  GCIdleTimeHandler()
+      : mark_compacts_since_idle_round_started_(0),
+        scavenges_since_last_idle_round_(0) {}
+
+  GCIdleTimeAction Compute(int idle_time_in_ms, int contexts_disposed,
+                           size_t size_of_objects,
+                           bool incremental_marking_stopped,
+                           GCTracer* gc_tracer);
+
+  void NotifyIdleMarkCompact() {
+ if (mark_compacts_since_idle_round_started_ < kMaxMarkCompactsInIdleRound) {
+      ++mark_compacts_since_idle_round_started_;
+      if (mark_compacts_since_idle_round_started_ ==
+          kMaxMarkCompactsInIdleRound) {
+        scavenges_since_last_idle_round_ = 0;
+      }
+    }
+  }
+
+  void NotifyScavenge() { ++scavenges_since_last_idle_round_; }
+
+  static size_t EstimateMarkingStepSize(size_t idle_time_in_ms,
+ size_t marking_speed_in_bytes_per_ms);
+
+  static size_t EstimateMarkCompactTime(
+      size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms);
+
  private:
+  void StartIdleRound() { mark_compacts_since_idle_round_started_ = 0; }
+  bool IsIdleRoundFinished() {
+    return mark_compacts_since_idle_round_started_ ==
+           kMaxMarkCompactsInIdleRound;
+  }
+  bool EnoughGarbageSinceLastIdleRound() {
+    return scavenges_since_last_idle_round_ >= kIdleScavengeThreshold;
+  }
+
+  static const int kMaxMarkCompactsInIdleRound = 7;
+  static const int kIdleScavengeThreshold = 5;
+  int mark_compacts_since_idle_round_started_;
+  int scavenges_since_last_idle_round_;
+
   DISALLOW_COPY_AND_ASSIGN(GCIdleTimeHandler);
 };

=======================================
--- /branches/bleeding_edge/src/heap/gc-tracer.cc Tue Aug 19 12:07:59 2014 UTC +++ /branches/bleeding_edge/src/heap/gc-tracer.cc Thu Aug 21 14:42:22 2014 UTC
@@ -413,6 +413,23 @@
     durations += iter->end_time - iter->start_time;
     ++iter;
   }
+
+  if (durations == 0.0) return 0;
+
+  return static_cast<intptr_t>(bytes / durations);
+}
+
+
+intptr_t GCTracer::MarkCompactSpeedInBytesPerMillisecond() const {
+  intptr_t bytes = 0;
+  double durations = 0.0;
+  EventBuffer::const_iterator iter = mark_compactor_events_.begin();
+  while (iter != mark_compactor_events_.end()) {
+    bytes += iter->start_object_size;
+    durations += iter->end_time - iter->start_time +
+                 iter->pure_incremental_marking_duration;
+    ++iter;
+  }

   if (durations == 0.0) return 0;

=======================================
--- /branches/bleeding_edge/src/heap/gc-tracer.h Tue Aug 19 12:07:59 2014 UTC +++ /branches/bleeding_edge/src/heap/gc-tracer.h Thu Aug 21 14:42:22 2014 UTC
@@ -5,6 +5,8 @@
 #ifndef V8_HEAP_GC_TRACER_H_
 #define V8_HEAP_GC_TRACER_H_

+#include "src/base/platform/platform.h"
+
 namespace v8 {
 namespace internal {

@@ -81,9 +83,9 @@
 // GCTracer collects and prints ONE line after each garbage collector
 // invocation IFF --trace_gc is used.
 // TODO(ernstm): Unit tests.
-class GCTracer BASE_EMBEDDED {
+class GCTracer {
  public:
-  class Scope BASE_EMBEDDED {
+  class Scope {
    public:
     enum ScopeId {
       EXTERNAL,
@@ -291,6 +293,10 @@
   // Returns 0 if no events have been recorded.
   intptr_t ScavengeSpeedInBytesPerMillisecond() const;

+  // Compute the max mark-sweep speed in bytes/millisecond.
+  // Returns 0 if no events have been recorded.
+  intptr_t MarkCompactSpeedInBytesPerMillisecond() const;
+
  private:
   // Print one detailed trace line in name=value format.
   // TODO(ernstm): Move to Heap.
=======================================
--- /branches/bleeding_edge/src/heap/heap.cc    Thu Aug 21 12:39:33 2014 UTC
+++ /branches/bleeding_edge/src/heap/heap.cc    Thu Aug 21 14:42:22 2014 UTC
@@ -120,12 +120,7 @@
       store_buffer_(this),
       marking_(this),
       incremental_marking_(this),
-      number_idle_notifications_(0),
-      last_idle_notification_gc_count_(0),
-      last_idle_notification_gc_count_init_(false),
-      mark_sweeps_since_idle_round_started_(0),
       gc_count_at_last_idle_gc_(0),
-      scavenges_since_last_idle_round_(kIdleScavengeThreshold),
       full_codegen_bytes_generated_(0),
       crankshaft_codegen_bytes_generated_(0),
       gcs_since_last_deopt_(0),
@@ -1559,7 +1554,7 @@

   gc_state_ = NOT_IN_GC;

-  scavenges_since_last_idle_round_++;
+  gc_idle_time_handler_.NotifyScavenge();
 }


@@ -4265,12 +4260,7 @@
 }


-void Heap::AdvanceIdleIncrementalMarking(int idle_time_in_ms) {
-  intptr_t step_size =
-      static_cast<size_t>(GCIdleTimeHandler::EstimateMarkingStepSize(
-          idle_time_in_ms,
-          tracer_.IncrementalMarkingSpeedInBytesPerMillisecond()));
-
+void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
   incremental_marking()->Step(step_size,
IncrementalMarking::NO_GC_VIA_STACK_GUARD, true);

@@ -4283,7 +4273,7 @@
     }
     CollectAllGarbage(kReduceMemoryFootprintMask,
                       "idle notification: finalize incremental");
-    mark_sweeps_since_idle_round_started_++;
+    gc_idle_time_handler_.NotifyIdleMarkCompact();
     gc_count_at_last_idle_gc_ = gc_count_;
     if (uncommit) {
       new_space_.Shrink();
@@ -4296,83 +4286,49 @@
 bool Heap::IdleNotification(int idle_time_in_ms) {
   // If incremental marking is off, we do not perform idle notification.
   if (!FLAG_incremental_marking) return true;
-
-  // Minimal hint that allows to do full GC.
-  const int kMinHintForFullGC = 100;
   isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample(
       idle_time_in_ms);
   HistogramTimerScope idle_notification_scope(
       isolate_->counters()->gc_idle_notification());

-  if (contexts_disposed_ > 0) {
-    contexts_disposed_ = 0;
-    int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
-    if (idle_time_in_ms >= mark_sweep_time && !FLAG_expose_gc &&
-        incremental_marking()->IsStopped()) {
+  GCIdleTimeAction action = gc_idle_time_handler_.Compute(
+ idle_time_in_ms, contexts_disposed_, static_cast<size_t>(SizeOfObjects()),
+      incremental_marking()->IsStopped(), tracer());
+  contexts_disposed_ = 0;
+  bool result = false;
+  switch (action.type) {
+    case DO_INCREMENTAL_MARKING:
+      if (incremental_marking()->IsStopped()) {
+        incremental_marking()->Start();
+      }
+      AdvanceIdleIncrementalMarking(action.parameter);
+      break;
+    case DO_FULL_GC: {
       HistogramTimerScope scope(isolate_->counters()->gc_context());
-      CollectAllGarbage(kReduceMemoryFootprintMask,
-                        "idle notification: contexts disposed");
-    } else {
-      AdvanceIdleIncrementalMarking(idle_time_in_ms);
-    }
-
- // After context disposal there is likely a lot of garbage remaining, reset - // the idle notification counters in order to trigger more incremental GCs
-    // on subsequent idle notifications.
-    StartIdleRound();
-    return false;
-  }
-
-  // By doing small chunks of GC work in each IdleNotification,
-  // perform a round of incremental GCs and after that wait until
-  // the mutator creates enough garbage to justify a new round.
-  // An incremental GC progresses as follows:
-  // 1. many incremental marking steps,
-  // 2. one old space mark-sweep-compact,
-  // Use mark-sweep-compact events to count incremental GCs in a round.
-
-  if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
-    if (EnoughGarbageSinceLastIdleRound()) {
-      StartIdleRound();
-    } else {
-      return true;
+      const char* message = contexts_disposed_
+                                ? "idle notification: contexts disposed"
+                                : "idle notification: finalize idle round";
+      CollectAllGarbage(kReduceMemoryFootprintMask, message);
+      gc_idle_time_handler_.NotifyIdleMarkCompact();
+      break;
     }
+    case DO_SCAVENGE:
+      CollectGarbage(NEW_SPACE, "idle notification: scavenge");
+      break;
+    case DO_NOTHING:
+      result = true;
+      break;
   }
-
-  int remaining_mark_sweeps =
-      kMaxMarkSweepsInIdleRound - mark_sweeps_since_idle_round_started_;
-
-  if (incremental_marking()->IsStopped()) {
-    // If there are no more than two GCs left in this idle round and we are
- // allowed to do a full GC, then make those GCs full in order to compact
-    // the code space.
-    // TODO(ulan): Once we enable code compaction for incremental marking,
- // we can get rid of this special case and always start incremental marking. - if (remaining_mark_sweeps <= 2 && idle_time_in_ms >= kMinHintForFullGC) {
-      CollectAllGarbage(kReduceMemoryFootprintMask,
-                        "idle notification: finalize idle round");
-      mark_sweeps_since_idle_round_started_++;
-    } else {
-      incremental_marking()->Start();
-    }
-  }
-  if (!incremental_marking()->IsStopped()) {
-    AdvanceIdleIncrementalMarking(idle_time_in_ms);
-  }
-
-  if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
-    FinishIdleRound();
-    return true;
-  }
-
   // If the IdleNotifcation is called with a large hint we will wait for
   // the sweepter threads here.
+  // TODO(ulan): move this in GCIdleTimeHandler.
+  const int kMinHintForFullGC = 100;
   if (idle_time_in_ms >= kMinHintForFullGC &&
       mark_compact_collector()->sweeping_in_progress()) {
     mark_compact_collector()->EnsureSweepingCompleted();
   }

-  return false;
+  return result;
 }


=======================================
--- /branches/bleeding_edge/src/heap/heap.h     Thu Aug 21 12:39:33 2014 UTC
+++ /branches/bleeding_edge/src/heap/heap.h     Thu Aug 21 14:42:22 2014 UTC
@@ -11,6 +11,7 @@
 #include "src/assert-scope.h"
 #include "src/counters.h"
 #include "src/globals.h"
+#include "src/heap/gc-idle-time-handler.h"
 #include "src/heap/gc-tracer.h"
 #include "src/heap/incremental-marking.h"
 #include "src/heap/mark-compact.h"
@@ -1929,30 +1930,7 @@

   void SelectScavengingVisitorsTable();

-  void StartIdleRound() { mark_sweeps_since_idle_round_started_ = 0; }
-
-  void FinishIdleRound() {
-    mark_sweeps_since_idle_round_started_ = kMaxMarkSweepsInIdleRound;
-    scavenges_since_last_idle_round_ = 0;
-  }
-
-  bool EnoughGarbageSinceLastIdleRound() {
-    return (scavenges_since_last_idle_round_ >= kIdleScavengeThreshold);
-  }
-
-  // Estimates how many milliseconds a Mark-Sweep would take to complete.
-  // In idle notification handler we assume that this function will return:
-  // - a number less than 10 for small heaps, which are less than 8Mb.
- // - a number greater than 10 for large heaps, which are greater than 32Mb.
-  int TimeMarkSweepWouldTakeInMs() {
- // Rough estimate of how many megabytes of heap can be processed in 1 ms.
-    static const int kMbPerMs = 2;
-
-    int heap_size_mb = static_cast<int>(SizeOfObjects() / MB);
-    return heap_size_mb / kMbPerMs;
-  }
-
-  void AdvanceIdleIncrementalMarking(int idle_time_in_ms);
+  void AdvanceIdleIncrementalMarking(intptr_t step_size);

   void ClearObjectStats(bool clear_last_time_stats = false);

@@ -2005,13 +1983,8 @@

   IncrementalMarking incremental_marking_;

-  int number_idle_notifications_;
-  unsigned int last_idle_notification_gc_count_;
-  bool last_idle_notification_gc_count_init_;
-
-  int mark_sweeps_since_idle_round_started_;
+  GCIdleTimeHandler gc_idle_time_handler_;
   unsigned int gc_count_at_last_idle_gc_;
-  int scavenges_since_last_idle_round_;

   // These two counters are monotomically increasing and never reset.
   size_t full_codegen_bytes_generated_;
@@ -2029,7 +2002,7 @@
   static const int kAllocationSiteScratchpadSize = 256;
   int allocation_sites_scratchpad_length_;

-  static const int kMaxMarkSweepsInIdleRound = 7;
+  static const int kMaxMarkCompactsInIdleRound = 7;
   static const int kIdleScavengeThreshold = 5;

   // Shared state read by the scavenge collector and set by ScavengeObject.
=======================================
--- /branches/bleeding_edge/test/heap-unittests/heap-unittest.cc Wed Aug 20 15:37:43 2014 UTC +++ /branches/bleeding_edge/test/heap-unittests/heap-unittest.cc Thu Aug 21 14:42:22 2014 UTC
@@ -44,6 +44,30 @@
EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
             step_size);
 }
+
+
+TEST(EstimateMarkCompactTimeTest, EstimateMarkCompactTimeInitial) {
+  size_t size = 100 * MB;
+  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, 0);
+  EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeMarkCompactSpeed,
+            time);
+}
+
+
+TEST(EstimateMarkCompactTimeTest, EstimateMarkCompactTimeNonZero) {
+  size_t size = 100 * MB;
+  size_t speed = 10 * KB;
+  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
+  EXPECT_EQ(size / speed, time);
+}
+
+
+TEST(EstimateMarkCompactTimeTest, EstimateMarkCompactTimeMax) {
+  size_t size = std::numeric_limits<size_t>::max();
+  size_t speed = 1;
+  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
+  EXPECT_EQ(GCIdleTimeHandler::kMaxMarkCompactTimeInMs, time);
+}

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