f77c015bf5bef1530e062e91b8f74dd280905b07
[platform/upstream/v8.git] / src / heap / gc-idle-time-handler.cc
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::kMaxMarkCompactTimeInMs = 1000;
16 const size_t GCIdleTimeHandler::kMaxFinalIncrementalMarkCompactTimeInMs = 1000;
17 const double GCIdleTimeHandler::kHighContextDisposalRate = 100;
18 const size_t GCIdleTimeHandler::kMinTimeForOverApproximatingWeakClosureInMs = 1;
19
20
21 void GCIdleTimeAction::Print() {
22   switch (type) {
23     case DONE:
24       PrintF("done");
25       break;
26     case DO_NOTHING:
27       PrintF("no action");
28       break;
29     case DO_INCREMENTAL_STEP:
30       PrintF("incremental step");
31       if (additional_work) {
32         PrintF("; finalized marking");
33       }
34       break;
35     case DO_FULL_GC:
36       PrintF("full GC");
37       break;
38   }
39 }
40
41
42 void GCIdleTimeHeapState::Print() {
43   PrintF("contexts_disposed=%d ", contexts_disposed);
44   PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate);
45   PrintF("size_of_objects=%" V8_PTR_PREFIX "d ", size_of_objects);
46   PrintF("incremental_marking_stopped=%d ", incremental_marking_stopped);
47   PrintF("sweeping_in_progress=%d ", sweeping_in_progress);
48   PrintF("has_low_allocation_rate=%d", has_low_allocation_rate);
49   PrintF("mark_compact_speed=%" V8_PTR_PREFIX "d ",
50          mark_compact_speed_in_bytes_per_ms);
51   PrintF("incremental_marking_speed=%" V8_PTR_PREFIX "d ",
52          incremental_marking_speed_in_bytes_per_ms);
53 }
54
55
56 size_t GCIdleTimeHandler::EstimateMarkingStepSize(
57     size_t idle_time_in_ms, size_t marking_speed_in_bytes_per_ms) {
58   DCHECK(idle_time_in_ms > 0);
59
60   if (marking_speed_in_bytes_per_ms == 0) {
61     marking_speed_in_bytes_per_ms = kInitialConservativeMarkingSpeed;
62   }
63
64   size_t marking_step_size = marking_speed_in_bytes_per_ms * idle_time_in_ms;
65   if (marking_step_size / marking_speed_in_bytes_per_ms != idle_time_in_ms) {
66     // In the case of an overflow we return maximum marking step size.
67     return kMaximumMarkingStepSize;
68   }
69
70   if (marking_step_size > kMaximumMarkingStepSize)
71     return kMaximumMarkingStepSize;
72
73   return static_cast<size_t>(marking_step_size * kConservativeTimeRatio);
74 }
75
76
77 size_t GCIdleTimeHandler::EstimateMarkCompactTime(
78     size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms) {
79   // TODO(hpayer): Be more precise about the type of mark-compact event. It
80   // makes a huge difference if compaction is happening.
81   if (mark_compact_speed_in_bytes_per_ms == 0) {
82     mark_compact_speed_in_bytes_per_ms = kInitialConservativeMarkCompactSpeed;
83   }
84   size_t result = size_of_objects / mark_compact_speed_in_bytes_per_ms;
85   return Min(result, kMaxMarkCompactTimeInMs);
86 }
87
88
89 size_t GCIdleTimeHandler::EstimateFinalIncrementalMarkCompactTime(
90     size_t size_of_objects,
91     size_t final_incremental_mark_compact_speed_in_bytes_per_ms) {
92   if (final_incremental_mark_compact_speed_in_bytes_per_ms == 0) {
93     final_incremental_mark_compact_speed_in_bytes_per_ms =
94         kInitialConservativeFinalIncrementalMarkCompactSpeed;
95   }
96   size_t result =
97       size_of_objects / final_incremental_mark_compact_speed_in_bytes_per_ms;
98   return Min(result, kMaxFinalIncrementalMarkCompactTimeInMs);
99 }
100
101
102 bool GCIdleTimeHandler::ShouldDoMarkCompact(
103     size_t idle_time_in_ms, size_t size_of_objects,
104     size_t mark_compact_speed_in_bytes_per_ms) {
105   return idle_time_in_ms >= kMaxScheduledIdleTime &&
106          idle_time_in_ms >=
107              EstimateMarkCompactTime(size_of_objects,
108                                      mark_compact_speed_in_bytes_per_ms);
109 }
110
111
112 bool GCIdleTimeHandler::ShouldDoContextDisposalMarkCompact(
113     int contexts_disposed, double contexts_disposal_rate) {
114   return contexts_disposed > 0 && contexts_disposal_rate > 0 &&
115          contexts_disposal_rate < kHighContextDisposalRate;
116 }
117
118
119 bool GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
120     size_t idle_time_in_ms, size_t size_of_objects,
121     size_t final_incremental_mark_compact_speed_in_bytes_per_ms) {
122   return idle_time_in_ms >=
123          EstimateFinalIncrementalMarkCompactTime(
124              size_of_objects,
125              final_incremental_mark_compact_speed_in_bytes_per_ms);
126 }
127
128
129 bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure(
130     size_t idle_time_in_ms) {
131   // TODO(jochen): Estimate the time it will take to build the object groups.
132   return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs;
133 }
134
135
136 GCIdleTimeAction GCIdleTimeHandler::NothingOrDone(double idle_time_in_ms) {
137   if (idle_time_in_ms >= kMinBackgroundIdleTime) {
138     return GCIdleTimeAction::Nothing();
139   }
140   if (idle_times_which_made_no_progress_ >= kMaxNoProgressIdleTimes) {
141     return GCIdleTimeAction::Done();
142   } else {
143     idle_times_which_made_no_progress_++;
144     return GCIdleTimeAction::Nothing();
145   }
146 }
147
148
149 // The following logic is implemented by the controller:
150 // (1) If we don't have any idle time, do nothing, unless a context was
151 // disposed, incremental marking is stopped, and the heap is small. Then do
152 // a full GC.
153 // (2) If the context disposal rate is high and we cannot perform a full GC,
154 // we do nothing until the context disposal rate becomes lower.
155 // (3) If the new space is almost full and we can affort a scavenge or if the
156 // next scavenge will very likely take long, then a scavenge is performed.
157 // (4) If sweeping is in progress and we received a large enough idle time
158 // request, we finalize sweeping here.
159 // (5) If incremental marking is in progress, we perform a marking step. Note,
160 // that this currently may trigger a full garbage collection.
161 GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
162                                             GCIdleTimeHeapState heap_state) {
163   if (static_cast<int>(idle_time_in_ms) <= 0) {
164     if (heap_state.incremental_marking_stopped) {
165       if (ShouldDoContextDisposalMarkCompact(
166               heap_state.contexts_disposed,
167               heap_state.contexts_disposal_rate)) {
168         return GCIdleTimeAction::FullGC();
169       }
170     }
171     return GCIdleTimeAction::Nothing();
172   }
173
174   // We are in a context disposal GC scenario. Don't do anything if we do not
175   // get the right idle signal.
176   if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed,
177                                          heap_state.contexts_disposal_rate)) {
178     return NothingOrDone(idle_time_in_ms);
179   }
180
181   if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) {
182     return GCIdleTimeAction::Done();
183   }
184
185   return GCIdleTimeAction::IncrementalStep();
186 }
187
188
189 }
190 }