Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/heap/gc-idle-time-handler.h"
6 :
7 : #include "src/flags.h"
8 : #include "src/heap/gc-tracer.h"
9 : #include "src/utils.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 : const double GCIdleTimeHandler::kConservativeTimeRatio = 0.9;
15 : const size_t GCIdleTimeHandler::kMaxFinalIncrementalMarkCompactTimeInMs = 1000;
16 : const double GCIdleTimeHandler::kHighContextDisposalRate = 100;
17 : const size_t GCIdleTimeHandler::kMinTimeForOverApproximatingWeakClosureInMs = 1;
18 :
19 :
20 0 : void GCIdleTimeAction::Print() {
21 0 : switch (type) {
22 : case DONE:
23 0 : PrintF("done");
24 0 : break;
25 : case DO_NOTHING:
26 0 : PrintF("no action");
27 0 : break;
28 : case DO_INCREMENTAL_STEP:
29 0 : PrintF("incremental step");
30 0 : if (additional_work) {
31 0 : PrintF("; finalized marking");
32 : }
33 : break;
34 : case DO_FULL_GC:
35 0 : PrintF("full GC");
36 0 : break;
37 : }
38 0 : }
39 :
40 :
41 0 : void GCIdleTimeHeapState::Print() {
42 0 : PrintF("contexts_disposed=%d ", contexts_disposed);
43 0 : PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate);
44 0 : PrintF("size_of_objects=%" PRIuS " ", size_of_objects);
45 0 : PrintF("incremental_marking_stopped=%d ", incremental_marking_stopped);
46 0 : }
47 :
48 1300493 : size_t GCIdleTimeHandler::EstimateMarkingStepSize(
49 : double idle_time_in_ms, double marking_speed_in_bytes_per_ms) {
50 : DCHECK_LT(0, idle_time_in_ms);
51 :
52 1300493 : if (marking_speed_in_bytes_per_ms == 0) {
53 : marking_speed_in_bytes_per_ms = kInitialConservativeMarkingSpeed;
54 : }
55 :
56 1300493 : double marking_step_size = marking_speed_in_bytes_per_ms * idle_time_in_ms;
57 1300493 : if (marking_step_size >= kMaximumMarkingStepSize) {
58 : return kMaximumMarkingStepSize;
59 : }
60 1300486 : return static_cast<size_t>(marking_step_size * kConservativeTimeRatio);
61 : }
62 :
63 0 : double GCIdleTimeHandler::EstimateFinalIncrementalMarkCompactTime(
64 : size_t size_of_objects,
65 : double final_incremental_mark_compact_speed_in_bytes_per_ms) {
66 2 : if (final_incremental_mark_compact_speed_in_bytes_per_ms == 0) {
67 : final_incremental_mark_compact_speed_in_bytes_per_ms =
68 : kInitialConservativeFinalIncrementalMarkCompactSpeed;
69 : }
70 : double result =
71 2 : size_of_objects / final_incremental_mark_compact_speed_in_bytes_per_ms;
72 0 : return Min<double>(result, kMaxFinalIncrementalMarkCompactTimeInMs);
73 : }
74 :
75 0 : bool GCIdleTimeHandler::ShouldDoContextDisposalMarkCompact(
76 : int contexts_disposed, double contexts_disposal_rate,
77 : size_t size_of_objects) {
78 418 : return contexts_disposed > 0 && contexts_disposal_rate > 0 &&
79 726 : contexts_disposal_rate < kHighContextDisposalRate &&
80 0 : size_of_objects <= kMaxHeapSizeForContextDisposalMarkCompact;
81 : }
82 :
83 2 : bool GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
84 : double idle_time_in_ms, size_t size_of_objects,
85 : double final_incremental_mark_compact_speed_in_bytes_per_ms) {
86 : return idle_time_in_ms >=
87 : EstimateFinalIncrementalMarkCompactTime(
88 : size_of_objects,
89 2 : final_incremental_mark_compact_speed_in_bytes_per_ms);
90 : }
91 :
92 0 : bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure(
93 : double idle_time_in_ms) {
94 : // TODO(jochen): Estimate the time it will take to build the object groups.
95 0 : return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs;
96 : }
97 :
98 :
99 0 : GCIdleTimeAction GCIdleTimeHandler::NothingOrDone(double idle_time_in_ms) {
100 0 : if (idle_time_in_ms >= kMinBackgroundIdleTime) {
101 : return GCIdleTimeAction::Nothing();
102 : }
103 0 : if (idle_times_which_made_no_progress_ >= kMaxNoProgressIdleTimes) {
104 : return GCIdleTimeAction::Done();
105 : } else {
106 0 : idle_times_which_made_no_progress_++;
107 : return GCIdleTimeAction::Nothing();
108 : }
109 : }
110 :
111 :
112 : // The following logic is implemented by the controller:
113 : // (1) If we don't have any idle time, do nothing, unless a context was
114 : // disposed, incremental marking is stopped, and the heap is small. Then do
115 : // a full GC.
116 : // (2) If the context disposal rate is high and we cannot perform a full GC,
117 : // we do nothing until the context disposal rate becomes lower.
118 : // (3) If the new space is almost full and we can afford a scavenge or if the
119 : // next scavenge will very likely take long, then a scavenge is performed.
120 : // (4) If sweeping is in progress and we received a large enough idle time
121 : // request, we finalize sweeping here.
122 : // (5) If incremental marking is in progress, we perform a marking step. Note,
123 : // that this currently may trigger a full garbage collection.
124 672 : GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
125 : GCIdleTimeHeapState heap_state) {
126 672 : if (static_cast<int>(idle_time_in_ms) <= 0) {
127 401 : if (heap_state.incremental_marking_stopped) {
128 268 : if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed,
129 : heap_state.contexts_disposal_rate,
130 : heap_state.size_of_objects)) {
131 : return GCIdleTimeAction::FullGC();
132 : }
133 : }
134 : return GCIdleTimeAction::Nothing();
135 : }
136 :
137 : // We are in a context disposal GC scenario. Don't do anything if we do not
138 : // get the right idle signal.
139 271 : if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed,
140 : heap_state.contexts_disposal_rate,
141 : heap_state.size_of_objects)) {
142 : return NothingOrDone(idle_time_in_ms);
143 : }
144 :
145 271 : if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) {
146 : return GCIdleTimeAction::Done();
147 : }
148 :
149 : return GCIdleTimeAction::IncrementalStep();
150 : }
151 :
152 13 : bool GCIdleTimeHandler::Enabled() { return FLAG_incremental_marking; }
153 :
154 : } // namespace internal
155 183867 : } // namespace v8
|