1e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org// Copyright 2014 the V8 project authors. All rights reserved.
2e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org// Use of this source code is governed by a BSD-style license that can be
3e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org// found in the LICENSE file.
4e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org
5e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org#include "src/heap/gc-idle-time-handler.h"
6a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org#include "src/heap/gc-tracer.h"
7a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org#include "src/utils.h"
8e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org
9e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.orgnamespace v8 {
10e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.orgnamespace internal {
11e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org
12e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.orgconst double GCIdleTimeHandler::kConservativeTimeRatio = 0.9;
139e2b466e4b4a2026caefa79afe6737f1bad83a19machenbach@chromium.orgconst size_t GCIdleTimeHandler::kMaxMarkCompactTimeInMs = 1000;
14a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.orgconst size_t GCIdleTimeHandler::kMinTimeForFinalizeSweeping = 100;
15a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.orgconst int GCIdleTimeHandler::kMaxMarkCompactsInIdleRound = 7;
16a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.orgconst int GCIdleTimeHandler::kIdleScavengeThreshold = 5;
17e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org
18e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org
19ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.orgvoid GCIdleTimeAction::Print() {
20ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org  switch (type) {
21d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org    case DONE:
22d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org      PrintF("done");
23d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org      break;
24ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org    case DO_NOTHING:
25ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      PrintF("no action");
26ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      break;
27ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org    case DO_INCREMENTAL_MARKING:
28ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      PrintF("incremental marking with step %" V8_PTR_PREFIX "d", parameter);
29ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      break;
30ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org    case DO_SCAVENGE:
31ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      PrintF("scavenge");
32ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      break;
33ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org    case DO_FULL_GC:
34ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      PrintF("full GC");
35ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      break;
36ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org    case DO_FINALIZE_SWEEPING:
37ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      PrintF("finalize sweeping");
38ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org      break;
39ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org  }
40ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org}
41ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org
42ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org
43e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.orgsize_t GCIdleTimeHandler::EstimateMarkingStepSize(
44e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org    size_t idle_time_in_ms, size_t marking_speed_in_bytes_per_ms) {
45e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org  DCHECK(idle_time_in_ms > 0);
46e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org
47e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org  if (marking_speed_in_bytes_per_ms == 0) {
48a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    marking_speed_in_bytes_per_ms = kInitialConservativeMarkingSpeed;
49e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org  }
50e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org
51e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org  size_t marking_step_size = marking_speed_in_bytes_per_ms * idle_time_in_ms;
52e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org  if (marking_step_size / marking_speed_in_bytes_per_ms != idle_time_in_ms) {
53e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org    // In the case of an overflow we return maximum marking step size.
54a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    return kMaximumMarkingStepSize;
55e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org  }
56e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org
57e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org  if (marking_step_size > kMaximumMarkingStepSize)
58e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org    return kMaximumMarkingStepSize;
59e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org
60a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  return static_cast<size_t>(marking_step_size * kConservativeTimeRatio);
61a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org}
62a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org
63a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org
64a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.orgsize_t GCIdleTimeHandler::EstimateMarkCompactTime(
65a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms) {
66a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  if (mark_compact_speed_in_bytes_per_ms == 0) {
67a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    mark_compact_speed_in_bytes_per_ms = kInitialConservativeMarkCompactSpeed;
68a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  }
69a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  size_t result = size_of_objects / mark_compact_speed_in_bytes_per_ms;
70a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  return Min(result, kMaxMarkCompactTimeInMs);
71a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org}
72a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org
73a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org
74d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.orgsize_t GCIdleTimeHandler::EstimateScavengeTime(
75d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org    size_t new_space_size, size_t scavenge_speed_in_bytes_per_ms) {
76d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org  if (scavenge_speed_in_bytes_per_ms == 0) {
77d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org    scavenge_speed_in_bytes_per_ms = kInitialConservativeScavengeSpeed;
78d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org  }
79d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org  return new_space_size / scavenge_speed_in_bytes_per_ms;
80d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org}
81d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org
82d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org
83a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.orgbool GCIdleTimeHandler::ScavangeMayHappenSoon(
84a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org    size_t available_new_space_memory,
85a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org    size_t new_space_allocation_throughput_in_bytes_per_ms) {
86a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org  if (available_new_space_memory <=
87a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org      new_space_allocation_throughput_in_bytes_per_ms *
88a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org          kMaxFrameRenderingIdleTime) {
89a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org    return true;
90a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org  }
91a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org  return false;
92a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org}
93a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org
94a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org
95d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// The following logic is implemented by the controller:
96d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// (1) If the new space is almost full and we can effort a Scavenge, then a
97d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// Scavenge is performed.
98d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// (2) If there is currently no MarkCompact idle round going on, we start a
99d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// new idle round if enough garbage was created or we received a context
100d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// disposal event. Otherwise we do not perform garbage collection to keep
101d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// system utilization low.
102d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// (3) If incremental marking is done, we perform a full garbage collection
103d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// if context was disposed or if we are allowed to still do full garbage
104d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// collections during this idle round or if we are not allowed to start
105d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// incremental marking. Otherwise we do not perform garbage collection to
106d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// keep system utilization low.
107d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// (4) If sweeping is in progress and we received a large enough idle time
108d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// request, we finalize sweeping here.
109d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// (5) If incremental marking is in progress, we perform a marking step. Note,
110d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org// that this currently may trigger a full garbage collection.
111a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.orgGCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
112a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org                                            HeapState heap_state) {
113a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org  if (idle_time_in_ms <= kMaxFrameRenderingIdleTime &&
114a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org      ScavangeMayHappenSoon(
115a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org          heap_state.available_new_space_memory,
116a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org          heap_state.new_space_allocation_throughput_in_bytes_per_ms) &&
117d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org      idle_time_in_ms >=
118d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org          EstimateScavengeTime(heap_state.new_space_capacity,
119d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org                               heap_state.scavenge_speed_in_bytes_per_ms)) {
120d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org    return GCIdleTimeAction::Scavenge();
121d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org  }
122d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org  if (IsMarkCompactIdleRoundFinished()) {
123a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    if (EnoughGarbageSinceLastIdleRound() || heap_state.contexts_disposed > 0) {
124a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      StartIdleRound();
125a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    } else {
126d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org      return GCIdleTimeAction::Done();
127a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    }
128a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  }
129d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org
130a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org  if (idle_time_in_ms == 0) {
131a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org    return GCIdleTimeAction::Nothing();
132a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org  }
133a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org
134a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  if (heap_state.incremental_marking_stopped) {
1359e2b466e4b4a2026caefa79afe6737f1bad83a19machenbach@chromium.org    size_t estimated_time_in_ms =
1369e2b466e4b4a2026caefa79afe6737f1bad83a19machenbach@chromium.org        EstimateMarkCompactTime(heap_state.size_of_objects,
1379e2b466e4b4a2026caefa79afe6737f1bad83a19machenbach@chromium.org                                heap_state.mark_compact_speed_in_bytes_per_ms);
1389e2b466e4b4a2026caefa79afe6737f1bad83a19machenbach@chromium.org    if (idle_time_in_ms >= estimated_time_in_ms ||
1396313e220249748eb26e1ddcee2bbe857fef03b42machenbach@chromium.org        (heap_state.size_of_objects < kSmallHeapSize &&
1406313e220249748eb26e1ddcee2bbe857fef03b42machenbach@chromium.org         heap_state.contexts_disposed > 0)) {
141a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      // If there are no more than two GCs left in this idle round and we are
142a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      // allowed to do a full GC, then make those GCs full in order to compact
143a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      // the code space.
144a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      // TODO(ulan): Once we enable code compaction for incremental marking, we
145a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      // can get rid of this special case and always start incremental marking.
146a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      int remaining_mark_sweeps =
147a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org          kMaxMarkCompactsInIdleRound - mark_compacts_since_idle_round_started_;
148d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org      if (heap_state.contexts_disposed > 0 ||
149d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org          (idle_time_in_ms > kMaxFrameRenderingIdleTime &&
150d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org           (remaining_mark_sweeps <= 2 ||
151d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org            !heap_state.can_start_incremental_marking))) {
152a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org        return GCIdleTimeAction::FullGC();
153a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      }
154a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    }
155a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    if (!heap_state.can_start_incremental_marking) {
156a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      return GCIdleTimeAction::Nothing();
157a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    }
158a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  }
159a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  // TODO(hpayer): Estimate finalize sweeping time.
160a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  if (heap_state.sweeping_in_progress &&
161a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      idle_time_in_ms >= kMinTimeForFinalizeSweeping) {
162a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org    return GCIdleTimeAction::FinalizeSweeping();
163a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  }
164a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org
165d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org  if (heap_state.incremental_marking_stopped &&
166d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org      !heap_state.can_start_incremental_marking) {
167d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org    return GCIdleTimeAction::Nothing();
168d3df75b4472c9d5d4d2615aaea74d2adce4160f8machenbach@chromium.org  }
169a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  size_t step_size = EstimateMarkingStepSize(
170a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org      idle_time_in_ms, heap_state.incremental_marking_speed_in_bytes_per_ms);
171a8702c210b949f35c64d8e4aa01bb6d525086c85machenbach@chromium.org  return GCIdleTimeAction::IncrementalMarking(step_size);
172e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org}
173e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org}
174e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org}
175