forked from Pissandshittium/pissandshittium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmemory_pressure_monitor_win.cc
233 lines (190 loc) · 8.54 KB
/
memory_pressure_monitor_win.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/memory_pressure_monitor_win.h"
#include <windows.h>
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
namespace base {
namespace win {
namespace {
static const DWORDLONG kMBBytes = 1024 * 1024;
} // namespace
// The following constants have been lifted from similar values in the ChromeOS
// memory pressure monitor. The values were determined experimentally to ensure
// sufficient responsiveness of the memory pressure subsystem, and minimal
// overhead.
const int MemoryPressureMonitor::kPollingIntervalMs = 5000;
const int MemoryPressureMonitor::kModeratePressureCooldownMs = 10000;
const int MemoryPressureMonitor::kModeratePressureCooldownCycles =
kModeratePressureCooldownMs / kPollingIntervalMs;
// TODO(chrisha): Explore the following constants further with an experiment.
// A system is considered 'high memory' if it has more than 1.5GB of system
// memory available for use by the memory manager (not reserved for hardware
// and drivers). This is a fuzzy version of the ~2GB discussed below.
const int MemoryPressureMonitor::kLargeMemoryThresholdMb = 1536;
// These are the default thresholds used for systems with < ~2GB of physical
// memory. Such systems have been observed to always maintain ~100MB of
// available memory, paging until that is the case. To try to avoid paging a
// threshold slightly above this is chosen. The moderate threshold is slightly
// less grounded in reality and chosen as 2.5x critical.
const int MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb = 500;
const int MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb = 200;
// These are the default thresholds used for systems with >= ~2GB of physical
// memory. Such systems have been observed to always maintain ~300MB of
// available memory, paging until that is the case.
const int MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb = 1000;
const int MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb = 400;
MemoryPressureMonitor::MemoryPressureMonitor()
: moderate_threshold_mb_(0),
critical_threshold_mb_(0),
current_memory_pressure_level_(
MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
moderate_pressure_repeat_count_(0),
dispatch_callback_(
base::Bind(&MemoryPressureListener::NotifyMemoryPressure)),
weak_ptr_factory_(this) {
InferThresholds();
StartObserving();
}
MemoryPressureMonitor::MemoryPressureMonitor(int moderate_threshold_mb,
int critical_threshold_mb)
: moderate_threshold_mb_(moderate_threshold_mb),
critical_threshold_mb_(critical_threshold_mb),
current_memory_pressure_level_(
MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
moderate_pressure_repeat_count_(0),
dispatch_callback_(
base::Bind(&MemoryPressureListener::NotifyMemoryPressure)),
weak_ptr_factory_(this) {
DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
DCHECK_LE(0, critical_threshold_mb_);
StartObserving();
}
MemoryPressureMonitor::~MemoryPressureMonitor() {
StopObserving();
}
void MemoryPressureMonitor::CheckMemoryPressureSoon() {
DCHECK(thread_checker_.CalledOnValidThread());
ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, Bind(&MemoryPressureMonitor::CheckMemoryPressure,
weak_ptr_factory_.GetWeakPtr()));
}
MemoryPressureListener::MemoryPressureLevel
MemoryPressureMonitor::GetCurrentPressureLevel() {
return current_memory_pressure_level_;
}
void MemoryPressureMonitor::InferThresholds() {
// Default to a 'high' memory situation, which uses more conservative
// thresholds.
bool high_memory = true;
MEMORYSTATUSEX mem_status = {};
if (GetSystemMemoryStatus(&mem_status)) {
static const DWORDLONG kLargeMemoryThresholdBytes =
static_cast<DWORDLONG>(kLargeMemoryThresholdMb) * kMBBytes;
high_memory = mem_status.ullTotalPhys >= kLargeMemoryThresholdBytes;
}
if (high_memory) {
moderate_threshold_mb_ = kLargeMemoryDefaultModerateThresholdMb;
critical_threshold_mb_ = kLargeMemoryDefaultCriticalThresholdMb;
} else {
moderate_threshold_mb_ = kSmallMemoryDefaultModerateThresholdMb;
critical_threshold_mb_ = kSmallMemoryDefaultCriticalThresholdMb;
}
}
void MemoryPressureMonitor::StartObserving() {
DCHECK(thread_checker_.CalledOnValidThread());
timer_.Start(FROM_HERE,
TimeDelta::FromMilliseconds(kPollingIntervalMs),
Bind(&MemoryPressureMonitor::
CheckMemoryPressureAndRecordStatistics,
weak_ptr_factory_.GetWeakPtr()));
}
void MemoryPressureMonitor::StopObserving() {
DCHECK(thread_checker_.CalledOnValidThread());
// If StartObserving failed, StopObserving will still get called.
timer_.Stop();
weak_ptr_factory_.InvalidateWeakPtrs();
}
void MemoryPressureMonitor::CheckMemoryPressure() {
DCHECK(thread_checker_.CalledOnValidThread());
// Get the previous pressure level and update the current one.
MemoryPressureLevel old_pressure = current_memory_pressure_level_;
current_memory_pressure_level_ = CalculateCurrentPressureLevel();
// |notify| will be set to true if MemoryPressureListeners need to be
// notified of a memory pressure level state change.
bool notify = false;
switch (current_memory_pressure_level_) {
case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
break;
case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
if (old_pressure != current_memory_pressure_level_) {
// This is a new transition to moderate pressure so notify.
moderate_pressure_repeat_count_ = 0;
notify = true;
} else {
// Already in moderate pressure, only notify if sustained over the
// cooldown period.
if (++moderate_pressure_repeat_count_ ==
kModeratePressureCooldownCycles) {
moderate_pressure_repeat_count_ = 0;
notify = true;
}
}
break;
case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
// Always notify of critical pressure levels.
notify = true;
break;
}
if (!notify)
return;
// Emit a notification of the current memory pressure level. This can only
// happen for moderate and critical pressure levels.
DCHECK_NE(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
current_memory_pressure_level_);
dispatch_callback_.Run(current_memory_pressure_level_);
}
void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() {
DCHECK(thread_checker_.CalledOnValidThread());
CheckMemoryPressure();
RecordMemoryPressure(current_memory_pressure_level_, 1);
}
MemoryPressureListener::MemoryPressureLevel
MemoryPressureMonitor::CalculateCurrentPressureLevel() {
MEMORYSTATUSEX mem_status = {};
if (!GetSystemMemoryStatus(&mem_status))
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
// How much system memory is actively available for use right now, in MBs.
int phys_free = static_cast<int>(mem_status.ullAvailPhys / kMBBytes);
// TODO(chrisha): This should eventually care about address space pressure,
// but the browser process (where this is running) effectively never runs out
// of address space. Renderers occasionally do, but it does them no good to
// have the browser process monitor address space pressure. Long term,
// renderers should run their own address space pressure monitors and act
// accordingly, with the browser making cross-process decisions based on
// system memory pressure.
// Determine if the physical memory is under critical memory pressure.
if (phys_free <= critical_threshold_mb_)
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
// Determine if the physical memory is under moderate memory pressure.
if (phys_free <= moderate_threshold_mb_)
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
// No memory pressure was detected.
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
}
bool MemoryPressureMonitor::GetSystemMemoryStatus(
MEMORYSTATUSEX* mem_status) {
DCHECK(mem_status != nullptr);
mem_status->dwLength = sizeof(*mem_status);
if (!::GlobalMemoryStatusEx(mem_status))
return false;
return true;
}
void MemoryPressureMonitor::SetDispatchCallback(
const DispatchCallback& callback) {
dispatch_callback_ = callback;
}
} // namespace win
} // namespace base