| 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 |