| OLD | NEW |
| 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/memory/memory_pressure_monitor_chromeos.h" | 5 #include "base/memory/memory_pressure_monitor_chromeos.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include "base/memory/ptr_util.h" |
| 8 #include <sys/select.h> | |
| 9 | |
| 10 #include "base/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
| 11 #include "base/posix/eintr_wrapper.h" | |
| 12 #include "base/process/process_metrics.h" | 9 #include "base/process/process_metrics.h" |
| 13 #include "base/single_thread_task_runner.h" | 10 #include "base/single_thread_task_runner.h" |
| 14 #include "base/sys_info.h" | |
| 15 #include "base/threading/thread_task_runner_handle.h" | 11 #include "base/threading/thread_task_runner_handle.h" |
| 16 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 17 | 13 |
| 18 namespace base { | 14 namespace base { |
| 19 namespace chromeos { | 15 namespace chromeos { |
| 20 | 16 |
| 21 namespace { | 17 namespace { |
| 22 | 18 |
| 23 // The time between memory pressure checks. While under critical pressure, this | 19 // The time between memory pressure checks. While under critical pressure, this |
| 24 // is also the timer to repeat cleanup attempts. | 20 // is also the timer to repeat cleanup attempts. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 40 // The possible state for memory pressure level. The values should be in line | 36 // The possible state for memory pressure level. The values should be in line |
| 41 // with values in MemoryPressureListener::MemoryPressureLevel and should be | 37 // with values in MemoryPressureListener::MemoryPressureLevel and should be |
| 42 // updated if more memory pressure levels are introduced. | 38 // updated if more memory pressure levels are introduced. |
| 43 enum MemoryPressureLevelUMA { | 39 enum MemoryPressureLevelUMA { |
| 44 MEMORY_PRESSURE_LEVEL_NONE = 0, | 40 MEMORY_PRESSURE_LEVEL_NONE = 0, |
| 45 MEMORY_PRESSURE_LEVEL_MODERATE, | 41 MEMORY_PRESSURE_LEVEL_MODERATE, |
| 46 MEMORY_PRESSURE_LEVEL_CRITICAL, | 42 MEMORY_PRESSURE_LEVEL_CRITICAL, |
| 47 NUM_MEMORY_PRESSURE_LEVELS | 43 NUM_MEMORY_PRESSURE_LEVELS |
| 48 }; | 44 }; |
| 49 | 45 |
| 50 // This is the file that will exist if low memory notification is available | |
| 51 // on the device. Whenever it becomes readable, it signals a low memory | |
| 52 // condition. | |
| 53 const char kLowMemFile[] = "/dev/chromeos-low-mem"; | |
| 54 | |
| 55 // Converts a |MemoryPressureThreshold| value into a used memory percentage for | 46 // Converts a |MemoryPressureThreshold| value into a used memory percentage for |
| 56 // the moderate pressure event. | 47 // the moderate pressure event. |
| 57 int GetModerateMemoryThresholdInPercent( | 48 int GetModerateMemoryThresholdInPercent( |
| 58 MemoryPressureMonitor::MemoryPressureThresholds thresholds) { | 49 MemoryPressureMonitor::MemoryPressureThresholds thresholds) { |
| 59 return thresholds == MemoryPressureMonitor:: | 50 return thresholds == MemoryPressureMonitor:: |
| 60 THRESHOLD_AGGRESSIVE_CACHE_DISCARD || | 51 THRESHOLD_AGGRESSIVE_CACHE_DISCARD || |
| 61 thresholds == MemoryPressureMonitor::THRESHOLD_AGGRESSIVE | 52 thresholds == MemoryPressureMonitor::THRESHOLD_AGGRESSIVE |
| 62 ? kAggressiveMemoryPressureModerateThresholdPercent | 53 ? kAggressiveMemoryPressureModerateThresholdPercent |
| 63 : kNormalMemoryPressureModerateThresholdPercent; | 54 : kNormalMemoryPressureModerateThresholdPercent; |
| 64 } | 55 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 79 int actual_fill_level, | 70 int actual_fill_level, |
| 80 int moderate_threshold, | 71 int moderate_threshold, |
| 81 int critical_threshold) { | 72 int critical_threshold) { |
| 82 if (actual_fill_level < moderate_threshold) | 73 if (actual_fill_level < moderate_threshold) |
| 83 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; | 74 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; |
| 84 return actual_fill_level < critical_threshold | 75 return actual_fill_level < critical_threshold |
| 85 ? MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE | 76 ? MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE |
| 86 : MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; | 77 : MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; |
| 87 } | 78 } |
| 88 | 79 |
| 89 // This function will be called less than once a second. It will check if | |
| 90 // the kernel has detected a low memory situation. | |
| 91 bool IsLowMemoryCondition(int file_descriptor) { | |
| 92 fd_set fds; | |
| 93 struct timeval tv; | |
| 94 | |
| 95 FD_ZERO(&fds); | |
| 96 FD_SET(file_descriptor, &fds); | |
| 97 | |
| 98 tv.tv_sec = 0; | |
| 99 tv.tv_usec = 0; | |
| 100 | |
| 101 return HANDLE_EINTR(select(file_descriptor + 1, &fds, NULL, NULL, &tv)) > 0; | |
| 102 } | |
| 103 | |
| 104 } // namespace | 80 } // namespace |
| 105 | 81 |
| 106 MemoryPressureMonitor::MemoryPressureMonitor( | 82 MemoryPressureMonitor::MemoryPressureMonitor( |
| 107 MemoryPressureThresholds thresholds) | 83 MemoryPressureThresholds thresholds) |
| 108 : current_memory_pressure_level_( | 84 : current_memory_pressure_level_( |
| 109 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE), | 85 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE), |
| 110 moderate_pressure_repeat_count_(0), | 86 moderate_pressure_repeat_count_(0), |
| 111 seconds_since_reporting_(0), | 87 seconds_since_reporting_(0), |
| 112 moderate_pressure_threshold_percent_( | 88 moderate_pressure_threshold_percent_( |
| 113 GetModerateMemoryThresholdInPercent(thresholds)), | 89 GetModerateMemoryThresholdInPercent(thresholds)), |
| 114 critical_pressure_threshold_percent_( | 90 critical_pressure_threshold_percent_( |
| 115 GetCriticalMemoryThresholdInPercent(thresholds)), | 91 GetCriticalMemoryThresholdInPercent(thresholds)), |
| 116 low_mem_file_(HANDLE_EINTR(::open(kLowMemFile, O_RDONLY))), | 92 low_mem_observer_(base::MakeUnique<LowMemoryObserver>()), |
| 117 dispatch_callback_( | 93 dispatch_callback_( |
| 118 base::Bind(&MemoryPressureListener::NotifyMemoryPressure)), | 94 base::Bind(&MemoryPressureListener::NotifyMemoryPressure)), |
| 119 weak_ptr_factory_(this) { | 95 weak_ptr_factory_(this) { |
| 120 StartObserving(); | 96 StartObserving(); |
| 121 LOG_IF(ERROR, | |
| 122 base::SysInfo::IsRunningOnChromeOS() && !low_mem_file_.is_valid()) | |
| 123 << "Cannot open kernel listener"; | |
| 124 } | 97 } |
| 125 | 98 |
| 126 MemoryPressureMonitor::~MemoryPressureMonitor() { | 99 MemoryPressureMonitor::~MemoryPressureMonitor() { |
| 127 StopObserving(); | 100 StopObserving(); |
| 128 } | 101 } |
| 129 | 102 |
| 130 void MemoryPressureMonitor::ScheduleEarlyCheck() { | 103 void MemoryPressureMonitor::ScheduleEarlyCheck() { |
| 131 ThreadTaskRunnerHandle::Get()->PostTask( | 104 ThreadTaskRunnerHandle::Get()->PostTask( |
| 132 FROM_HERE, Bind(&MemoryPressureMonitor::CheckMemoryPressure, | 105 FROM_HERE, Bind(&MemoryPressureMonitor::CheckMemoryPressure, |
| 133 weak_ptr_factory_.GetWeakPtr())); | 106 weak_ptr_factory_.GetWeakPtr())); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 void MemoryPressureMonitor::CheckMemoryPressure() { | 160 void MemoryPressureMonitor::CheckMemoryPressure() { |
| 188 MemoryPressureListener::MemoryPressureLevel old_pressure = | 161 MemoryPressureListener::MemoryPressureLevel old_pressure = |
| 189 current_memory_pressure_level_; | 162 current_memory_pressure_level_; |
| 190 | 163 |
| 191 // If we have the kernel low memory observer, we use it's flag instead of our | 164 // If we have the kernel low memory observer, we use it's flag instead of our |
| 192 // own computation (for now). Note that in "simulation mode" it can be null. | 165 // own computation (for now). Note that in "simulation mode" it can be null. |
| 193 // TODO(skuhne): We need to add code which makes sure that the kernel and this | 166 // TODO(skuhne): We need to add code which makes sure that the kernel and this |
| 194 // computation come to similar results and then remove this override again. | 167 // computation come to similar results and then remove this override again. |
| 195 // TODO(skuhne): Add some testing framework here to see how close the kernel | 168 // TODO(skuhne): Add some testing framework here to see how close the kernel |
| 196 // and the internal functions are. | 169 // and the internal functions are. |
| 197 if (low_mem_file_.is_valid() && IsLowMemoryCondition(low_mem_file_.get())) { | 170 if (low_mem_observer_->IsLowMemoryCondition()) { |
| 198 current_memory_pressure_level_ = | 171 current_memory_pressure_level_ = |
| 199 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; | 172 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; |
| 200 } else { | 173 } else { |
| 201 current_memory_pressure_level_ = GetMemoryPressureLevelFromFillLevel( | 174 current_memory_pressure_level_ = GetMemoryPressureLevelFromFillLevel( |
| 202 GetUsedMemoryInPercent(), | 175 GetUsedMemoryInPercent(), |
| 203 moderate_pressure_threshold_percent_, | 176 moderate_pressure_threshold_percent_, |
| 204 critical_pressure_threshold_percent_); | 177 critical_pressure_threshold_percent_); |
| 205 | 178 |
| 206 // When listening to the kernel, we ignore the reported memory pressure | 179 // When listening to the kernel, we ignore the reported memory pressure |
| 207 // level from our own computation and reduce critical to moderate. | 180 // level from our own computation and reduce critical to moderate. |
| 208 if (low_mem_file_.is_valid() && | 181 if (low_mem_observer_->is_valid() && |
| 209 current_memory_pressure_level_ == | 182 current_memory_pressure_level_ == |
| 210 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { | 183 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { |
| 211 current_memory_pressure_level_ = | 184 current_memory_pressure_level_ = |
| 212 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; | 185 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; |
| 213 } | 186 } |
| 214 } | 187 } |
| 215 | 188 |
| 216 // In case there is no memory pressure we do not notify. | 189 // In case there is no memory pressure we do not notify. |
| 217 if (current_memory_pressure_level_ == | 190 if (current_memory_pressure_level_ == |
| 218 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { | 191 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { |
| 219 return; | 192 return; |
| 220 } | 193 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 return percentage; | 252 return percentage; |
| 280 } | 253 } |
| 281 | 254 |
| 282 void MemoryPressureMonitor::SetDispatchCallback( | 255 void MemoryPressureMonitor::SetDispatchCallback( |
| 283 const DispatchCallback& callback) { | 256 const DispatchCallback& callback) { |
| 284 dispatch_callback_ = callback; | 257 dispatch_callback_ = callback; |
| 285 } | 258 } |
| 286 | 259 |
| 287 } // namespace chromeos | 260 } // namespace chromeos |
| 288 } // namespace base | 261 } // namespace base |
| OLD | NEW |