Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/heap/heap-controller.h"
6 :
7 : #include "src/heap/spaces.h"
8 : #include "src/isolate-inl.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 : // Given GC speed in bytes per ms, the allocation throughput in bytes per ms
14 : // (mutator speed), this function returns the heap growing factor that will
15 : // achieve the target_mutator_utilization_ if the GC speed and the mutator speed
16 : // remain the same until the next GC.
17 : //
18 : // For a fixed time-frame T = TM + TG, the mutator utilization is the ratio
19 : // TM / (TM + TG), where TM is the time spent in the mutator and TG is the
20 : // time spent in the garbage collector.
21 : //
22 : // Let MU be target_mutator_utilization_, the desired mutator utilization for
23 : // the time-frame from the end of the current GC to the end of the next GC.
24 : // Based on the MU we can compute the heap growing factor F as
25 : //
26 : // F = R * (1 - MU) / (R * (1 - MU) - MU), where R = gc_speed / mutator_speed.
27 : //
28 : // This formula can be derived as follows.
29 : //
30 : // F = Limit / Live by definition, where the Limit is the allocation limit,
31 : // and the Live is size of live objects.
32 : // Let’s assume that we already know the Limit. Then:
33 : // TG = Limit / gc_speed
34 : // TM = (TM + TG) * MU, by definition of MU.
35 : // TM = TG * MU / (1 - MU)
36 : // TM = Limit * MU / (gc_speed * (1 - MU))
37 : // On the other hand, if the allocation throughput remains constant:
38 : // Limit = Live + TM * allocation_throughput = Live + TM * mutator_speed
39 : // Solving it for TM, we get
40 : // TM = (Limit - Live) / mutator_speed
41 : // Combining the two equation for TM:
42 : // (Limit - Live) / mutator_speed = Limit * MU / (gc_speed * (1 - MU))
43 : // (Limit - Live) = Limit * MU * mutator_speed / (gc_speed * (1 - MU))
44 : // substitute R = gc_speed / mutator_speed
45 : // (Limit - Live) = Limit * MU / (R * (1 - MU))
46 : // substitute F = Limit / Live
47 : // F - 1 = F * MU / (R * (1 - MU))
48 : // F - F * MU / (R * (1 - MU)) = 1
49 : // F * (1 - MU / (R * (1 - MU))) = 1
50 : // F * (R * (1 - MU) - MU) / (R * (1 - MU)) = 1
51 : // F = R * (1 - MU) / (R * (1 - MU) - MU)
52 10 : double MemoryController::GrowingFactor(double gc_speed, double mutator_speed,
53 : double max_factor) {
54 : DCHECK_LE(min_growing_factor_, max_factor);
55 : DCHECK_GE(max_growing_factor_, max_factor);
56 69941 : if (gc_speed == 0 || mutator_speed == 0) return max_factor;
57 :
58 54627 : const double speed_ratio = gc_speed / mutator_speed;
59 :
60 54627 : const double a = speed_ratio * (1 - target_mutator_utilization_);
61 : const double b = speed_ratio * (1 - target_mutator_utilization_) -
62 54627 : target_mutator_utilization_;
63 :
64 : // The factor is a / b, but we need to check for small b first.
65 54627 : double factor = (a < b * max_factor) ? a / b : max_factor;
66 : factor = Min(factor, max_factor);
67 54627 : factor = Max(factor, min_growing_factor_);
68 10 : return factor;
69 : }
70 :
71 69931 : size_t MemoryController::CalculateAllocationLimit(
72 : size_t curr_size, size_t max_size, double max_factor, double gc_speed,
73 : double mutator_speed, size_t new_space_capacity,
74 : Heap::HeapGrowingMode growing_mode) {
75 : double factor = GrowingFactor(gc_speed, mutator_speed, max_factor);
76 :
77 69931 : if (FLAG_trace_gc_verbose) {
78 0 : Isolate::FromHeap(heap_)->PrintWithTimestamp(
79 : "%s factor %.1f based on mu=%.3f, speed_ratio=%.f "
80 : "(gc=%.f, mutator=%.f)\n",
81 0 : ControllerName(), factor, target_mutator_utilization_,
82 0 : gc_speed / mutator_speed, gc_speed, mutator_speed);
83 : }
84 :
85 69931 : if (growing_mode == Heap::HeapGrowingMode::kConservative ||
86 : growing_mode == Heap::HeapGrowingMode::kSlow) {
87 68 : factor = Min(factor, conservative_growing_factor_);
88 : }
89 :
90 69931 : if (growing_mode == Heap::HeapGrowingMode::kMinimal) {
91 7310 : factor = min_growing_factor_;
92 : }
93 :
94 69931 : if (FLAG_heap_growing_percent > 0) {
95 0 : factor = 1.0 + FLAG_heap_growing_percent / 100.0;
96 : }
97 :
98 69931 : CHECK_LT(1.0, factor);
99 69931 : CHECK_LT(0, curr_size);
100 69931 : uint64_t limit = static_cast<uint64_t>(curr_size * factor);
101 69931 : limit = Max(limit, static_cast<uint64_t>(curr_size) +
102 : MinimumAllocationLimitGrowingStep(growing_mode));
103 69931 : limit += new_space_capacity;
104 : uint64_t halfway_to_the_max =
105 69931 : (static_cast<uint64_t>(curr_size) + max_size) / 2;
106 : size_t result = static_cast<size_t>(Min(limit, halfway_to_the_max));
107 :
108 69931 : if (FLAG_trace_gc_verbose) {
109 0 : Isolate::FromHeap(heap_)->PrintWithTimestamp(
110 : "%s Limit: old size: %" PRIuS " KB, new limit: %" PRIuS " KB (%.1f)\n",
111 0 : ControllerName(), curr_size / KB, result / KB, factor);
112 : }
113 :
114 69931 : return result;
115 : }
116 :
117 8291 : size_t MemoryController::MinimumAllocationLimitGrowingStep(
118 : Heap::HeapGrowingMode growing_mode) {
119 : const size_t kRegularAllocationLimitGrowingStep = 8;
120 : const size_t kLowMemoryAllocationLimitGrowingStep = 2;
121 : size_t limit = (Page::kPageSize > MB ? Page::kPageSize : MB);
122 78222 : return limit * (growing_mode == Heap::HeapGrowingMode::kConservative
123 : ? kLowMemoryAllocationLimitGrowingStep
124 78222 : : kRegularAllocationLimitGrowingStep);
125 : }
126 :
127 69932 : double HeapController::MaxGrowingFactor(size_t curr_max_size) {
128 : const double min_small_factor = 1.3;
129 : const double max_small_factor = 2.0;
130 : const double high_factor = 4.0;
131 :
132 69932 : size_t max_size_in_mb = curr_max_size / MB;
133 : max_size_in_mb = Max(max_size_in_mb, kMinSize);
134 :
135 : // If we are on a device with lots of memory, we allow a high heap
136 : // growing factor.
137 69932 : if (max_size_in_mb >= kMaxSize) {
138 : return high_factor;
139 : }
140 :
141 : DCHECK_GE(max_size_in_mb, kMinSize);
142 : DCHECK_LT(max_size_in_mb, kMaxSize);
143 :
144 : // On smaller devices we linearly scale the factor: (X-A)/(B-A)*(D-C)+C
145 22719 : double factor = (max_size_in_mb - kMinSize) *
146 22719 : (max_small_factor - min_small_factor) /
147 : (kMaxSize - kMinSize) +
148 22719 : min_small_factor;
149 22719 : return factor;
150 : }
151 :
152 : } // namespace internal
153 122036 : } // namespace v8
|