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