OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/pages.h" | 5 #include "vm/pages.h" |
6 | 6 |
7 #include "platform/assert.h" | 7 #include "platform/assert.h" |
8 #include "vm/compiler_stats.h" | 8 #include "vm/compiler_stats.h" |
9 #include "vm/gc_marker.h" | 9 #include "vm/gc_marker.h" |
10 #include "vm/gc_sweeper.h" | 10 #include "vm/gc_sweeper.h" |
(...skipping 1135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1146 grow_heap_); | 1146 grow_heap_); |
1147 } | 1147 } |
1148 return needs_gc; | 1148 return needs_gc; |
1149 } | 1149 } |
1150 | 1150 |
1151 | 1151 |
1152 void PageSpaceController::EvaluateGarbageCollection( | 1152 void PageSpaceController::EvaluateGarbageCollection( |
1153 SpaceUsage before, SpaceUsage after, int64_t start, int64_t end) { | 1153 SpaceUsage before, SpaceUsage after, int64_t start, int64_t end) { |
1154 ASSERT(end >= start); | 1154 ASSERT(end >= start); |
1155 history_.AddGarbageCollectionTime(start, end); | 1155 history_.AddGarbageCollectionTime(start, end); |
1156 int gc_time_fraction = history_.GarbageCollectionTimeFraction(); | 1156 const int gc_time_fraction = history_.GarbageCollectionTimeFraction(); |
1157 heap_->RecordData(PageSpace::kGCTimeFraction, gc_time_fraction); | 1157 heap_->RecordData(PageSpace::kGCTimeFraction, gc_time_fraction); |
1158 | 1158 |
1159 // Assume garbage increases linearly with allocation: | 1159 // Assume garbage increases linearly with allocation: |
1160 // G = kA, and estimate k from the previous cycle. | 1160 // G = kA, and estimate k from the previous cycle. |
1161 intptr_t allocated_since_previous_gc = | 1161 const intptr_t allocated_since_previous_gc = |
1162 before.used_in_words - last_usage_.used_in_words; | 1162 before.used_in_words - last_usage_.used_in_words; |
1163 intptr_t garbage = before.used_in_words - after.used_in_words; | 1163 ASSERT(allocated_since_previous_gc > 0); |
1164 double k = garbage / static_cast<double>(allocated_since_previous_gc); | 1164 const intptr_t garbage = before.used_in_words - after.used_in_words; |
1165 heap_->RecordData(PageSpace::kGarbageRatio, static_cast<int>(k * 100)); | 1165 ASSERT(garbage >= 0); |
| 1166 const double k = garbage / static_cast<double>(allocated_since_previous_gc); |
| 1167 const int garbage_ratio = static_cast<int>(k * 100); |
| 1168 heap_->RecordData(PageSpace::kGarbageRatio, garbage_ratio); |
1166 | 1169 |
1167 // Define GC to be 'worthwhile' iff at least fraction t of heap is garbage. | 1170 // Define GC to be 'worthwhile' iff at least fraction t of heap is garbage. |
1168 double t = 1.0 - desired_utilization_; | 1171 double t = 1.0 - desired_utilization_; |
1169 // If we spend too much time in GC, strive for even more free space. | 1172 // If we spend too much time in GC, strive for even more free space. |
1170 if (gc_time_fraction > garbage_collection_time_ratio_) { | 1173 if (gc_time_fraction > garbage_collection_time_ratio_) { |
1171 t += (gc_time_fraction - garbage_collection_time_ratio_) / 100.0; | 1174 t += (gc_time_fraction - garbage_collection_time_ratio_) / 100.0; |
1172 } | 1175 } |
1173 | 1176 |
1174 // Find minimum 'grow_heap_' such that after increasing capacity by | 1177 const intptr_t grow_ratio = ( |
1175 // 'grow_heap_' pages and filling them, we expect a GC to be worthwhile. | 1178 static_cast<intptr_t>(after.capacity_in_words / desired_utilization_) - |
1176 for (grow_heap_ = 0; grow_heap_ < heap_growth_max_; ++grow_heap_) { | 1179 after.capacity_in_words) / PageSpace::kPageSizeInWords; |
1177 intptr_t limit = | 1180 if (garbage_ratio == 0) { |
1178 after.capacity_in_words + (grow_heap_ * PageSpace::kPageSizeInWords); | 1181 // No garbage in the previous cycle so it would be hard to compute a |
1179 intptr_t allocated_before_next_gc = limit - after.used_in_words; | 1182 // grow_heap_ size based on estimated garbage so we use growth ratio |
1180 double estimated_garbage = k * allocated_before_next_gc; | 1183 // heuristics instead. |
1181 if (t <= estimated_garbage / limit) { | 1184 grow_heap_ = Utils::Maximum(static_cast<intptr_t>(heap_growth_max_), |
1182 break; | 1185 grow_ratio); |
| 1186 } else { |
| 1187 // Find minimum 'grow_heap_' such that after increasing capacity by |
| 1188 // 'grow_heap_' pages and filling them, we expect a GC to be worthwhile. |
| 1189 intptr_t max = heap_growth_max_; |
| 1190 intptr_t min = 0; |
| 1191 intptr_t adjustment = 0; |
| 1192 intptr_t local_grow_heap = 0; |
| 1193 while (min < max) { |
| 1194 local_grow_heap = (max + min) / 2; |
| 1195 const intptr_t limit = |
| 1196 after.capacity_in_words + (grow_heap_ * PageSpace::kPageSizeInWords); |
| 1197 const intptr_t allocated_before_next_gc = limit - after.used_in_words; |
| 1198 const double estimated_garbage = k * allocated_before_next_gc; |
| 1199 if (t <= estimated_garbage / limit) { |
| 1200 max = local_grow_heap - 1; |
| 1201 adjustment = -1; |
| 1202 } else { |
| 1203 min = local_grow_heap + 1; |
| 1204 adjustment = 1; |
| 1205 } |
| 1206 } |
| 1207 grow_heap_ = local_grow_heap + adjustment; |
| 1208 ASSERT(grow_heap_ >= 0); |
| 1209 // If we are going to grow by heap_grow_max_ then ensure that we |
| 1210 // will be growing the heap at least by the growth ratio heuristics. |
| 1211 if ((grow_heap_ == heap_growth_max_) && (grow_ratio > grow_heap_)) { |
| 1212 grow_heap_ = grow_ratio; |
1183 } | 1213 } |
1184 } | 1214 } |
1185 heap_->RecordData(PageSpace::kPageGrowth, grow_heap_); | 1215 heap_->RecordData(PageSpace::kPageGrowth, grow_heap_); |
1186 | 1216 |
1187 // Limit shrinkage: allow growth by at least half the pages freed by GC. | 1217 // Limit shrinkage: allow growth by at least half the pages freed by GC. |
1188 intptr_t freed_pages = | 1218 const intptr_t freed_pages = |
1189 (before.capacity_in_words - after.capacity_in_words) / | 1219 (before.capacity_in_words - after.capacity_in_words) / |
1190 PageSpace::kPageSizeInWords; | 1220 PageSpace::kPageSizeInWords; |
1191 grow_heap_ = Utils::Maximum(grow_heap_, freed_pages / 2); | 1221 grow_heap_ = Utils::Maximum(grow_heap_, freed_pages / 2); |
1192 heap_->RecordData(PageSpace::kAllowedGrowth, grow_heap_); | 1222 heap_->RecordData(PageSpace::kAllowedGrowth, grow_heap_); |
1193 last_usage_ = after; | 1223 last_usage_ = after; |
1194 } | 1224 } |
1195 | 1225 |
1196 | 1226 |
1197 void PageSpaceGarbageCollectionHistory:: | 1227 void PageSpaceGarbageCollectionHistory:: |
1198 AddGarbageCollectionTime(int64_t start, int64_t end) { | 1228 AddGarbageCollectionTime(int64_t start, int64_t end) { |
(...skipping 17 matching lines...) Expand all Loading... |
1216 return 0; | 1246 return 0; |
1217 } else { | 1247 } else { |
1218 ASSERT(total_time >= gc_time); | 1248 ASSERT(total_time >= gc_time); |
1219 int result = static_cast<int>((static_cast<double>(gc_time) / | 1249 int result = static_cast<int>((static_cast<double>(gc_time) / |
1220 static_cast<double>(total_time)) * 100); | 1250 static_cast<double>(total_time)) * 100); |
1221 return result; | 1251 return result; |
1222 } | 1252 } |
1223 } | 1253 } |
1224 | 1254 |
1225 } // namespace dart | 1255 } // namespace dart |
OLD | NEW |