Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(95)

Side by Side Diff: src/heap/heap.cc

Issue 1163143009: Compute the heap growing factor based on mutator utilization and allocation throughput. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add missing file Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/heap/heap.h ('k') | test/unittests/heap/heap-unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/heap/heap.h ('k') | test/unittests/heap/heap-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698