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

Side by Side Diff: base/chromeos/memory_pressure_monitor_chromeos.cc

Issue 1124763003: Update from https://crrev.com/327068 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: update nacl, buildtools, fix display_change_notifier_unittest Created 5 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
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/chromeos/memory_pressure_observer_chromeos.h" 5 #include "base/chromeos/memory_pressure_monitor_chromeos.h"
6
7 #include <fcntl.h>
8 #include <sys/select.h>
6 9
7 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop.h"
8 #include "base/metrics/histogram_macros.h" 11 #include "base/metrics/histogram_macros.h"
12 #include "base/posix/eintr_wrapper.h"
9 #include "base/process/process_metrics.h" 13 #include "base/process/process_metrics.h"
10 #include "base/time/time.h" 14 #include "base/time/time.h"
11 15
12 namespace base { 16 namespace base {
13 17
14 namespace { 18 namespace {
15 19
16 // The time between memory pressure checks. While under critical pressure, this 20 // The time between memory pressure checks. While under critical pressure, this
17 // is also the timer to repeat cleanup attempts. 21 // is also the timer to repeat cleanup attempts.
18 const int kMemoryPressureIntervalMs = 1000; 22 const int kMemoryPressureIntervalMs = 1000;
19 23
20 // The time which should pass between two moderate memory pressure calls. 24 // The time which should pass between two moderate memory pressure calls.
21 const int kModerateMemoryPressureCooldownMs = 10000; 25 const int kModerateMemoryPressureCooldownMs = 10000;
22 26
23 // Number of event polls before the next moderate pressure event can be sent. 27 // Number of event polls before the next moderate pressure event can be sent.
24 const int kModerateMemoryPressureCooldown = 28 const int kModerateMemoryPressureCooldown =
25 kModerateMemoryPressureCooldownMs / kMemoryPressureIntervalMs; 29 kModerateMemoryPressureCooldownMs / kMemoryPressureIntervalMs;
26 30
27 // Threshold constants to emit pressure events. 31 // Threshold constants to emit pressure events.
28 const int kNormalMemoryPressureModerateThresholdPercent = 60; 32 const int kNormalMemoryPressureModerateThresholdPercent = 60;
29 const int kNormalMemoryPressureCriticalThresholdPercent = 90; 33 const int kNormalMemoryPressureCriticalThresholdPercent = 95;
30 const int kAggressiveMemoryPressureModerateThresholdPercent = 35; 34 const int kAggressiveMemoryPressureModerateThresholdPercent = 35;
31 const int kAggressiveMemoryPressureCriticalThresholdPercent = 70; 35 const int kAggressiveMemoryPressureCriticalThresholdPercent = 70;
32 36
33 // The possible state for memory pressure level. The values should be in line 37 // The possible state for memory pressure level. The values should be in line
34 // with values in MemoryPressureListener::MemoryPressureLevel and should be 38 // with values in MemoryPressureListener::MemoryPressureLevel and should be
35 // updated if more memory pressure levels are introduced. 39 // updated if more memory pressure levels are introduced.
36 enum MemoryPressureLevelUMA { 40 enum MemoryPressureLevelUMA {
37 MEMORY_PRESSURE_LEVEL_NONE = 0, 41 MEMORY_PRESSURE_LEVEL_NONE = 0,
38 MEMORY_PRESSURE_LEVEL_MODERATE, 42 MEMORY_PRESSURE_LEVEL_MODERATE,
39 MEMORY_PRESSURE_LEVEL_CRITICAL, 43 MEMORY_PRESSURE_LEVEL_CRITICAL,
40 NUM_MEMORY_PRESSURE_LEVELS 44 NUM_MEMORY_PRESSURE_LEVELS
41 }; 45 };
42 46
47 // This is the file that will exist if low memory notification is available
48 // on the device. Whenever it becomes readable, it signals a low memory
49 // condition.
50 const char kLowMemFile[] = "/dev/chromeos-low-mem";
51
43 // Converts a |MemoryPressureThreshold| value into a used memory percentage for 52 // Converts a |MemoryPressureThreshold| value into a used memory percentage for
44 // the moderate pressure event. 53 // the moderate pressure event.
45 int GetModerateMemoryThresholdInPercent( 54 int GetModerateMemoryThresholdInPercent(
46 MemoryPressureObserverChromeOS::MemoryPressureThresholds thresholds) { 55 MemoryPressureMonitorChromeOS::MemoryPressureThresholds thresholds) {
47 return thresholds == MemoryPressureObserverChromeOS:: 56 return thresholds == MemoryPressureMonitorChromeOS::
48 THRESHOLD_AGGRESSIVE_CACHE_DISCARD || 57 THRESHOLD_AGGRESSIVE_CACHE_DISCARD ||
49 thresholds == MemoryPressureObserverChromeOS::THRESHOLD_AGGRESSIVE 58 thresholds == MemoryPressureMonitorChromeOS::THRESHOLD_AGGRESSIVE
50 ? kAggressiveMemoryPressureModerateThresholdPercent 59 ? kAggressiveMemoryPressureModerateThresholdPercent
51 : kNormalMemoryPressureModerateThresholdPercent; 60 : kNormalMemoryPressureModerateThresholdPercent;
52 } 61 }
53 62
54 // Converts a |MemoryPressureThreshold| value into a used memory percentage for 63 // Converts a |MemoryPressureThreshold| value into a used memory percentage for
55 // the critical pressure event. 64 // the critical pressure event.
56 int GetCriticalMemoryThresholdInPercent( 65 int GetCriticalMemoryThresholdInPercent(
57 MemoryPressureObserverChromeOS::MemoryPressureThresholds thresholds) { 66 MemoryPressureMonitorChromeOS::MemoryPressureThresholds thresholds) {
58 return thresholds == MemoryPressureObserverChromeOS:: 67 return thresholds == MemoryPressureMonitorChromeOS::
59 THRESHOLD_AGGRESSIVE_TAB_DISCARD || 68 THRESHOLD_AGGRESSIVE_TAB_DISCARD ||
60 thresholds == MemoryPressureObserverChromeOS::THRESHOLD_AGGRESSIVE 69 thresholds == MemoryPressureMonitorChromeOS::THRESHOLD_AGGRESSIVE
61 ? kAggressiveMemoryPressureCriticalThresholdPercent 70 ? kAggressiveMemoryPressureCriticalThresholdPercent
62 : kNormalMemoryPressureCriticalThresholdPercent; 71 : kNormalMemoryPressureCriticalThresholdPercent;
63 } 72 }
64 73
65 // Converts free percent of memory into a memory pressure value. 74 // Converts free percent of memory into a memory pressure value.
66 MemoryPressureListener::MemoryPressureLevel GetMemoryPressureLevelFromFillLevel( 75 MemoryPressureListener::MemoryPressureLevel GetMemoryPressureLevelFromFillLevel(
67 int actual_fill_level, 76 int actual_fill_level,
68 int moderate_threshold, 77 int moderate_threshold,
69 int critical_threshold) { 78 int critical_threshold) {
70 if (actual_fill_level < moderate_threshold) 79 if (actual_fill_level < moderate_threshold)
71 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; 80 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
72 return actual_fill_level < critical_threshold 81 return actual_fill_level < critical_threshold
73 ? MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE 82 ? MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE
74 : MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; 83 : MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
75 } 84 }
76 85
86 // This function will be called less then once a second. It will check if
87 // the kernel has detected a low memory situation.
88 bool IsLowMemoryCondition(int file_descriptor) {
89 fd_set fds;
90 struct timeval tv;
91
92 FD_ZERO(&fds);
93 FD_SET(file_descriptor, &fds);
94
95 tv.tv_sec = 0;
96 tv.tv_usec = 0;
97
98 return HANDLE_EINTR(select(file_descriptor + 1, &fds, NULL, NULL, &tv)) > 0;
99 }
100
77 } // namespace 101 } // namespace
78 102
79 MemoryPressureObserverChromeOS::MemoryPressureObserverChromeOS( 103 MemoryPressureMonitorChromeOS::MemoryPressureMonitorChromeOS(
80 MemoryPressureThresholds thresholds) 104 MemoryPressureThresholds thresholds)
81 : current_memory_pressure_level_( 105 : current_memory_pressure_level_(
82 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE), 106 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
83 moderate_pressure_repeat_count_(0), 107 moderate_pressure_repeat_count_(0),
84 moderate_pressure_threshold_percent_( 108 moderate_pressure_threshold_percent_(
85 GetModerateMemoryThresholdInPercent(thresholds)), 109 GetModerateMemoryThresholdInPercent(thresholds)),
86 critical_pressure_threshold_percent_( 110 critical_pressure_threshold_percent_(
87 GetCriticalMemoryThresholdInPercent(thresholds)), 111 GetCriticalMemoryThresholdInPercent(thresholds)),
112 low_mem_file_(HANDLE_EINTR(::open(kLowMemFile, O_RDONLY))),
88 weak_ptr_factory_(this) { 113 weak_ptr_factory_(this) {
89 StartObserving(); 114 StartObserving();
115 LOG_IF(ERROR, !low_mem_file_.is_valid()) << "Cannot open kernel listener";
90 } 116 }
91 117
92 MemoryPressureObserverChromeOS::~MemoryPressureObserverChromeOS() { 118 MemoryPressureMonitorChromeOS::~MemoryPressureMonitorChromeOS() {
93 StopObserving(); 119 StopObserving();
94 } 120 }
95 121
96 void MemoryPressureObserverChromeOS::ScheduleEarlyCheck() { 122 void MemoryPressureMonitorChromeOS::ScheduleEarlyCheck() {
97 MessageLoop::current()->PostTask( 123 MessageLoop::current()->PostTask(
98 FROM_HERE, 124 FROM_HERE,
99 Bind(&MemoryPressureObserverChromeOS::CheckMemoryPressure, 125 Bind(&MemoryPressureMonitorChromeOS::CheckMemoryPressure,
100 weak_ptr_factory_.GetWeakPtr())); 126 weak_ptr_factory_.GetWeakPtr()));
101 } 127 }
102 128
103 void MemoryPressureObserverChromeOS::StartObserving() { 129 MemoryPressureListener::MemoryPressureLevel
130 MemoryPressureMonitorChromeOS::GetCurrentPressureLevel() const {
131 return current_memory_pressure_level_;
132 }
133
134 void MemoryPressureMonitorChromeOS::StartObserving() {
104 timer_.Start(FROM_HERE, 135 timer_.Start(FROM_HERE,
105 TimeDelta::FromMilliseconds(kMemoryPressureIntervalMs), 136 TimeDelta::FromMilliseconds(kMemoryPressureIntervalMs),
106 Bind(&MemoryPressureObserverChromeOS:: 137 Bind(&MemoryPressureMonitorChromeOS::
107 CheckMemoryPressureAndRecordStatistics, 138 CheckMemoryPressureAndRecordStatistics,
108 weak_ptr_factory_.GetWeakPtr())); 139 weak_ptr_factory_.GetWeakPtr()));
109 } 140 }
110 141
111 void MemoryPressureObserverChromeOS::StopObserving() { 142 void MemoryPressureMonitorChromeOS::StopObserving() {
112 // If StartObserving failed, StopObserving will still get called. 143 // If StartObserving failed, StopObserving will still get called.
113 timer_.Stop(); 144 timer_.Stop();
114 } 145 }
115 146
116 void MemoryPressureObserverChromeOS::CheckMemoryPressureAndRecordStatistics() { 147 void MemoryPressureMonitorChromeOS::CheckMemoryPressureAndRecordStatistics() {
117 CheckMemoryPressure(); 148 CheckMemoryPressure();
118 149
119 // Record UMA histogram statistics for the current memory pressure level. 150 // Record UMA histogram statistics for the current memory pressure level.
120 MemoryPressureLevelUMA memory_pressure_level_uma(MEMORY_PRESSURE_LEVEL_NONE); 151 MemoryPressureLevelUMA memory_pressure_level_uma(MEMORY_PRESSURE_LEVEL_NONE);
121 switch (current_memory_pressure_level_) { 152 switch (current_memory_pressure_level_) {
122 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: 153 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
123 memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_NONE; 154 memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_NONE;
124 break; 155 break;
125 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: 156 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
126 memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_MODERATE; 157 memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_MODERATE;
127 break; 158 break;
128 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: 159 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
129 memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_CRITICAL; 160 memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_CRITICAL;
130 break; 161 break;
131 } 162 }
132 163
133 UMA_HISTOGRAM_ENUMERATION("ChromeOS.MemoryPressureLevel", 164 UMA_HISTOGRAM_ENUMERATION("ChromeOS.MemoryPressureLevel",
134 memory_pressure_level_uma, 165 memory_pressure_level_uma,
135 NUM_MEMORY_PRESSURE_LEVELS); 166 NUM_MEMORY_PRESSURE_LEVELS);
136 } 167 }
137 168
138 void MemoryPressureObserverChromeOS::CheckMemoryPressure() { 169 void MemoryPressureMonitorChromeOS::CheckMemoryPressure() {
139 MemoryPressureListener::MemoryPressureLevel old_pressure = 170 MemoryPressureListener::MemoryPressureLevel old_pressure =
140 current_memory_pressure_level_; 171 current_memory_pressure_level_;
141 current_memory_pressure_level_ = 172
142 GetMemoryPressureLevelFromFillLevel(GetUsedMemoryInPercent(), 173 // If we have the kernel low memory observer, we use it's flag instead of our
143 moderate_pressure_threshold_percent_, 174 // own computation (for now). Note that in "simulation mode" it can be null.
144 critical_pressure_threshold_percent_); 175 // TODO(skuhne): We need to add code which makes sure that the kernel and this
176 // computation come to similar results and then remove this override again.
177 // TODO(skuhne): Add some testing framework here to see how close the kernel
178 // and the internal functions are.
179 if (low_mem_file_.is_valid() && IsLowMemoryCondition(low_mem_file_.get())) {
180 current_memory_pressure_level_ =
181 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
182 } else {
183 current_memory_pressure_level_ = GetMemoryPressureLevelFromFillLevel(
184 GetUsedMemoryInPercent(),
185 moderate_pressure_threshold_percent_,
186 critical_pressure_threshold_percent_);
187
188 // When listening to the kernel, we ignore the reported memory pressure
189 // level from our own computation and reduce critical to moderate.
190 if (low_mem_file_.is_valid() &&
191 current_memory_pressure_level_ ==
192 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
193 current_memory_pressure_level_ =
194 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
195 }
196 }
197
145 // In case there is no memory pressure we do not notify. 198 // In case there is no memory pressure we do not notify.
146 if (current_memory_pressure_level_ == 199 if (current_memory_pressure_level_ ==
147 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { 200 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
148 return; 201 return;
149 } 202 }
150 if (old_pressure == current_memory_pressure_level_) { 203 if (old_pressure == current_memory_pressure_level_) {
151 // If the memory pressure is still at the same level, we notify again for a 204 // If the memory pressure is still at the same level, we notify again for a
152 // critical level. In case of a moderate level repeat however, we only send 205 // critical level. In case of a moderate level repeat however, we only send
153 // a notification after a certain time has passed. 206 // a notification after a certain time has passed.
154 if (current_memory_pressure_level_ == 207 if (current_memory_pressure_level_ ==
155 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE && 208 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE &&
156 ++moderate_pressure_repeat_count_ < 209 ++moderate_pressure_repeat_count_ <
157 kModerateMemoryPressureCooldown) { 210 kModerateMemoryPressureCooldown) {
158 return; 211 return;
159 } 212 }
160 } else if (current_memory_pressure_level_ == 213 } else if (current_memory_pressure_level_ ==
161 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE && 214 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE &&
162 old_pressure == 215 old_pressure ==
163 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { 216 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
164 // When we reducing the pressure level from critical to moderate, we 217 // When we reducing the pressure level from critical to moderate, we
165 // restart the timeout and do not send another notification. 218 // restart the timeout and do not send another notification.
166 moderate_pressure_repeat_count_ = 0; 219 moderate_pressure_repeat_count_ = 0;
167 return; 220 return;
168 } 221 }
169 moderate_pressure_repeat_count_ = 0; 222 moderate_pressure_repeat_count_ = 0;
170 MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_); 223 MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
171 } 224 }
172 225
173 // Gets the used ChromeOS memory in percent. 226 // Gets the used ChromeOS memory in percent.
174 int MemoryPressureObserverChromeOS::GetUsedMemoryInPercent() { 227 int MemoryPressureMonitorChromeOS::GetUsedMemoryInPercent() {
175 base::SystemMemoryInfoKB info; 228 base::SystemMemoryInfoKB info;
176 if (!base::GetSystemMemoryInfo(&info)) { 229 if (!base::GetSystemMemoryInfo(&info)) {
177 VLOG(1) << "Cannot determine the free memory of the system."; 230 VLOG(1) << "Cannot determine the free memory of the system.";
178 return 0; 231 return 0;
179 } 232 }
180 // TODO(skuhne): Instead of adding the kernel memory pressure calculation 233 // TODO(skuhne): Instead of adding the kernel memory pressure calculation
181 // logic here, we should have a kernel mechanism similar to the low memory 234 // logic here, we should have a kernel mechanism similar to the low memory
182 // notifier in ChromeOS which offers multiple pressure states. 235 // notifier in ChromeOS which offers multiple pressure states.
183 // To track this, we have crbug.com/381196. 236 // To track this, we have crbug.com/381196.
184 237
(...skipping 17 matching lines...) Expand all
202 // Available memory is the sum of free, swap and easy reclaimable memory. 255 // Available memory is the sum of free, swap and easy reclaimable memory.
203 int available_memory = 256 int available_memory =
204 info.free + info.swap_free / kSwapWeight + file_memory; 257 info.free + info.swap_free / kSwapWeight + file_memory;
205 258
206 DCHECK(available_memory < total_memory); 259 DCHECK(available_memory < total_memory);
207 int percentage = ((total_memory - available_memory) * 100) / total_memory; 260 int percentage = ((total_memory - available_memory) * 100) / total_memory;
208 return percentage; 261 return percentage;
209 } 262 }
210 263
211 } // namespace base 264 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698