OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium 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 // Declares the MemoryPressureMonitor class. This is responsible for monitoring | |
6 // system-wide memory pressure and dispatching memory pressure signals to | |
7 // MemoryPressureListener. It is also responsible for rate limiting calls to the | |
8 // memory pressure subsytem and gathering statistics for UMA. | |
9 // | |
10 // The class has a few compile time differences depending on if | |
11 // MEMORY_PRESSURE_IS_POLLING is defined. For Windows, ChromeOS and Linux | |
12 // the implementation is polling so MEMORY_PRESSURE_IS_POLLING is defined. For | |
13 // Mac, iOS and Android it is not defined. | |
14 // | |
15 // The difference is that "polling" platforms have no native OS signals | |
16 // indicating memory pressure. These platforms implement | |
17 // DirectMemoryPressureCalculator, which is polled on a schedule to check for | |
18 // memory pressure changes. On non-polling platforms the OS provides a native | |
19 // signal. This signal is observed by the platform-specific implementation of | |
20 // MemoryPressureMonitorImpl. | |
21 // | |
22 // The memory pressure system periodically repeats memory pressure signals while | |
23 // under memory pressure (the interval varying depending on the pressure level). | |
24 // As such, even non-polling platforms require a scheduling mechanism for | |
25 // repeating notifications. Both implementations share this basic scheduling | |
26 // subsystem, and also leverage it to make timely UMA reports. | |
27 | |
28 #ifndef COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_MONITOR_H_ | |
29 #define COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_MONITOR_H_ | |
30 | |
31 #include <map> | |
32 #include <memory> | |
33 | |
34 #include "base/callback.h" | |
35 #include "base/memory/weak_ptr.h" | |
36 #include "base/synchronization/lock.h" | |
37 #include "base/time/time.h" | |
38 #include "components/memory_pressure/memory_pressure_listener.h" | |
39 | |
40 namespace base { | |
41 class TaskRunner; | |
42 class TickClock; | |
43 } // namespace | |
44 | |
45 namespace memory_pressure { | |
46 | |
47 class MemoryPressureCalculator; | |
48 class MemoryPressureStatsCollector; | |
49 | |
50 #if !defined(MEMORY_PRESSURE_IS_POLLING) | |
51 // For non-polling platform specific implementation details. An instance of | |
52 // this class will be encapsulated in the monitor. It will received an injected | |
53 // callback that routes messages to OnMemoryPressureChanged. | |
54 class MemoryPressureMonitorImpl; | |
55 #endif | |
56 | |
57 // A thread-safe class for directly querying and automatically monitoring | |
58 // memory pressure. When system memory pressure levels change this class is | |
59 // responsible for notifying MemoryPressureListeners, and periodically | |
60 // renotifying them as conditions persist. This class will do its periodic work | |
61 // on the thread on which it was created. However, it is safe to call | |
62 // GetCurrentPressureLevel from any thread. | |
63 // | |
64 // This class doesn't make use of base::RepeatingTimer as it leaves an orphaned | |
65 // scheduled task every time it is canceled. This can occur every time a memory | |
66 // pressure level transition occurs, which has no strict upper bound. Instead | |
67 // a collection of at most "number of memory pressure level" scheduled tasks | |
68 // is used, with these tasks being reused as transition levels are crossed and | |
69 // polling requirements change. See |scheduled_checks_| and | |
70 // "ScheduleTaskIfNeededLocked" for details. | |
71 class MemoryPressureMonitor { | |
72 public: | |
73 using MemoryPressureLevel = MemoryPressureListener::MemoryPressureLevel; | |
74 | |
75 // A simple dispatch delegate as a testing seam. Makes unittests much simpler | |
76 // as they don't need to setup a multithreaded environment. | |
77 using DispatchCallback = base::Callback<void(MemoryPressureLevel)>; | |
78 | |
79 #if defined(MEMORY_PRESSURE_IS_POLLING) | |
80 // The minimum time that must pass between successive polls. This enforces an | |
81 // upper bound on the rate of calls to the contained MemoryPressureCalculator. | |
82 // 100ms (10Hz) allows a relatively fast respsonse time for rapidly increasing | |
83 // memory usage, but limits the amount of work done in the calculator and | |
84 // stats collection. | |
85 enum : int { kMinimumTimeBetweenSamplesMs = 100 }; | |
86 // On polling platforms this is required to be somewhat short in order to | |
87 // observe memory pressure changes as they occur. | |
88 enum : int { kDefaultPollingIntervalMs = 5000 }; | |
89 #else | |
90 // On non-polling platforms this is only required for keeping statistics up to | |
91 // date so can be quite a long period. | |
92 enum : int { kDefaultPollingIntervalMs = 60000 }; | |
93 #endif | |
94 | |
95 // Renotification intervals, per pressure level. These are the same on all | |
96 // platforms. These act as an upper bound on the polling interval when under | |
97 // the corresponding memory pressure. | |
98 enum : int { kNotificationIntervalPressureModerateMs = 5000 }; | |
99 enum : int { kNotificationIntervalPressureCriticalMs = 1000 }; | |
100 | |
101 #if defined(MEMORY_PRESSURE_IS_POLLING) | |
102 // Fully configurable constructor for polling platforms. | |
103 MemoryPressureMonitor(const scoped_refptr<base::TaskRunner>& task_runner, | |
104 base::TickClock* tick_clock, | |
105 MemoryPressureStatsCollector* stats_collector, | |
106 MemoryPressureCalculator* calculator, | |
107 const DispatchCallback& dispatch_callback); | |
108 #else | |
109 // Constructor for non-polling platforms. | |
110 MemoryPressureMonitor(const scoped_refptr<base::TaskRunner>& task_runner, | |
111 base::TickClock* tick_clock, | |
112 MemoryPressureStatsCollector* stats_collector, | |
113 const DispatchCallback& dispatch_callback, | |
114 MemoryPressureLevel initial_pressure_level); | |
115 #endif | |
116 | |
117 ~MemoryPressureMonitor(); | |
118 | |
119 // Returns the current memory pressure level. On polling platforms this may | |
120 // result in a forced calculation of the current pressure level (a cheap | |
121 // operation). Can be called from any thread. | |
122 MemoryPressureLevel GetCurrentPressureLevel(); | |
123 | |
124 // Schedules a memory pressure check to run soon. This can be called from any | |
125 // thread. | |
126 void CheckMemoryPressureSoon(); | |
127 | |
128 private: | |
129 // For unittesting. | |
130 friend class TestMemoryPressureMonitor; | |
131 | |
132 #if !defined(MEMORY_PRESSURE_IS_POLLING) | |
133 // Notifications from the OS will be routed here by the contained | |
134 // MemoryPressureMonitorImpl instance. For statistics and renotification to | |
135 // work properly this must be notified of all pressure level changes, even | |
136 // those indicating a return to a state of no pressure. | |
137 void OnMemoryPressureChanged(MemoryPressureLevel level); | |
138 #endif | |
139 | |
140 // Starts the memory pressure monitor. To be called in the constructor. | |
141 void Start(); | |
142 | |
143 // Checks memory pressure and updates stats. This is the entry point for all | |
144 // scheduled checks. Each scheduled check is assigned a |serial| id | |
145 // (monotonically increasing) which is used to tie the task to the time at | |
146 // which it was scheduled via the |scheduled_checks_| map. | |
147 void CheckPressureAndUpdateStats(int serial); | |
148 void CheckPressureAndUpdateStatsLocked(int serial); | |
149 | |
150 // Ensures that a task is scheduled for renotification/recalculation/stats | |
151 // updating. Uses the |serial| id of the current task to determine the time at | |
152 // which the next scheduled check should run. Assumes |lock_| is held. | |
153 void ScheduleTaskIfNeededLocked(int serial); | |
154 | |
155 // Schedules a task. | |
156 void ScheduleTaskLocked(base::TimeTicks when); | |
157 | |
158 // A lock for synchronization. | |
159 base::Lock lock_; | |
160 | |
161 // Injected dependencies. | |
162 // The task runner on which periodic pressure checks and statistics uploading | |
163 // are run. | |
164 scoped_refptr<base::TaskRunner> task_runner_; | |
165 // The tick clock in use. Used under |lock_|. | |
166 base::TickClock* tick_clock_; | |
167 // The stats collector in use. Used under |lock_|. | |
168 MemoryPressureStatsCollector* stats_collector_; | |
169 // The memory pressure calculator in use. Used under |lock_|. | |
170 MemoryPressureCalculator* calculator_; | |
171 // The dispatch callback to use. | |
172 DispatchCallback dispatch_callback_; | |
173 | |
174 #if !defined(MEMORY_PRESSURE_IS_POLLING) | |
175 // On non-polling platforms this object is responsible for routing OS | |
176 // notifications to OnMemoryPressureChanged, and setting the initial pressure | |
177 // value. The OS specific implementation is responsible for allocating this | |
178 // object. | |
179 std::unique_ptr<MemoryPressureMonitorImpl> monitor_impl_; | |
180 #endif | |
181 | |
182 // Object state. | |
183 // The pressure level as of the most recent poll or notification. Under | |
184 // |lock_|. | |
185 MemoryPressureLevel current_memory_pressure_level_; | |
186 #if defined(MEMORY_PRESSURE_IS_POLLING) | |
187 // Time of the last pressure check. Under |lock_|. Only needed for polling | |
188 // implementations. | |
189 base::TimeTicks last_check_; | |
190 #endif | |
191 // Time of the last pressure notification. Under |lock_|. | |
192 base::TimeTicks last_notification_; | |
193 // A map of scheduled pressure checks/statistics updates and their serial | |
194 // numbers. Under |lock_|. | |
195 std::map<int, base::TimeTicks> scheduled_checks_; | |
196 // The most recently assigned serial number for a pressure check. The number | |
197 // 0 will never be assigned but will instead be reserved for unscheduled | |
198 // checks initiated externally. Under |lock_|. | |
199 int serial_number_; | |
200 | |
201 // Weak pointer factory to ourself used for posting delayed tasks to | |
202 // task_runner_. | |
203 base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_; | |
204 | |
205 DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor); | |
206 }; | |
207 | |
208 } // namespace memory_pressure | |
209 | |
210 #endif // COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_MONITOR_H_ | |
OLD | NEW |