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 #ifndef V8_HEAP_GC_IDLE_TIME_HANDLER_H_
6 #define V8_HEAP_GC_IDLE_TIME_HANDLER_H_
7 
8 #include "src/globals.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 enum GCIdleTimeActionType {
14   DONE,
15   DO_NOTHING,
16   DO_INCREMENTAL_STEP,
17   DO_FULL_GC,
18 };
19 
20 
21 class GCIdleTimeAction {
22  public:
Done()23   static GCIdleTimeAction Done() {
24     GCIdleTimeAction result;
25     result.type = DONE;
26     result.additional_work = false;
27     return result;
28   }
29 
Nothing()30   static GCIdleTimeAction Nothing() {
31     GCIdleTimeAction result;
32     result.type = DO_NOTHING;
33     result.additional_work = false;
34     return result;
35   }
36 
IncrementalStep()37   static GCIdleTimeAction IncrementalStep() {
38     GCIdleTimeAction result;
39     result.type = DO_INCREMENTAL_STEP;
40     result.additional_work = false;
41     return result;
42   }
43 
FullGC()44   static GCIdleTimeAction FullGC() {
45     GCIdleTimeAction result;
46     result.type = DO_FULL_GC;
47     result.additional_work = false;
48     return result;
49   }
50 
51   void Print();
52 
53   GCIdleTimeActionType type;
54   bool additional_work;
55 };
56 
57 
58 class GCIdleTimeHeapState {
59  public:
60   void Print();
61 
62   int contexts_disposed;
63   double contexts_disposal_rate;
64   size_t size_of_objects;
65   bool incremental_marking_stopped;
66 };
67 
68 
69 // The idle time handler makes decisions about which garbage collection
70 // operations are executing during IdleNotification.
71 class GCIdleTimeHandler {
72  public:
73   // If we haven't recorded any incremental marking events yet, we carefully
74   // mark with a conservative lower bound for the marking speed.
75   static const size_t kInitialConservativeMarkingSpeed = 100 * KB;
76 
77   // Maximum marking step size returned by EstimateMarkingStepSize.
78   static const size_t kMaximumMarkingStepSize = 700 * MB;
79 
80   // We have to make sure that we finish the IdleNotification before
81   // idle_time_in_ms. Hence, we conservatively prune our workload estimate.
82   static const double kConservativeTimeRatio;
83 
84   // If we haven't recorded any mark-compact events yet, we use
85   // conservative lower bound for the mark-compact speed.
86   static const size_t kInitialConservativeMarkCompactSpeed = 2 * MB;
87 
88   // If we haven't recorded any final incremental mark-compact events yet, we
89   // use conservative lower bound for the mark-compact speed.
90   static const size_t kInitialConservativeFinalIncrementalMarkCompactSpeed =
91       2 * MB;
92 
93   // Maximum mark-compact time returned by EstimateMarkCompactTime.
94   static const size_t kMaxMarkCompactTimeInMs;
95 
96   // Maximum final incremental mark-compact time returned by
97   // EstimateFinalIncrementalMarkCompactTime.
98   static const size_t kMaxFinalIncrementalMarkCompactTimeInMs;
99 
100   // This is the maximum scheduled idle time. Note that it can be more than
101   // 16.66 ms when there is currently no rendering going on.
102   static const size_t kMaxScheduledIdleTime = 50;
103 
104   // The maximum idle time when frames are rendered is 16.66ms.
105   static const size_t kMaxFrameRenderingIdleTime = 17;
106 
107   static const int kMinBackgroundIdleTime = 900;
108 
109   // An allocation throughput below kLowAllocationThroughput bytes/ms is
110   // considered low
111   static const size_t kLowAllocationThroughput = 1000;
112 
113   // If contexts are disposed at a higher rate a full gc is triggered.
114   static const double kHighContextDisposalRate;
115 
116   // Incremental marking step time.
117   static const size_t kIncrementalMarkingStepTimeInMs = 1;
118 
119   static const size_t kMinTimeForOverApproximatingWeakClosureInMs;
120 
121   // Number of times we will return a Nothing action in the current mode
122   // despite having idle time available before we returning a Done action to
123   // ensure we don't keep scheduling idle tasks and making no progress.
124   static const int kMaxNoProgressIdleTimes = 10;
125 
GCIdleTimeHandler()126   GCIdleTimeHandler() : idle_times_which_made_no_progress_(0) {}
127 
128   GCIdleTimeAction Compute(double idle_time_in_ms,
129                            GCIdleTimeHeapState heap_state);
130 
ResetNoProgressCounter()131   void ResetNoProgressCounter() { idle_times_which_made_no_progress_ = 0; }
132 
133   static size_t EstimateMarkingStepSize(size_t idle_time_in_ms,
134                                         size_t marking_speed_in_bytes_per_ms);
135 
136   static size_t EstimateMarkCompactTime(
137       size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms);
138 
139   static size_t EstimateFinalIncrementalMarkCompactTime(
140       size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms);
141 
142   static bool ShouldDoMarkCompact(size_t idle_time_in_ms,
143                                   size_t size_of_objects,
144                                   size_t mark_compact_speed_in_bytes_per_ms);
145 
146   static bool ShouldDoContextDisposalMarkCompact(int context_disposed,
147                                                  double contexts_disposal_rate);
148 
149   static bool ShouldDoFinalIncrementalMarkCompact(
150       size_t idle_time_in_ms, size_t size_of_objects,
151       size_t final_incremental_mark_compact_speed_in_bytes_per_ms);
152 
153   static bool ShouldDoOverApproximateWeakClosure(size_t idle_time_in_ms);
154 
155  private:
156   GCIdleTimeAction NothingOrDone(double idle_time_in_ms);
157 
158   // Idle notifications with no progress.
159   int idle_times_which_made_no_progress_;
160 
161   DISALLOW_COPY_AND_ASSIGN(GCIdleTimeHandler);
162 };
163 
164 }  // namespace internal
165 }  // namespace v8
166 
167 #endif  // V8_HEAP_GC_IDLE_TIME_HANDLER_H_
168