OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_HEAP_memory_reducer_H | 5 #ifndef V8_HEAP_memory_reducer_H |
6 #define V8_HEAP_memory_reducer_H | 6 #define V8_HEAP_memory_reducer_H |
7 | 7 |
8 #include "include/v8-platform.h" | 8 #include "include/v8-platform.h" |
9 #include "src/base/macros.h" | 9 #include "src/base/macros.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 | 13 |
14 class Heap; | 14 class Heap; |
15 | 15 |
16 | 16 |
17 // The goal of the MemoryReducer class is to detect transition of the mutator | 17 // The goal of the MemoryReducer class is to detect transition of the mutator |
18 // from high allocation phase to low allocation phase and to collect potential | 18 // from high allocation phase to low allocation phase and to collect potential |
19 // garbage created in the high allocation phase. | 19 // garbage created in the high allocation phase. |
20 // | 20 // |
21 // The class implements an automaton with the following states and transitions. | 21 // The class implements an automaton with the following states and transitions. |
22 // | 22 // |
23 // States: | 23 // States: |
24 // - DONE | 24 // - DONE <last_gc_time_ms> |
25 // - WAIT <started_gcs> <next_gc_start_ms> | 25 // - WAIT <started_gcs> <next_gc_start_ms> <last_gc_time_ms> |
26 // - RUN <started_gcs> | 26 // - RUN <started_gcs> <last_gc_time_ms> |
27 // The <started_gcs> is an integer in range from 0..kMaxNumberOfGCs that stores | 27 // The <started_gcs> is an integer in range from 0..kMaxNumberOfGCs that stores |
28 // the number of GCs initiated by the MemoryReducer since it left the DONE | 28 // the number of GCs initiated by the MemoryReducer since it left the DONE |
29 // state. | 29 // state. |
30 // The <next_gc_start_ms> is a double that stores the earliest time the next GC | 30 // The <next_gc_start_ms> is a double that stores the earliest time the next GC |
31 // can be initiated by the MemoryReducer. | 31 // can be initiated by the MemoryReducer. |
| 32 // The <last_gc_start_ms> is a double that stores the time of the last full GC. |
32 // The DONE state means that the MemoryReducer is not active. | 33 // The DONE state means that the MemoryReducer is not active. |
33 // The WAIT state means that the MemoryReducer is waiting for mutator allocation | 34 // The WAIT state means that the MemoryReducer is waiting for mutator allocation |
34 // rate to drop. The check for the allocation rate happens in the timer task | 35 // rate to drop. The check for the allocation rate happens in the timer task |
35 // callback. | 36 // callback. If the allocation rate does not drop in watchdog_delay_ms since |
| 37 // the last GC then transition to the RUN state is forced. |
36 // The RUN state means that the MemoryReducer started incremental marking and is | 38 // The RUN state means that the MemoryReducer started incremental marking and is |
37 // waiting for it to finish. Incremental marking steps are performed as usual | 39 // waiting for it to finish. Incremental marking steps are performed as usual |
38 // in the idle notification and in the mutator. | 40 // in the idle notification and in the mutator. |
39 // | 41 // |
40 // Transitions: | 42 // Transitions: |
41 // DONE -> WAIT 0 (now_ms + long_delay_ms) happens: | 43 // DONE t -> WAIT 0 (now_ms + long_delay_ms) t' happens: |
42 // - on context disposal, | 44 // - on context disposal. |
43 // - at the end of mark-compact GC initiated by the mutator. | 45 // - at the end of mark-compact GC initiated by the mutator. |
44 // This signals that there is potential garbage to be collected. | 46 // This signals that there is potential garbage to be collected. |
45 // | 47 // |
46 // WAIT n x -> WAIT n (now_ms + long_delay_ms) happens: | 48 // WAIT n x t -> WAIT n (now_ms + long_delay_ms) t' happens: |
47 // - on mark-compact GC initiated by the mutator, | 49 // - on mark-compact GC initiated by the mutator, |
48 // - in the timer callback if the mutator allocation rate is high or | 50 // - in the timer callback if the mutator allocation rate is high or |
49 // incremental GC is in progress. | 51 // incremental GC is in progress or (now_ms - t < watchdog_delay_ms) |
50 // | 52 // |
51 // WAIT n x -> WAIT (n+1) happens: | 53 // WAIT n x t -> WAIT (n+1) t happens: |
52 // - on background idle notification, which signals that we can start | 54 // - on background idle notification, which signals that we can start |
53 // incremental marking even if the allocation rate is high. | 55 // incremental marking even if the allocation rate is high. |
54 // The MemoryReducer starts incremental marking on this transition but still | 56 // The MemoryReducer starts incremental marking on this transition but still |
55 // has a pending timer task. | 57 // has a pending timer task. |
56 // | 58 // |
57 // WAIT n x -> DONE happens: | 59 // WAIT n x t -> DONE t happens: |
58 // - in the timer callback if n >= kMaxNumberOfGCs. | 60 // - in the timer callback if n >= kMaxNumberOfGCs. |
59 // | 61 // |
60 // WAIT n x -> RUN (n+1) happens: | 62 // WAIT n x t -> RUN (n+1) t happens: |
61 // - in the timer callback if the mutator allocation rate is low | 63 // - in the timer callback if the mutator allocation rate is low |
62 // and now_ms >= x and there is no incremental GC in progress. | 64 // and now_ms >= x and there is no incremental GC in progress. |
| 65 // - in the timer callback if (now_ms - t > watchdog_delay_ms) and |
| 66 // and now_ms >= x and there is no incremental GC in progress. |
63 // The MemoryReducer starts incremental marking on this transition. | 67 // The MemoryReducer starts incremental marking on this transition. |
64 // | 68 // |
65 // RUN n -> DONE happens: | 69 // RUN n t -> DONE now_ms happens: |
66 // - at end of the incremental GC initiated by the MemoryReducer if | 70 // - at end of the incremental GC initiated by the MemoryReducer if |
67 // (n > 1 and there is no more garbage to be collected) or | 71 // (n > 1 and there is no more garbage to be collected) or |
68 // n == kMaxNumberOfGCs. | 72 // n == kMaxNumberOfGCs. |
69 // RUN n -> WAIT n (now_ms + short_delay_ms) happens: | 73 // RUN n t -> WAIT n (now_ms + short_delay_ms) now_ms happens: |
70 // - at end of the incremental GC initiated by the MemoryReducer if | 74 // - at end of the incremental GC initiated by the MemoryReducer if |
71 // (n == 1 or there is more garbage to be collected) and | 75 // (n == 1 or there is more garbage to be collected) and |
72 // n < kMaxNumberOfGCs. | 76 // n < kMaxNumberOfGCs. |
73 // | 77 // |
74 // now_ms is the current time, long_delay_ms and short_delay_ms are constants. | 78 // now_ms is the current time, |
| 79 // t' is t if the current event is not a GC event and is now_ms otherwise, |
| 80 // long_delay_ms, short_delay_ms, and watchdog_delay_ms are constants. |
75 class MemoryReducer { | 81 class MemoryReducer { |
76 public: | 82 public: |
77 enum Action { kDone, kWait, kRun }; | 83 enum Action { kDone, kWait, kRun }; |
78 | 84 |
79 struct State { | 85 struct State { |
80 State(Action action, int started_gcs, double next_gc_start_ms) | 86 State(Action action, int started_gcs, double next_gc_start_ms, |
| 87 double last_gc_time_ms) |
81 : action(action), | 88 : action(action), |
82 started_gcs(started_gcs), | 89 started_gcs(started_gcs), |
83 next_gc_start_ms(next_gc_start_ms) {} | 90 next_gc_start_ms(next_gc_start_ms), |
| 91 last_gc_time_ms(last_gc_time_ms) {} |
84 Action action; | 92 Action action; |
85 int started_gcs; | 93 int started_gcs; |
86 double next_gc_start_ms; | 94 double next_gc_start_ms; |
| 95 double last_gc_time_ms; |
87 }; | 96 }; |
88 | 97 |
89 enum EventType { | 98 enum EventType { |
90 kTimer, | 99 kTimer, |
91 kMarkCompact, | 100 kMarkCompact, |
92 kContextDisposed, | 101 kContextDisposed, |
93 kBackgroundIdleNotification | 102 kBackgroundIdleNotification |
94 }; | 103 }; |
95 | 104 |
96 struct Event { | 105 struct Event { |
97 EventType type; | 106 EventType type; |
98 double time_ms; | 107 double time_ms; |
99 bool low_allocation_rate; | 108 bool low_allocation_rate; |
100 bool next_gc_likely_to_collect_more; | 109 bool next_gc_likely_to_collect_more; |
101 bool can_start_incremental_gc; | 110 bool can_start_incremental_gc; |
102 }; | 111 }; |
103 | 112 |
104 explicit MemoryReducer(Heap* heap) | 113 explicit MemoryReducer(Heap* heap) |
105 : heap_(heap), state_(kDone, 0, 0.0), pending_task_(nullptr) {} | 114 : heap_(heap), state_(kDone, 0, 0.0, 0.0), pending_task_(nullptr) {} |
106 // Callbacks. | 115 // Callbacks. |
107 void NotifyTimer(const Event& event); | 116 void NotifyTimer(const Event& event); |
108 void NotifyMarkCompact(const Event& event); | 117 void NotifyMarkCompact(const Event& event); |
109 void NotifyContextDisposed(const Event& event); | 118 void NotifyContextDisposed(const Event& event); |
110 void NotifyBackgroundIdleNotification(const Event& event); | 119 void NotifyBackgroundIdleNotification(const Event& event); |
111 // The step function that computes the next state from the current state and | 120 // The step function that computes the next state from the current state and |
112 // the incoming event. | 121 // the incoming event. |
113 static State Step(const State& state, const Event& event); | 122 static State Step(const State& state, const Event& event); |
114 // Posts a timer task that will call NotifyTimer after the given delay. | 123 // Posts a timer task that will call NotifyTimer after the given delay. |
115 void ScheduleTimer(double delay_ms); | 124 void ScheduleTimer(double delay_ms); |
116 void TearDown(); | 125 void TearDown(); |
117 void ClearTask(v8::Task* task); | 126 void ClearTask(v8::Task* task); |
| 127 |
| 128 static bool WatchdogGC(const State& state, const Event& event); |
| 129 |
118 static const int kLongDelayMs; | 130 static const int kLongDelayMs; |
119 static const int kShortDelayMs; | 131 static const int kShortDelayMs; |
| 132 static const int kWatchdogDelayMs; |
120 static const int kMaxNumberOfGCs; | 133 static const int kMaxNumberOfGCs; |
121 | 134 |
122 Heap* heap() { return heap_; } | 135 Heap* heap() { return heap_; } |
123 | 136 |
| 137 bool ShouldGrowHeapSlowly() { |
| 138 return state_.action == kDone && state_.started_gcs > 0; |
| 139 } |
| 140 |
124 private: | 141 private: |
125 class TimerTask : public v8::Task { | 142 class TimerTask : public v8::Task { |
126 public: | 143 public: |
127 explicit TimerTask(MemoryReducer* memory_reducer) | 144 explicit TimerTask(MemoryReducer* memory_reducer) |
128 : memory_reducer_(memory_reducer), heap_is_torn_down_(false) {} | 145 : memory_reducer_(memory_reducer), heap_is_torn_down_(false) {} |
129 virtual ~TimerTask() { | 146 virtual ~TimerTask() { |
130 if (!heap_is_torn_down_) { | 147 if (!heap_is_torn_down_) { |
131 memory_reducer_->ClearTask(this); | 148 memory_reducer_->ClearTask(this); |
132 } | 149 } |
133 } | 150 } |
(...skipping 10 matching lines...) Expand all Loading... |
144 State state_; | 161 State state_; |
145 TimerTask* pending_task_; | 162 TimerTask* pending_task_; |
146 | 163 |
147 DISALLOW_COPY_AND_ASSIGN(MemoryReducer); | 164 DISALLOW_COPY_AND_ASSIGN(MemoryReducer); |
148 }; | 165 }; |
149 | 166 |
150 } // namespace internal | 167 } // namespace internal |
151 } // namespace v8 | 168 } // namespace v8 |
152 | 169 |
153 #endif // V8_HEAP_memory_reducer_H | 170 #endif // V8_HEAP_memory_reducer_H |
OLD | NEW |