OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/api.h" | 8 #include "src/api.h" |
9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/base/once.h" | 10 #include "src/base/once.h" |
(...skipping 1201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1212 } | 1212 } |
1213 | 1213 |
1214 if (collector == MARK_COMPACTOR) { | 1214 if (collector == MARK_COMPACTOR) { |
1215 UpdateOldGenerationAllocationCounter(); | 1215 UpdateOldGenerationAllocationCounter(); |
1216 // Perform mark-sweep with optional compaction. | 1216 // Perform mark-sweep with optional compaction. |
1217 MarkCompact(); | 1217 MarkCompact(); |
1218 sweep_generation_++; | 1218 sweep_generation_++; |
1219 old_gen_exhausted_ = false; | 1219 old_gen_exhausted_ = false; |
1220 old_generation_size_configured_ = true; | 1220 old_generation_size_configured_ = true; |
1221 // This should be updated before PostGarbageCollectionProcessing, which can | 1221 // This should be updated before PostGarbageCollectionProcessing, which can |
1222 // cause another GC. | 1222 // cause another GC. Take into account the objects promoted during GC. |
| 1223 old_generation_allocation_counter_ += |
| 1224 static_cast<size_t>(promoted_objects_size_); |
1223 old_generation_size_at_last_gc_ = PromotedSpaceSizeOfObjects(); | 1225 old_generation_size_at_last_gc_ = PromotedSpaceSizeOfObjects(); |
1224 } else { | 1226 } else { |
1225 Scavenge(); | 1227 Scavenge(); |
1226 } | 1228 } |
1227 | 1229 |
1228 | 1230 |
1229 UpdateSurvivalStatistics(start_new_space_size); | 1231 UpdateSurvivalStatistics(start_new_space_size); |
1230 ConfigureInitialOldGenerationSize(); | 1232 ConfigureInitialOldGenerationSize(); |
1231 | 1233 |
1232 isolate_->counters()->objs_since_last_young()->Set(0); | 1234 isolate_->counters()->objs_since_last_young()->Set(0); |
(...skipping 21 matching lines...) Expand all Loading... |
1254 | 1256 |
1255 isolate_->eternal_handles()->PostGarbageCollectionProcessing(this); | 1257 isolate_->eternal_handles()->PostGarbageCollectionProcessing(this); |
1256 | 1258 |
1257 // Update relocatables. | 1259 // Update relocatables. |
1258 Relocatable::PostGarbageCollectionProcessing(isolate_); | 1260 Relocatable::PostGarbageCollectionProcessing(isolate_); |
1259 | 1261 |
1260 if (collector == MARK_COMPACTOR) { | 1262 if (collector == MARK_COMPACTOR) { |
1261 // Register the amount of external allocated memory. | 1263 // Register the amount of external allocated memory. |
1262 amount_of_external_allocated_memory_at_last_global_gc_ = | 1264 amount_of_external_allocated_memory_at_last_global_gc_ = |
1263 amount_of_external_allocated_memory_; | 1265 amount_of_external_allocated_memory_; |
1264 SetOldGenerationAllocationLimit( | 1266 double gc_speed = tracer()->CombinedMarkCompactSpeedInBytesPerMillisecond(); |
1265 PromotedSpaceSizeOfObjects(), | 1267 double mutator_speed = static_cast<double>( |
1266 tracer()->CurrentAllocationThroughputInBytesPerMillisecond()); | 1268 tracer() |
| 1269 ->CurrentOldGenerationAllocationThroughputInBytesPerMillisecond()); |
| 1270 intptr_t old_gen_size = PromotedSpaceSizeOfObjects(); |
| 1271 SetOldGenerationAllocationLimit(old_gen_size, gc_speed, mutator_speed); |
1267 } | 1272 } |
1268 | 1273 |
1269 { | 1274 { |
1270 GCCallbacksScope scope(this); | 1275 GCCallbacksScope scope(this); |
1271 if (scope.CheckReenter()) { | 1276 if (scope.CheckReenter()) { |
1272 AllowHeapAllocation allow_allocation; | 1277 AllowHeapAllocation allow_allocation; |
1273 GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL); | 1278 GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL); |
1274 VMState<EXTERNAL> state(isolate_); | 1279 VMState<EXTERNAL> state(isolate_); |
1275 HandleScope handle_scope(isolate_); | 1280 HandleScope handle_scope(isolate_); |
1276 CallGCEpilogueCallbacks(gc_type, gc_callback_flags); | 1281 CallGCEpilogueCallbacks(gc_type, gc_callback_flags); |
(...skipping 4002 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5279 | 5284 |
5280 int64_t Heap::PromotedExternalMemorySize() { | 5285 int64_t Heap::PromotedExternalMemorySize() { |
5281 if (amount_of_external_allocated_memory_ <= | 5286 if (amount_of_external_allocated_memory_ <= |
5282 amount_of_external_allocated_memory_at_last_global_gc_) | 5287 amount_of_external_allocated_memory_at_last_global_gc_) |
5283 return 0; | 5288 return 0; |
5284 return amount_of_external_allocated_memory_ - | 5289 return amount_of_external_allocated_memory_ - |
5285 amount_of_external_allocated_memory_at_last_global_gc_; | 5290 amount_of_external_allocated_memory_at_last_global_gc_; |
5286 } | 5291 } |
5287 | 5292 |
5288 | 5293 |
| 5294 const double Heap::kMinHeapGrowingFactor = 1.1; |
| 5295 const double Heap::kMaxHeapGrowingFactor = 4.0; |
| 5296 const double Heap::kMaxHeapGrowingFactorMemoryConstrained = 2.0; |
| 5297 const double Heap::kMaxHeapGrowingFactorIdle = 1.5; |
| 5298 const double Heap::kTargetMutatorUtilization = 0.97; |
| 5299 |
| 5300 |
| 5301 // Given GC speed in bytes per ms, the allocation throughput in bytes per ms |
| 5302 // (mutator speed), this function returns the heap growing factor that will |
| 5303 // achieve the kTargetMutatorUtilisation if the GC speed and the mutator speed |
| 5304 // remain the same until the next GC. |
| 5305 // |
| 5306 // For a fixed time-frame T = TM + TG, the mutator utilization is the ratio |
| 5307 // TM / (TM + TG), where TM is the time spent in the mutator and TG is the |
| 5308 // time spent in the garbage collector. |
| 5309 // |
| 5310 // Let MU be kTargetMutatorUtilisation, the desired mutator utilization for the |
| 5311 // time-frame from the end of the current GC to the end of the next GC. Based |
| 5312 // on the MU we can compute the heap growing factor F as |
| 5313 // |
| 5314 // F = R * (1 - MU) / (R * (1 - MU) - MU), where R = gc_speed / mutator_speed. |
| 5315 // |
| 5316 // This formula can be derived as follows. |
| 5317 // |
| 5318 // F = Limit / Live by definition, where the Limit is the allocation limit, |
| 5319 // and the Live is size of live objects. |
| 5320 // Let’s assume that we already know the Limit. Then: |
| 5321 // TG = Limit / gc_speed |
| 5322 // TM = (TM + TG) * MU, by definition of MU. |
| 5323 // TM = TG * MU / (1 - MU) |
| 5324 // TM = Limit * MU / (gc_speed * (1 - MU)) |
| 5325 // On the other hand, if the allocation throughput remains constant: |
| 5326 // Limit = Live + TM * allocation_throughput = Live + TM * mutator_speed |
| 5327 // Solving it for TM, we get |
| 5328 // TM = (Limit - Live) / mutator_speed |
| 5329 // Combining the two equation for TM: |
| 5330 // (Limit - Live) / mutator_speed = Limit * MU / (gc_speed * (1 - MU)) |
| 5331 // (Limit - Live) = Limit * MU * mutator_speed / (gc_speed * (1 - MU)) |
| 5332 // substitute R = gc_speed / mutator_speed |
| 5333 // (Limit - Live) = Limit * MU / (R * (1 - MU)) |
| 5334 // substitute F = Limit / Live |
| 5335 // F - 1 = F * MU / (R * (1 - MU)) |
| 5336 // F - F * MU / (R * (1 - MU)) = 1 |
| 5337 // F * (1 - MU / (R * (1 - MU))) = 1 |
| 5338 // F * (R * (1 - MU) - MU) / (R * (1 - MU)) = 1 |
| 5339 // F = R * (1 - MU) / (R * (1 - MU) - MU) |
| 5340 double Heap::HeapGrowingFactor(double gc_speed, double mutator_speed) { |
| 5341 if (gc_speed == 0 || mutator_speed == 0) return kMaxHeapGrowingFactor; |
| 5342 |
| 5343 const double speed_ratio = gc_speed / mutator_speed; |
| 5344 const double mu = kTargetMutatorUtilization; |
| 5345 |
| 5346 const double a = speed_ratio * (1 - mu); |
| 5347 const double b = speed_ratio * (1 - mu) - mu; |
| 5348 |
| 5349 // The factor is a / b, but we need to check for small b first. |
| 5350 double factor = |
| 5351 (a < b * kMaxHeapGrowingFactor) ? a / b : kMaxHeapGrowingFactor; |
| 5352 factor = Min(factor, kMaxHeapGrowingFactor); |
| 5353 factor = Max(factor, kMinHeapGrowingFactor); |
| 5354 return factor; |
| 5355 } |
| 5356 |
| 5357 |
5289 intptr_t Heap::CalculateOldGenerationAllocationLimit(double factor, | 5358 intptr_t Heap::CalculateOldGenerationAllocationLimit(double factor, |
5290 intptr_t old_gen_size) { | 5359 intptr_t old_gen_size) { |
5291 CHECK(factor > 1.0); | 5360 CHECK(factor > 1.0); |
5292 CHECK(old_gen_size > 0); | 5361 CHECK(old_gen_size > 0); |
5293 intptr_t limit = static_cast<intptr_t>(old_gen_size * factor); | 5362 intptr_t limit = static_cast<intptr_t>(old_gen_size * factor); |
5294 limit = Max(limit, old_gen_size + kMinimumOldGenerationAllocationLimit); | 5363 limit = Max(limit, old_gen_size + kMinimumOldGenerationAllocationLimit); |
5295 limit += new_space_.Capacity(); | 5364 limit += new_space_.Capacity(); |
5296 intptr_t halfway_to_the_max = (old_gen_size + max_old_generation_size_) / 2; | 5365 intptr_t halfway_to_the_max = (old_gen_size + max_old_generation_size_) / 2; |
5297 return Min(limit, halfway_to_the_max); | 5366 return Min(limit, halfway_to_the_max); |
5298 } | 5367 } |
5299 | 5368 |
5300 | 5369 |
5301 void Heap::SetOldGenerationAllocationLimit( | 5370 void Heap::SetOldGenerationAllocationLimit(intptr_t old_gen_size, |
5302 intptr_t old_gen_size, size_t current_allocation_throughput) { | 5371 double gc_speed, |
5303 // Allocation throughput on Android devices is typically lower than on | 5372 double mutator_speed) { |
5304 // non-mobile devices. | 5373 double factor = HeapGrowingFactor(gc_speed, mutator_speed); |
5305 #if V8_OS_ANDROID | 5374 |
5306 const size_t kHighThroughput = 2500; | 5375 if (FLAG_trace_gc_verbose) { |
5307 const size_t kLowThroughput = 250; | 5376 PrintIsolate(isolate_, |
5308 #else | 5377 "Heap growing factor %.1f based on mu=%.3f, speed_ratio=%.f " |
5309 const size_t kHighThroughput = 10000; | 5378 "(gc=%.f, mutator=%.f)\n", |
5310 const size_t kLowThroughput = 1000; | 5379 factor, kTargetMutatorUtilization, gc_speed / mutator_speed, |
5311 #endif | 5380 gc_speed, mutator_speed); |
5312 const double min_scaling_factor = 1.1; | 5381 } |
5313 const double max_scaling_factor = 1.5; | 5382 |
5314 double max_factor = 4; | |
5315 const double idle_max_factor = 1.5; | |
5316 // We set the old generation growing factor to 2 to grow the heap slower on | 5383 // We set the old generation growing factor to 2 to grow the heap slower on |
5317 // memory-constrained devices. | 5384 // memory-constrained devices. |
5318 if (max_old_generation_size_ <= kMaxOldSpaceSizeMediumMemoryDevice) { | 5385 if (max_old_generation_size_ <= kMaxOldSpaceSizeMediumMemoryDevice) { |
5319 max_factor = 2; | 5386 factor = Min(factor, kMaxHeapGrowingFactorMemoryConstrained); |
5320 } | |
5321 | |
5322 double factor; | |
5323 double idle_factor; | |
5324 if (current_allocation_throughput == 0 || | |
5325 current_allocation_throughput >= kHighThroughput) { | |
5326 factor = max_factor; | |
5327 } else if (current_allocation_throughput <= kLowThroughput) { | |
5328 factor = min_scaling_factor; | |
5329 } else { | |
5330 // Compute factor using linear interpolation between points | |
5331 // (kHighThroughput, max_scaling_factor) and (kLowThroughput, min_factor). | |
5332 factor = min_scaling_factor + | |
5333 (current_allocation_throughput - kLowThroughput) * | |
5334 (max_scaling_factor - min_scaling_factor) / | |
5335 (kHighThroughput - kLowThroughput); | |
5336 } | 5387 } |
5337 | 5388 |
5338 if (FLAG_stress_compaction || | 5389 if (FLAG_stress_compaction || |
5339 mark_compact_collector()->reduce_memory_footprint_) { | 5390 mark_compact_collector()->reduce_memory_footprint_) { |
5340 factor = min_scaling_factor; | 5391 factor = kMinHeapGrowingFactor; |
5341 } | 5392 } |
5342 | 5393 |
5343 // TODO(hpayer): Investigate if idle_old_generation_allocation_limit_ is still | 5394 // TODO(hpayer): Investigate if idle_old_generation_allocation_limit_ is still |
5344 // needed after taking the allocation rate for the old generation limit into | 5395 // needed after taking the allocation rate for the old generation limit into |
5345 // account. | 5396 // account. |
5346 idle_factor = Min(factor, idle_max_factor); | 5397 double idle_factor = Min(factor, kMaxHeapGrowingFactorIdle); |
5347 | 5398 |
5348 old_generation_allocation_limit_ = | 5399 old_generation_allocation_limit_ = |
5349 CalculateOldGenerationAllocationLimit(factor, old_gen_size); | 5400 CalculateOldGenerationAllocationLimit(factor, old_gen_size); |
5350 idle_old_generation_allocation_limit_ = | 5401 idle_old_generation_allocation_limit_ = |
5351 CalculateOldGenerationAllocationLimit(idle_factor, old_gen_size); | 5402 CalculateOldGenerationAllocationLimit(idle_factor, old_gen_size); |
5352 | 5403 |
5353 if (FLAG_trace_gc_verbose) { | 5404 if (FLAG_trace_gc_verbose) { |
5354 PrintIsolate( | 5405 PrintIsolate( |
5355 isolate_, | 5406 isolate_, |
5356 "Grow: old size: %" V8_PTR_PREFIX "d KB, new limit: %" V8_PTR_PREFIX | 5407 "Grow: old size: %" V8_PTR_PREFIX "d KB, new limit: %" V8_PTR_PREFIX |
(...skipping 1216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6573 *object_type = "CODE_TYPE"; \ | 6624 *object_type = "CODE_TYPE"; \ |
6574 *object_sub_type = "CODE_AGE/" #name; \ | 6625 *object_sub_type = "CODE_AGE/" #name; \ |
6575 return true; | 6626 return true; |
6576 CODE_AGE_LIST_COMPLETE(COMPARE_AND_RETURN_NAME) | 6627 CODE_AGE_LIST_COMPLETE(COMPARE_AND_RETURN_NAME) |
6577 #undef COMPARE_AND_RETURN_NAME | 6628 #undef COMPARE_AND_RETURN_NAME |
6578 } | 6629 } |
6579 return false; | 6630 return false; |
6580 } | 6631 } |
6581 } // namespace internal | 6632 } // namespace internal |
6582 } // namespace v8 | 6633 } // namespace v8 |
OLD | NEW |