V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
gc-idle-time-handler.cc
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 void GCIdleTimeAction::Print() {
21  switch (type) {
22  case DONE:
23  PrintF("done");
24  break;
25  case DO_NOTHING:
26  PrintF("no action");
27  break;
28  case DO_INCREMENTAL_STEP:
29  PrintF("incremental step");
30  if (additional_work) {
31  PrintF("; finalized marking");
32  }
33  break;
34  case DO_FULL_GC:
35  PrintF("full GC");
36  break;
37  }
38 }
39 
40 
41 void GCIdleTimeHeapState::Print() {
42  PrintF("contexts_disposed=%d ", contexts_disposed);
43  PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate);
44  PrintF("size_of_objects=%" PRIuS " ", size_of_objects);
45  PrintF("incremental_marking_stopped=%d ", incremental_marking_stopped);
46 }
47 
48 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  if (marking_speed_in_bytes_per_ms == 0) {
53  marking_speed_in_bytes_per_ms = kInitialConservativeMarkingSpeed;
54  }
55 
56  double marking_step_size = marking_speed_in_bytes_per_ms * idle_time_in_ms;
57  if (marking_step_size >= kMaximumMarkingStepSize) {
58  return kMaximumMarkingStepSize;
59  }
60  return static_cast<size_t>(marking_step_size * kConservativeTimeRatio);
61 }
62 
63 double GCIdleTimeHandler::EstimateFinalIncrementalMarkCompactTime(
64  size_t size_of_objects,
65  double final_incremental_mark_compact_speed_in_bytes_per_ms) {
66  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  size_of_objects / final_incremental_mark_compact_speed_in_bytes_per_ms;
72  return Min<double>(result, kMaxFinalIncrementalMarkCompactTimeInMs);
73 }
74 
75 bool GCIdleTimeHandler::ShouldDoContextDisposalMarkCompact(
76  int contexts_disposed, double contexts_disposal_rate,
77  size_t size_of_objects) {
78  return contexts_disposed > 0 && contexts_disposal_rate > 0 &&
79  contexts_disposal_rate < kHighContextDisposalRate &&
80  size_of_objects <= kMaxHeapSizeForContextDisposalMarkCompact;
81 }
82 
83 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  final_incremental_mark_compact_speed_in_bytes_per_ms);
90 }
91 
92 bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure(
93  double idle_time_in_ms) {
94  // TODO(jochen): Estimate the time it will take to build the object groups.
95  return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs;
96 }
97 
98 
99 GCIdleTimeAction GCIdleTimeHandler::NothingOrDone(double idle_time_in_ms) {
100  if (idle_time_in_ms >= kMinBackgroundIdleTime) {
101  return GCIdleTimeAction::Nothing();
102  }
103  if (idle_times_which_made_no_progress_ >= kMaxNoProgressIdleTimes) {
104  return GCIdleTimeAction::Done();
105  } else {
106  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 GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
125  GCIdleTimeHeapState heap_state) {
126  if (static_cast<int>(idle_time_in_ms) <= 0) {
127  if (heap_state.incremental_marking_stopped) {
128  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  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  if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) {
146  return GCIdleTimeAction::Done();
147  }
148 
149  return GCIdleTimeAction::IncrementalStep();
150 }
151 
152 bool GCIdleTimeHandler::Enabled() { return FLAG_incremental_marking; }
153 
154 } // namespace internal
155 } // namespace v8
Definition: libplatform.h:13