Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / base / memory / memory_pressure_monitor_win.cc
blob4349d035806c3efe6689c0846b7d787a11e467ce
1 // Copyright 2015 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.
5 #include "base/memory/memory_pressure_monitor_win.h"
7 #include <windows.h>
9 #include "base/metrics/histogram_macros.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "base/time/time.h"
14 namespace base {
15 namespace win {
17 namespace {
19 static const DWORDLONG kMBBytes = 1024 * 1024;
21 // Enumeration of UMA memory pressure levels. This needs to be kept in sync with
22 // histograms.xml and the memory pressure levels defined in
23 // MemoryPressureListener.
24 enum MemoryPressureLevelUMA {
25 UMA_MEMORY_PRESSURE_LEVEL_NONE = 0,
26 UMA_MEMORY_PRESSURE_LEVEL_MODERATE = 1,
27 UMA_MEMORY_PRESSURE_LEVEL_CRITICAL = 2,
28 // This must be the last value in the enum.
29 UMA_MEMORY_PRESSURE_LEVEL_COUNT,
32 // Converts a memory pressure level to an UMA enumeration value.
33 MemoryPressureLevelUMA MemoryPressureLevelToUmaEnumValue(
34 MemoryPressureListener::MemoryPressureLevel level) {
35 switch (level) {
36 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
37 return UMA_MEMORY_PRESSURE_LEVEL_NONE;
38 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
39 return UMA_MEMORY_PRESSURE_LEVEL_MODERATE;
40 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
41 return UMA_MEMORY_PRESSURE_LEVEL_CRITICAL;
43 NOTREACHED();
44 return UMA_MEMORY_PRESSURE_LEVEL_NONE;
47 } // namespace
49 // The following constants have been lifted from similar values in the ChromeOS
50 // memory pressure monitor. The values were determined experimentally to ensure
51 // sufficient responsiveness of the memory pressure subsystem, and minimal
52 // overhead.
53 const int MemoryPressureMonitor::kPollingIntervalMs = 5000;
54 const int MemoryPressureMonitor::kModeratePressureCooldownMs = 10000;
55 const int MemoryPressureMonitor::kModeratePressureCooldownCycles =
56 kModeratePressureCooldownMs / kPollingIntervalMs;
58 // TODO(chrisha): Explore the following constants further with an experiment.
60 // A system is considered 'high memory' if it has more than 1.5GB of system
61 // memory available for use by the memory manager (not reserved for hardware
62 // and drivers). This is a fuzzy version of the ~2GB discussed below.
63 const int MemoryPressureMonitor::kLargeMemoryThresholdMb = 1536;
65 // These are the default thresholds used for systems with < ~2GB of physical
66 // memory. Such systems have been observed to always maintain ~100MB of
67 // available memory, paging until that is the case. To try to avoid paging a
68 // threshold slightly above this is chosen. The moderate threshold is slightly
69 // less grounded in reality and chosen as 2.5x critical.
70 const int MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb = 500;
71 const int MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb = 200;
73 // These are the default thresholds used for systems with >= ~2GB of physical
74 // memory. Such systems have been observed to always maintain ~300MB of
75 // available memory, paging until that is the case.
76 const int MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb = 1000;
77 const int MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb = 400;
79 MemoryPressureMonitor::MemoryPressureMonitor()
80 : moderate_threshold_mb_(0),
81 critical_threshold_mb_(0),
82 current_memory_pressure_level_(
83 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
84 moderate_pressure_repeat_count_(0),
85 weak_ptr_factory_(this) {
86 InferThresholds();
87 StartObserving();
90 MemoryPressureMonitor::MemoryPressureMonitor(int moderate_threshold_mb,
91 int critical_threshold_mb)
92 : moderate_threshold_mb_(moderate_threshold_mb),
93 critical_threshold_mb_(critical_threshold_mb),
94 current_memory_pressure_level_(
95 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
96 moderate_pressure_repeat_count_(0),
97 weak_ptr_factory_(this) {
98 DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
99 DCHECK_LE(0, critical_threshold_mb_);
100 StartObserving();
103 MemoryPressureMonitor::~MemoryPressureMonitor() {
104 StopObserving();
107 void MemoryPressureMonitor::CheckMemoryPressureSoon() {
108 DCHECK(thread_checker_.CalledOnValidThread());
110 ThreadTaskRunnerHandle::Get()->PostTask(
111 FROM_HERE, Bind(&MemoryPressureMonitor::CheckMemoryPressure,
112 weak_ptr_factory_.GetWeakPtr()));
115 MemoryPressureListener::MemoryPressureLevel
116 MemoryPressureMonitor::GetCurrentPressureLevel() const {
117 return current_memory_pressure_level_;
120 void MemoryPressureMonitor::InferThresholds() {
121 // Default to a 'high' memory situation, which uses more conservative
122 // thresholds.
123 bool high_memory = true;
124 MEMORYSTATUSEX mem_status = {};
125 if (GetSystemMemoryStatus(&mem_status)) {
126 static const DWORDLONG kLargeMemoryThresholdBytes =
127 static_cast<DWORDLONG>(kLargeMemoryThresholdMb) * kMBBytes;
128 high_memory = mem_status.ullTotalPhys >= kLargeMemoryThresholdBytes;
131 if (high_memory) {
132 moderate_threshold_mb_ = kLargeMemoryDefaultModerateThresholdMb;
133 critical_threshold_mb_ = kLargeMemoryDefaultCriticalThresholdMb;
134 } else {
135 moderate_threshold_mb_ = kSmallMemoryDefaultModerateThresholdMb;
136 critical_threshold_mb_ = kSmallMemoryDefaultCriticalThresholdMb;
140 void MemoryPressureMonitor::StartObserving() {
141 DCHECK(thread_checker_.CalledOnValidThread());
143 timer_.Start(FROM_HERE,
144 TimeDelta::FromMilliseconds(kPollingIntervalMs),
145 Bind(&MemoryPressureMonitor::
146 CheckMemoryPressureAndRecordStatistics,
147 weak_ptr_factory_.GetWeakPtr()));
150 void MemoryPressureMonitor::StopObserving() {
151 DCHECK(thread_checker_.CalledOnValidThread());
153 // If StartObserving failed, StopObserving will still get called.
154 timer_.Stop();
155 weak_ptr_factory_.InvalidateWeakPtrs();
158 void MemoryPressureMonitor::CheckMemoryPressure() {
159 DCHECK(thread_checker_.CalledOnValidThread());
161 // Get the previous pressure level and update the current one.
162 MemoryPressureLevel old_pressure = current_memory_pressure_level_;
163 current_memory_pressure_level_ = CalculateCurrentPressureLevel();
165 // |notify| will be set to true if MemoryPressureListeners need to be
166 // notified of a memory pressure level state change.
167 bool notify = false;
168 switch (current_memory_pressure_level_) {
169 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
170 break;
172 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
173 if (old_pressure != current_memory_pressure_level_) {
174 // This is a new transition to moderate pressure so notify.
175 moderate_pressure_repeat_count_ = 0;
176 notify = true;
177 } else {
178 // Already in moderate pressure, only notify if sustained over the
179 // cooldown period.
180 if (++moderate_pressure_repeat_count_ ==
181 kModeratePressureCooldownCycles) {
182 moderate_pressure_repeat_count_ = 0;
183 notify = true;
186 break;
188 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
189 // Always notify of critical pressure levels.
190 notify = true;
191 break;
194 if (!notify)
195 return;
197 // Emit a notification of the current memory pressure level. This can only
198 // happen for moderate and critical pressure levels.
199 DCHECK_NE(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
200 current_memory_pressure_level_);
201 MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
204 void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() {
205 DCHECK(thread_checker_.CalledOnValidThread());
207 CheckMemoryPressure();
209 UMA_HISTOGRAM_ENUMERATION(
210 "Memory.PressureLevel",
211 MemoryPressureLevelToUmaEnumValue(current_memory_pressure_level_),
212 UMA_MEMORY_PRESSURE_LEVEL_COUNT);
215 MemoryPressureListener::MemoryPressureLevel
216 MemoryPressureMonitor::CalculateCurrentPressureLevel() {
217 MEMORYSTATUSEX mem_status = {};
218 if (!GetSystemMemoryStatus(&mem_status))
219 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
221 // How much system memory is actively available for use right now, in MBs.
222 int phys_free = static_cast<int>(mem_status.ullAvailPhys / kMBBytes);
224 // TODO(chrisha): This should eventually care about address space pressure,
225 // but the browser process (where this is running) effectively never runs out
226 // of address space. Renderers occasionally do, but it does them no good to
227 // have the browser process monitor address space pressure. Long term,
228 // renderers should run their own address space pressure monitors and act
229 // accordingly, with the browser making cross-process decisions based on
230 // system memory pressure.
232 // Determine if the physical memory is under critical memory pressure.
233 if (phys_free <= critical_threshold_mb_)
234 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
236 // Determine if the physical memory is under moderate memory pressure.
237 if (phys_free <= moderate_threshold_mb_)
238 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
240 // No memory pressure was detected.
241 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
244 bool MemoryPressureMonitor::GetSystemMemoryStatus(
245 MEMORYSTATUSEX* mem_status) {
246 DCHECK(mem_status != nullptr);
247 mem_status->dwLength = sizeof(*mem_status);
248 if (!::GlobalMemoryStatusEx(mem_status))
249 return false;
250 return true;
253 } // namespace win
254 } // namespace base