OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/heap/gc-idle-time-handler.h" | 5 #include "src/heap/gc-idle-time-handler.h" |
6 | 6 |
7 #include "src/flags.h" | 7 #include "src/flags.h" |
8 #include "src/heap/gc-tracer.h" | 8 #include "src/heap/gc-tracer.h" |
9 #include "src/utils.h" | 9 #include "src/utils.h" |
10 | 10 |
(...skipping 14 matching lines...) Expand all Loading... |
25 break; | 25 break; |
26 case DO_NOTHING: | 26 case DO_NOTHING: |
27 PrintF("no action"); | 27 PrintF("no action"); |
28 break; | 28 break; |
29 case DO_INCREMENTAL_STEP: | 29 case DO_INCREMENTAL_STEP: |
30 PrintF("incremental step"); | 30 PrintF("incremental step"); |
31 if (additional_work) { | 31 if (additional_work) { |
32 PrintF("; finalized marking"); | 32 PrintF("; finalized marking"); |
33 } | 33 } |
34 break; | 34 break; |
35 case DO_SCAVENGE: | |
36 PrintF("scavenge"); | |
37 break; | |
38 case DO_FULL_GC: | 35 case DO_FULL_GC: |
39 PrintF("full GC"); | 36 PrintF("full GC"); |
40 break; | 37 break; |
41 } | 38 } |
42 } | 39 } |
43 | 40 |
44 | 41 |
45 void GCIdleTimeHeapState::Print() { | 42 void GCIdleTimeHeapState::Print() { |
46 PrintF("contexts_disposed=%d ", contexts_disposed); | 43 PrintF("contexts_disposed=%d ", contexts_disposed); |
47 PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate); | 44 PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate); |
48 PrintF("size_of_objects=%" V8_PTR_PREFIX "d ", size_of_objects); | 45 PrintF("size_of_objects=%" V8_PTR_PREFIX "d ", size_of_objects); |
49 PrintF("incremental_marking_stopped=%d ", incremental_marking_stopped); | 46 PrintF("incremental_marking_stopped=%d ", incremental_marking_stopped); |
50 PrintF("sweeping_in_progress=%d ", sweeping_in_progress); | 47 PrintF("sweeping_in_progress=%d ", sweeping_in_progress); |
51 PrintF("has_low_allocation_rate=%d", has_low_allocation_rate); | 48 PrintF("has_low_allocation_rate=%d", has_low_allocation_rate); |
52 PrintF("mark_compact_speed=%" V8_PTR_PREFIX "d ", | 49 PrintF("mark_compact_speed=%" V8_PTR_PREFIX "d ", |
53 mark_compact_speed_in_bytes_per_ms); | 50 mark_compact_speed_in_bytes_per_ms); |
54 PrintF("incremental_marking_speed=%" V8_PTR_PREFIX "d ", | 51 PrintF("incremental_marking_speed=%" V8_PTR_PREFIX "d ", |
55 incremental_marking_speed_in_bytes_per_ms); | 52 incremental_marking_speed_in_bytes_per_ms); |
56 PrintF("scavenge_speed=%" V8_PTR_PREFIX "d ", scavenge_speed_in_bytes_per_ms); | |
57 PrintF("new_space_size=%" V8_PTR_PREFIX "d ", used_new_space_size); | |
58 PrintF("new_space_capacity=%" V8_PTR_PREFIX "d ", new_space_capacity); | |
59 PrintF("new_space_allocation_throughput=%" V8_PTR_PREFIX "d ", | |
60 new_space_allocation_throughput_in_bytes_per_ms); | |
61 } | 53 } |
62 | 54 |
63 | 55 |
64 size_t GCIdleTimeHandler::EstimateMarkingStepSize( | 56 size_t GCIdleTimeHandler::EstimateMarkingStepSize( |
65 size_t idle_time_in_ms, size_t marking_speed_in_bytes_per_ms) { | 57 size_t idle_time_in_ms, size_t marking_speed_in_bytes_per_ms) { |
66 DCHECK(idle_time_in_ms > 0); | 58 DCHECK(idle_time_in_ms > 0); |
67 | 59 |
68 if (marking_speed_in_bytes_per_ms == 0) { | 60 if (marking_speed_in_bytes_per_ms == 0) { |
69 marking_speed_in_bytes_per_ms = kInitialConservativeMarkingSpeed; | 61 marking_speed_in_bytes_per_ms = kInitialConservativeMarkingSpeed; |
70 } | 62 } |
(...skipping 29 matching lines...) Expand all Loading... |
100 if (final_incremental_mark_compact_speed_in_bytes_per_ms == 0) { | 92 if (final_incremental_mark_compact_speed_in_bytes_per_ms == 0) { |
101 final_incremental_mark_compact_speed_in_bytes_per_ms = | 93 final_incremental_mark_compact_speed_in_bytes_per_ms = |
102 kInitialConservativeFinalIncrementalMarkCompactSpeed; | 94 kInitialConservativeFinalIncrementalMarkCompactSpeed; |
103 } | 95 } |
104 size_t result = | 96 size_t result = |
105 size_of_objects / final_incremental_mark_compact_speed_in_bytes_per_ms; | 97 size_of_objects / final_incremental_mark_compact_speed_in_bytes_per_ms; |
106 return Min(result, kMaxFinalIncrementalMarkCompactTimeInMs); | 98 return Min(result, kMaxFinalIncrementalMarkCompactTimeInMs); |
107 } | 99 } |
108 | 100 |
109 | 101 |
110 bool GCIdleTimeHandler::ShouldDoScavenge( | |
111 size_t idle_time_in_ms, size_t new_space_size, size_t used_new_space_size, | |
112 size_t scavenge_speed_in_bytes_per_ms, | |
113 size_t new_space_allocation_throughput_in_bytes_per_ms) { | |
114 if (idle_time_in_ms >= kMinBackgroundIdleTime) { | |
115 // It is better to do full GC for the background tab. | |
116 return false; | |
117 } | |
118 | |
119 // Calculates how much memory are we able to scavenge in | |
120 // kMaxFrameRenderingIdleTime ms. If scavenge_speed_in_bytes_per_ms is 0 we | |
121 // will take care of this later. | |
122 size_t idle_new_space_allocation_limit = | |
123 kMaxFrameRenderingIdleTime * scavenge_speed_in_bytes_per_ms; | |
124 | |
125 // If the limit is larger than the new space size, then scavenging used to be | |
126 // really fast. We can take advantage of the whole new space. | |
127 if (idle_new_space_allocation_limit > new_space_size) { | |
128 idle_new_space_allocation_limit = new_space_size; | |
129 } | |
130 | |
131 // We do not know the allocation throughput before the first scavenge. | |
132 // TODO(hpayer): Estimate allocation throughput before the first scavenge. | |
133 if (new_space_allocation_throughput_in_bytes_per_ms > 0) { | |
134 // We have to trigger scavenge before we reach the end of new space. | |
135 size_t adjust_limit = new_space_allocation_throughput_in_bytes_per_ms * | |
136 kTimeUntilNextIdleEvent; | |
137 if (adjust_limit > idle_new_space_allocation_limit) { | |
138 idle_new_space_allocation_limit = 0; | |
139 } else { | |
140 idle_new_space_allocation_limit -= adjust_limit; | |
141 } | |
142 } | |
143 | |
144 // The allocated new space limit to trigger a scavange has to be at least | |
145 // kMinimumNewSpaceSizeToPerformScavenge. | |
146 if (idle_new_space_allocation_limit < kMinimumNewSpaceSizeToPerformScavenge) { | |
147 idle_new_space_allocation_limit = kMinimumNewSpaceSizeToPerformScavenge; | |
148 } | |
149 | |
150 // Set an initial scavenge speed if it is unknown. | |
151 if (scavenge_speed_in_bytes_per_ms == 0) { | |
152 scavenge_speed_in_bytes_per_ms = kInitialConservativeScavengeSpeed; | |
153 } | |
154 | |
155 // We apply a max factor to the new space size to make sure that a slowly | |
156 // allocating application still leaves enough of wiggle room to schedule a | |
157 // scavenge. | |
158 size_t max_limit; | |
159 const double kMaxNewSpaceSizeFactorLongIdleTimes = 0.5; | |
160 const double kMaxNewSpaceSizeFactorShortIdleTimes = 0.8; | |
161 if (idle_time_in_ms > kMaxFrameRenderingIdleTime) { | |
162 max_limit = static_cast<size_t>(new_space_size * | |
163 kMaxNewSpaceSizeFactorLongIdleTimes); | |
164 } else { | |
165 max_limit = static_cast<size_t>(new_space_size * | |
166 kMaxNewSpaceSizeFactorShortIdleTimes); | |
167 } | |
168 idle_new_space_allocation_limit = | |
169 Min(idle_new_space_allocation_limit, max_limit); | |
170 | |
171 // We perform a scavenge if we are over the idle new space limit and | |
172 // a scavenge fits into the given idle time bucket. | |
173 if (idle_new_space_allocation_limit <= used_new_space_size) { | |
174 if (used_new_space_size / scavenge_speed_in_bytes_per_ms <= | |
175 idle_time_in_ms) { | |
176 return true; | |
177 } | |
178 } | |
179 return false; | |
180 } | |
181 | |
182 | |
183 bool GCIdleTimeHandler::ShouldDoMarkCompact( | 102 bool GCIdleTimeHandler::ShouldDoMarkCompact( |
184 size_t idle_time_in_ms, size_t size_of_objects, | 103 size_t idle_time_in_ms, size_t size_of_objects, |
185 size_t mark_compact_speed_in_bytes_per_ms) { | 104 size_t mark_compact_speed_in_bytes_per_ms) { |
186 return idle_time_in_ms >= kMaxScheduledIdleTime && | 105 return idle_time_in_ms >= kMaxScheduledIdleTime && |
187 idle_time_in_ms >= | 106 idle_time_in_ms >= |
188 EstimateMarkCompactTime(size_of_objects, | 107 EstimateMarkCompactTime(size_of_objects, |
189 mark_compact_speed_in_bytes_per_ms); | 108 mark_compact_speed_in_bytes_per_ms); |
190 } | 109 } |
191 | 110 |
192 | 111 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 return GCIdleTimeAction::Nothing(); | 171 return GCIdleTimeAction::Nothing(); |
253 } | 172 } |
254 | 173 |
255 // We are in a context disposal GC scenario. Don't do anything if we do not | 174 // We are in a context disposal GC scenario. Don't do anything if we do not |
256 // get the right idle signal. | 175 // get the right idle signal. |
257 if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed, | 176 if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed, |
258 heap_state.contexts_disposal_rate)) { | 177 heap_state.contexts_disposal_rate)) { |
259 return NothingOrDone(idle_time_in_ms); | 178 return NothingOrDone(idle_time_in_ms); |
260 } | 179 } |
261 | 180 |
262 if (ShouldDoScavenge( | |
263 static_cast<size_t>(idle_time_in_ms), heap_state.new_space_capacity, | |
264 heap_state.used_new_space_size, | |
265 heap_state.scavenge_speed_in_bytes_per_ms, | |
266 heap_state.new_space_allocation_throughput_in_bytes_per_ms)) { | |
267 return GCIdleTimeAction::Scavenge(); | |
268 } | |
269 | |
270 if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) { | 181 if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) { |
271 return GCIdleTimeAction::Done(); | 182 return GCIdleTimeAction::Done(); |
272 } | 183 } |
273 | 184 |
274 return GCIdleTimeAction::IncrementalStep(); | 185 return GCIdleTimeAction::IncrementalStep(); |
275 } | 186 } |
276 | 187 |
277 | 188 |
278 } | 189 } |
279 } | 190 } |
OLD | NEW |