Home | History | Annotate | Download | only in heap
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/heap/gc-idle-time-handler.h"
      6 
      7 #include "src/flags.h"
      8 #include "src/heap/gc-tracer.h"
      9 #include "src/utils.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 const double GCIdleTimeHandler::kConservativeTimeRatio = 0.9;
     15 const size_t GCIdleTimeHandler::kMaxFinalIncrementalMarkCompactTimeInMs = 1000;
     16 const double GCIdleTimeHandler::kHighContextDisposalRate = 100;
     17 const size_t GCIdleTimeHandler::kMinTimeForOverApproximatingWeakClosureInMs = 1;
     18 
     19 
     20 void GCIdleTimeAction::Print() {
     21   switch (type) {
     22     case DONE:
     23       PrintF("done");
     24       break;
     25     case DO_NOTHING:
     26       PrintF("no action");
     27       break;
     28     case DO_INCREMENTAL_STEP:
     29       PrintF("incremental step");
     30       if (additional_work) {
     31         PrintF("; finalized marking");
     32       }
     33       break;
     34     case DO_FULL_GC:
     35       PrintF("full GC");
     36       break;
     37   }
     38 }
     39 
     40 
     41 void GCIdleTimeHeapState::Print() {
     42   PrintF("contexts_disposed=%d ", contexts_disposed);
     43   PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate);
     44   PrintF("size_of_objects=%" PRIuS " ", size_of_objects);
     45   PrintF("incremental_marking_stopped=%d ", incremental_marking_stopped);
     46 }
     47 
     48 size_t GCIdleTimeHandler::EstimateMarkingStepSize(
     49     double idle_time_in_ms, double marking_speed_in_bytes_per_ms) {
     50   DCHECK(idle_time_in_ms > 0);
     51 
     52   if (marking_speed_in_bytes_per_ms == 0) {
     53     marking_speed_in_bytes_per_ms = kInitialConservativeMarkingSpeed;
     54   }
     55 
     56   double marking_step_size = marking_speed_in_bytes_per_ms * idle_time_in_ms;
     57   if (marking_step_size >= kMaximumMarkingStepSize) {
     58     return kMaximumMarkingStepSize;
     59   }
     60   return static_cast<size_t>(marking_step_size * kConservativeTimeRatio);
     61 }
     62 
     63 double GCIdleTimeHandler::EstimateFinalIncrementalMarkCompactTime(
     64     size_t size_of_objects,
     65     double final_incremental_mark_compact_speed_in_bytes_per_ms) {
     66   if (final_incremental_mark_compact_speed_in_bytes_per_ms == 0) {
     67     final_incremental_mark_compact_speed_in_bytes_per_ms =
     68         kInitialConservativeFinalIncrementalMarkCompactSpeed;
     69   }
     70   double result =
     71       size_of_objects / final_incremental_mark_compact_speed_in_bytes_per_ms;
     72   return Min<double>(result, kMaxFinalIncrementalMarkCompactTimeInMs);
     73 }
     74 
     75 bool GCIdleTimeHandler::ShouldDoContextDisposalMarkCompact(
     76     int contexts_disposed, double contexts_disposal_rate) {
     77   return contexts_disposed > 0 && contexts_disposal_rate > 0 &&
     78          contexts_disposal_rate < kHighContextDisposalRate;
     79 }
     80 
     81 bool GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
     82     double idle_time_in_ms, size_t size_of_objects,
     83     double final_incremental_mark_compact_speed_in_bytes_per_ms) {
     84   return idle_time_in_ms >=
     85          EstimateFinalIncrementalMarkCompactTime(
     86              size_of_objects,
     87              final_incremental_mark_compact_speed_in_bytes_per_ms);
     88 }
     89 
     90 bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure(
     91     double idle_time_in_ms) {
     92   // TODO(jochen): Estimate the time it will take to build the object groups.
     93   return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs;
     94 }
     95 
     96 
     97 GCIdleTimeAction GCIdleTimeHandler::NothingOrDone(double idle_time_in_ms) {
     98   if (idle_time_in_ms >= kMinBackgroundIdleTime) {
     99     return GCIdleTimeAction::Nothing();
    100   }
    101   if (idle_times_which_made_no_progress_ >= kMaxNoProgressIdleTimes) {
    102     return GCIdleTimeAction::Done();
    103   } else {
    104     idle_times_which_made_no_progress_++;
    105     return GCIdleTimeAction::Nothing();
    106   }
    107 }
    108 
    109 
    110 // The following logic is implemented by the controller:
    111 // (1) If we don't have any idle time, do nothing, unless a context was
    112 // disposed, incremental marking is stopped, and the heap is small. Then do
    113 // a full GC.
    114 // (2) If the context disposal rate is high and we cannot perform a full GC,
    115 // we do nothing until the context disposal rate becomes lower.
    116 // (3) If the new space is almost full and we can affort a scavenge or if the
    117 // next scavenge will very likely take long, then a scavenge is performed.
    118 // (4) If sweeping is in progress and we received a large enough idle time
    119 // request, we finalize sweeping here.
    120 // (5) If incremental marking is in progress, we perform a marking step. Note,
    121 // that this currently may trigger a full garbage collection.
    122 GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
    123                                             GCIdleTimeHeapState heap_state) {
    124   if (static_cast<int>(idle_time_in_ms) <= 0) {
    125     if (heap_state.incremental_marking_stopped) {
    126       if (ShouldDoContextDisposalMarkCompact(
    127               heap_state.contexts_disposed,
    128               heap_state.contexts_disposal_rate)) {
    129         return GCIdleTimeAction::FullGC();
    130       }
    131     }
    132     return GCIdleTimeAction::Nothing();
    133   }
    134 
    135   // We are in a context disposal GC scenario. Don't do anything if we do not
    136   // get the right idle signal.
    137   if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed,
    138                                          heap_state.contexts_disposal_rate)) {
    139     return NothingOrDone(idle_time_in_ms);
    140   }
    141 
    142   if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) {
    143     return GCIdleTimeAction::Done();
    144   }
    145 
    146   return GCIdleTimeAction::IncrementalStep();
    147 }
    148 
    149 bool GCIdleTimeHandler::Enabled() { return FLAG_incremental_marking; }
    150 
    151 }  // namespace internal
    152 }  // namespace v8
    153