Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(455)

Side by Side Diff: components/memory_pressure/memory_pressure_monitor.cc

Issue 2874553004: Remove memory_pressure component. (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 #include "components/memory_pressure/memory_pressure_monitor.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/task_runner.h"
10 #include "base/time/tick_clock.h"
11 #include "components/memory_pressure/memory_pressure_calculator.h"
12 #include "components/memory_pressure/memory_pressure_stats_collector.h"
13
14 namespace memory_pressure {
15
16 namespace {
17
18 using MemoryPressureLevel = MemoryPressureMonitor::MemoryPressureLevel;
19 const MemoryPressureLevel MEMORY_PRESSURE_LEVEL_NONE =
20 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
21 const MemoryPressureLevel MEMORY_PRESSURE_LEVEL_MODERATE =
22 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
23 const MemoryPressureLevel MEMORY_PRESSURE_LEVEL_CRITICAL =
24 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
25
26 // Returns the polling/notification interval for the given pressure level.
27 int GetPollingIntervalMs(MemoryPressureLevel level) {
28 switch (level) {
29 case MEMORY_PRESSURE_LEVEL_NONE:
30 return MemoryPressureMonitor::kDefaultPollingIntervalMs;
31
32 case MEMORY_PRESSURE_LEVEL_MODERATE:
33 return MemoryPressureMonitor::kNotificationIntervalPressureModerateMs;
34
35 case MEMORY_PRESSURE_LEVEL_CRITICAL:
36 return MemoryPressureMonitor::kNotificationIntervalPressureCriticalMs;
37 }
38
39 NOTREACHED();
40 return 0;
41 }
42
43 base::TimeDelta GetPollingInterval(MemoryPressureLevel level) {
44 return base::TimeDelta::FromMilliseconds(GetPollingIntervalMs(level));
45 }
46
47 // Serial number reserved for unscheduled checks as a result of external calls
48 // to the monitor.
49 const int kUnscheduledCheckSerial = 0;
50
51 } // namespace
52
53 #if !defined(MEMORY_PRESSURE_IS_POLLING)
54 // Default definition of this class.
55 // TODO(chrisha): Implement useful versions of this for affected platforms.
56 class MemoryPressureMonitorImpl {};
57 #endif
58
59 #if defined(MEMORY_PRESSURE_IS_POLLING)
60 MemoryPressureMonitor::MemoryPressureMonitor(
61 const scoped_refptr<base::TaskRunner>& task_runner,
62 base::TickClock* tick_clock,
63 MemoryPressureStatsCollector* stats_collector,
64 MemoryPressureCalculator* calculator,
65 const DispatchCallback& dispatch_callback)
66 : task_runner_(task_runner),
67 tick_clock_(tick_clock),
68 stats_collector_(stats_collector),
69 calculator_(calculator),
70 dispatch_callback_(dispatch_callback),
71 current_memory_pressure_level_(MEMORY_PRESSURE_LEVEL_NONE),
72 serial_number_(kUnscheduledCheckSerial),
73 weak_ptr_factory_(this) {
74 DCHECK(task_runner_.get());
75 DCHECK(tick_clock_);
76 DCHECK(stats_collector_);
77 DCHECK(calculator_);
78 DCHECK(!dispatch_callback_.is_null());
79
80 Start();
81 }
82 #else // MEMORY_PRESSURE_IS_POLLING
83 MemoryPressureMonitor::MemoryPressureMonitor(
84 const scoped_refptr<base::TaskRunner>& task_runner,
85 base::TickClock* tick_clock,
86 MemoryPressureStatsCollector* stats_collector,
87 const DispatchCallback& dispatch_callback,
88 MemoryPressureLevel initial_pressure_level)
89 : task_runner_(task_runner),
90 tick_clock_(tick_clock),
91 stats_collector_(stats_collector),
92 dispatch_callback_(dispatch_callback),
93 current_memory_pressure_level_(initial_pressure_level),
94 serial_number_(kUnscheduledCheckSerial),
95 weak_ptr_factory_(this) {
96 DCHECK(task_runner_.get());
97 DCHECK(tick_clock_);
98 DCHECK(stats_collector_);
99 DCHECK(!dispatch_callback_.is_null());
100
101 Start();
102 }
103 #endif // !MEMORY_PRESSURE_IS_POLLING
104
105 MemoryPressureMonitor::~MemoryPressureMonitor() {}
106
107 MemoryPressureLevel MemoryPressureMonitor::GetCurrentPressureLevel() {
108 base::AutoLock lock(lock_);
109
110 #if defined(MEMORY_PRESSURE_IS_POLLING)
111 // Force an immediate pressure check on polling platforms. On non-polling
112 // platforms the current memory pressure is always valid.
113 CheckPressureAndUpdateStatsLocked(kUnscheduledCheckSerial);
114 #endif
115
116 return current_memory_pressure_level_;
117 }
118
119 void MemoryPressureMonitor::CheckMemoryPressureSoon() {
120 // This function is a nop on non-polling platforms.
121 #if defined(MEMORY_PRESSURE_IS_POLLING)
122 // Schedule a check to run as soon as possible.
123 base::AutoLock lock(lock_);
124 base::TimeTicks now = tick_clock_->NowTicks();
125 ScheduleTaskLocked(now);
126 #endif
127 }
128
129 #if !defined(MEMORY_PRESSURE_IS_POLLING)
130 // This is the entry point for OS notifications of pressure level changes.
131 void MemoryPressureMonitor::OnMemoryPressureChanged(
132 MemoryPressureLevel level) {
133 base::AutoLock lock(lock_);
134
135 // Do nothing if the level hasn't changed.
136 if (level == current_memory_pressure_level_)
137 return;
138
139 // Update the level and the stats.
140 current_memory_pressure_level_ = level;
141 stats_collector_->UpdateStatistics(current_memory_pressure_level_);
142
143 // Only dispatch notifications if there is memory pressure.
144 if (current_memory_pressure_level_ > MEMORY_PRESSURE_LEVEL_NONE) {
145 last_notification_ = tick_clock_->NowTicks();
146 dispatch_callback_.Run(current_memory_pressure_level_);
147 }
148
149 ScheduleTaskIfNeededLocked(kUnscheduledCheckSerial);
150 }
151 #endif
152
153 void MemoryPressureMonitor::Start() {
154 base::AutoLock lock(lock_);
155
156 base::TimeTicks now = tick_clock_->NowTicks();
157
158 // Get the statistics collector warmed up by measuring the pressure level.
159 // Don't immediately fire a signal if already under memory pressure as the
160 // system is quite busy with startup right now. Wait until the first
161 // renotification is required, allowing the browser time to get started.
162 // Non-polling implementations set the initial memory pressure level in the
163 // constructor.
164 #if defined(MEMORY_PRESSURE_IS_POLLING)
165 current_memory_pressure_level_ = calculator_->CalculateCurrentPressureLevel();
166 last_check_ = now;
167 #endif
168
169 last_notification_ = now;
170 stats_collector_->UpdateStatistics(current_memory_pressure_level_);
171 ScheduleTaskIfNeededLocked(kUnscheduledCheckSerial);
172 }
173
174 void MemoryPressureMonitor::CheckPressureAndUpdateStats(int serial) {
175 // This should only ever be used by scheduled checks.
176 DCHECK_NE(kUnscheduledCheckSerial, serial);
177 base::AutoLock lock(lock_);
178 CheckPressureAndUpdateStatsLocked(serial);
179 }
180
181 void MemoryPressureMonitor::CheckPressureAndUpdateStatsLocked(int serial) {
182 lock_.AssertAcquired();
183
184 base::TimeTicks now = tick_clock_->NowTicks();
185 MemoryPressureLevel old_level = current_memory_pressure_level_;
186
187 #if defined(MEMORY_PRESSURE_IS_POLLING)
188 // Don't check again if pressure was calculated too recently.
189 DCHECK(!last_check_.is_null());
190 if ((now - last_check_) >=
191 base::TimeDelta::FromMilliseconds(kMinimumTimeBetweenSamplesMs)) {
192 // Calculate the current pressure level and update statistics.
193 last_check_ = now;
194 current_memory_pressure_level_ =
195 calculator_->CalculateCurrentPressureLevel();
196 stats_collector_->UpdateStatistics(current_memory_pressure_level_);
197 }
198 #else // MEMORY_PRESSURE_IS_POLLING
199 // On non-polling platforms this function can only be invoked by scheduled
200 // callbacks for updating statistics and sending renotifications. Simply
201 // update the statistics and move on.
202 DCHECK_NE(kUnscheduledCheckSerial, serial);
203 stats_collector_->UpdateStatistics(current_memory_pressure_level_);
204 #endif // !MEMORY_PRESSURE_IS_POLLING
205
206 // Check if the level has changed or a renotification is required.
207 DCHECK(!last_notification_.is_null());
208 if (current_memory_pressure_level_ != old_level ||
209 now - last_notification_ >=
210 GetPollingInterval(current_memory_pressure_level_)) {
211 last_notification_ = now;
212
213 // Only dispatch notifications if there is memory pressure.
214 if (current_memory_pressure_level_ > MEMORY_PRESSURE_LEVEL_NONE)
215 dispatch_callback_.Run(current_memory_pressure_level_);
216 }
217
218 ScheduleTaskIfNeededLocked(serial);
219 }
220
221 void MemoryPressureMonitor::ScheduleTaskIfNeededLocked(int serial) {
222 lock_.AssertAcquired();
223
224 // Remove this check from the set of scheduled checks.
225 if (serial != kUnscheduledCheckSerial) {
226 size_t erased = scheduled_checks_.erase(serial);
227 DCHECK_EQ(1u, erased);
228 }
229
230 // Get the time of the soonest scheduled check. This linear scan is quick
231 // because the map will contain at most 1 entry per pressure level, and most
232 // commonly only 1 entry.
233 base::TimeTicks next_check;
234 for (const auto& check : scheduled_checks_) {
235 if (next_check.is_null() || check.second < next_check)
236 next_check = check.second;
237 }
238
239 // Get the time of the required next check.
240 base::TimeTicks required_check =
241 last_notification_ + GetPollingInterval(current_memory_pressure_level_);
242
243 // If there's already a check scheduled in time then don't schedule
244 // another. This lets the number of scheduled checks shrink back down to 1
245 // as pressure changes occur.
246 if (!next_check.is_null() && next_check <= required_check)
247 return;
248
249 ScheduleTaskLocked(required_check);
250 }
251
252 void MemoryPressureMonitor::ScheduleTaskLocked(base::TimeTicks when) {
253 lock_.AssertAcquired();
254 int serial = ++serial_number_;
255
256 // Handle overflow. For simplicity keep serial numbers positive. 2^31 leaves
257 // room for 20 years of uptime in the worst case scenario (poll every second,
258 // constantly swinging through all the pressure levels). But you know...
259 // better safe the sorry!
260 if (serial < 0) {
261 serial_number_ = 1;
262 serial = 1;
263 }
264
265 // It's entirely possible for |when| to be in the past relative to |now|, so
266 // bound |delay| from below.
267 base::TimeTicks now = tick_clock_->NowTicks();
268 base::TimeDelta delay; // Initializes to zero.
269 if (when > now)
270 delay = when - now;
271
272 // Schedule another check.
273 if (task_runner_->PostDelayedTask(
274 FROM_HERE,
275 base::Bind(&MemoryPressureMonitor::CheckPressureAndUpdateStats,
276 weak_ptr_factory_.GetWeakPtr(), serial),
277 delay)) {
278 // If the task will run then add it to the map of scheduled checks.
279 scheduled_checks_[serial] = when;
280 }
281 }
282
283 } // namespace memory_pressure
OLDNEW
« no previous file with comments | « components/memory_pressure/memory_pressure_monitor.h ('k') | components/memory_pressure/memory_pressure_monitor_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698