Index: base/chromeos/memory_pressure_monitor_chromeos.cc |
diff --git a/base/chromeos/memory_pressure_observer_chromeos.cc b/base/chromeos/memory_pressure_monitor_chromeos.cc |
similarity index 68% |
rename from base/chromeos/memory_pressure_observer_chromeos.cc |
rename to base/chromeos/memory_pressure_monitor_chromeos.cc |
index 5691eb8b4ed1dbd626e85ef1ea617886396eeafd..404c515c8040edb399c6b3715c6b8306a8fc47be 100644 |
--- a/base/chromeos/memory_pressure_observer_chromeos.cc |
+++ b/base/chromeos/memory_pressure_monitor_chromeos.cc |
@@ -2,10 +2,14 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "base/chromeos/memory_pressure_observer_chromeos.h" |
+#include "base/chromeos/memory_pressure_monitor_chromeos.h" |
+ |
+#include <fcntl.h> |
+#include <sys/select.h> |
#include "base/message_loop/message_loop.h" |
#include "base/metrics/histogram_macros.h" |
+#include "base/posix/eintr_wrapper.h" |
#include "base/process/process_metrics.h" |
#include "base/time/time.h" |
@@ -26,7 +30,7 @@ const int kModerateMemoryPressureCooldown = |
// Threshold constants to emit pressure events. |
const int kNormalMemoryPressureModerateThresholdPercent = 60; |
-const int kNormalMemoryPressureCriticalThresholdPercent = 90; |
+const int kNormalMemoryPressureCriticalThresholdPercent = 95; |
const int kAggressiveMemoryPressureModerateThresholdPercent = 35; |
const int kAggressiveMemoryPressureCriticalThresholdPercent = 70; |
@@ -40,13 +44,18 @@ enum MemoryPressureLevelUMA { |
NUM_MEMORY_PRESSURE_LEVELS |
}; |
+// This is the file that will exist if low memory notification is available |
+// on the device. Whenever it becomes readable, it signals a low memory |
+// condition. |
+const char kLowMemFile[] = "/dev/chromeos-low-mem"; |
+ |
// Converts a |MemoryPressureThreshold| value into a used memory percentage for |
// the moderate pressure event. |
int GetModerateMemoryThresholdInPercent( |
- MemoryPressureObserverChromeOS::MemoryPressureThresholds thresholds) { |
- return thresholds == MemoryPressureObserverChromeOS:: |
+ MemoryPressureMonitorChromeOS::MemoryPressureThresholds thresholds) { |
+ return thresholds == MemoryPressureMonitorChromeOS:: |
THRESHOLD_AGGRESSIVE_CACHE_DISCARD || |
- thresholds == MemoryPressureObserverChromeOS::THRESHOLD_AGGRESSIVE |
+ thresholds == MemoryPressureMonitorChromeOS::THRESHOLD_AGGRESSIVE |
? kAggressiveMemoryPressureModerateThresholdPercent |
: kNormalMemoryPressureModerateThresholdPercent; |
} |
@@ -54,10 +63,10 @@ int GetModerateMemoryThresholdInPercent( |
// Converts a |MemoryPressureThreshold| value into a used memory percentage for |
// the critical pressure event. |
int GetCriticalMemoryThresholdInPercent( |
- MemoryPressureObserverChromeOS::MemoryPressureThresholds thresholds) { |
- return thresholds == MemoryPressureObserverChromeOS:: |
+ MemoryPressureMonitorChromeOS::MemoryPressureThresholds thresholds) { |
+ return thresholds == MemoryPressureMonitorChromeOS:: |
THRESHOLD_AGGRESSIVE_TAB_DISCARD || |
- thresholds == MemoryPressureObserverChromeOS::THRESHOLD_AGGRESSIVE |
+ thresholds == MemoryPressureMonitorChromeOS::THRESHOLD_AGGRESSIVE |
? kAggressiveMemoryPressureCriticalThresholdPercent |
: kNormalMemoryPressureCriticalThresholdPercent; |
} |
@@ -74,9 +83,24 @@ MemoryPressureListener::MemoryPressureLevel GetMemoryPressureLevelFromFillLevel( |
: MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; |
} |
+// This function will be called less then once a second. It will check if |
+// the kernel has detected a low memory situation. |
+bool IsLowMemoryCondition(int file_descriptor) { |
+ fd_set fds; |
+ struct timeval tv; |
+ |
+ FD_ZERO(&fds); |
+ FD_SET(file_descriptor, &fds); |
+ |
+ tv.tv_sec = 0; |
+ tv.tv_usec = 0; |
+ |
+ return HANDLE_EINTR(select(file_descriptor + 1, &fds, NULL, NULL, &tv)) > 0; |
+} |
+ |
} // namespace |
-MemoryPressureObserverChromeOS::MemoryPressureObserverChromeOS( |
+MemoryPressureMonitorChromeOS::MemoryPressureMonitorChromeOS( |
MemoryPressureThresholds thresholds) |
: current_memory_pressure_level_( |
MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE), |
@@ -85,35 +109,42 @@ MemoryPressureObserverChromeOS::MemoryPressureObserverChromeOS( |
GetModerateMemoryThresholdInPercent(thresholds)), |
critical_pressure_threshold_percent_( |
GetCriticalMemoryThresholdInPercent(thresholds)), |
+ low_mem_file_(HANDLE_EINTR(::open(kLowMemFile, O_RDONLY))), |
weak_ptr_factory_(this) { |
StartObserving(); |
+ LOG_IF(ERROR, !low_mem_file_.is_valid()) << "Cannot open kernel listener"; |
} |
-MemoryPressureObserverChromeOS::~MemoryPressureObserverChromeOS() { |
+MemoryPressureMonitorChromeOS::~MemoryPressureMonitorChromeOS() { |
StopObserving(); |
} |
-void MemoryPressureObserverChromeOS::ScheduleEarlyCheck() { |
+void MemoryPressureMonitorChromeOS::ScheduleEarlyCheck() { |
MessageLoop::current()->PostTask( |
FROM_HERE, |
- Bind(&MemoryPressureObserverChromeOS::CheckMemoryPressure, |
+ Bind(&MemoryPressureMonitorChromeOS::CheckMemoryPressure, |
weak_ptr_factory_.GetWeakPtr())); |
} |
-void MemoryPressureObserverChromeOS::StartObserving() { |
+MemoryPressureListener::MemoryPressureLevel |
+MemoryPressureMonitorChromeOS::GetCurrentPressureLevel() const { |
+ return current_memory_pressure_level_; |
+} |
+ |
+void MemoryPressureMonitorChromeOS::StartObserving() { |
timer_.Start(FROM_HERE, |
TimeDelta::FromMilliseconds(kMemoryPressureIntervalMs), |
- Bind(&MemoryPressureObserverChromeOS:: |
+ Bind(&MemoryPressureMonitorChromeOS:: |
CheckMemoryPressureAndRecordStatistics, |
weak_ptr_factory_.GetWeakPtr())); |
} |
-void MemoryPressureObserverChromeOS::StopObserving() { |
+void MemoryPressureMonitorChromeOS::StopObserving() { |
// If StartObserving failed, StopObserving will still get called. |
timer_.Stop(); |
} |
-void MemoryPressureObserverChromeOS::CheckMemoryPressureAndRecordStatistics() { |
+void MemoryPressureMonitorChromeOS::CheckMemoryPressureAndRecordStatistics() { |
CheckMemoryPressure(); |
// Record UMA histogram statistics for the current memory pressure level. |
@@ -135,13 +166,35 @@ void MemoryPressureObserverChromeOS::CheckMemoryPressureAndRecordStatistics() { |
NUM_MEMORY_PRESSURE_LEVELS); |
} |
-void MemoryPressureObserverChromeOS::CheckMemoryPressure() { |
+void MemoryPressureMonitorChromeOS::CheckMemoryPressure() { |
MemoryPressureListener::MemoryPressureLevel old_pressure = |
current_memory_pressure_level_; |
- current_memory_pressure_level_ = |
- GetMemoryPressureLevelFromFillLevel(GetUsedMemoryInPercent(), |
- moderate_pressure_threshold_percent_, |
- critical_pressure_threshold_percent_); |
+ |
+ // If we have the kernel low memory observer, we use it's flag instead of our |
+ // own computation (for now). Note that in "simulation mode" it can be null. |
+ // TODO(skuhne): We need to add code which makes sure that the kernel and this |
+ // computation come to similar results and then remove this override again. |
+ // TODO(skuhne): Add some testing framework here to see how close the kernel |
+ // and the internal functions are. |
+ if (low_mem_file_.is_valid() && IsLowMemoryCondition(low_mem_file_.get())) { |
+ current_memory_pressure_level_ = |
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; |
+ } else { |
+ current_memory_pressure_level_ = GetMemoryPressureLevelFromFillLevel( |
+ GetUsedMemoryInPercent(), |
+ moderate_pressure_threshold_percent_, |
+ critical_pressure_threshold_percent_); |
+ |
+ // When listening to the kernel, we ignore the reported memory pressure |
+ // level from our own computation and reduce critical to moderate. |
+ if (low_mem_file_.is_valid() && |
+ current_memory_pressure_level_ == |
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { |
+ current_memory_pressure_level_ = |
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; |
+ } |
+ } |
+ |
// In case there is no memory pressure we do not notify. |
if (current_memory_pressure_level_ == |
MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { |
@@ -171,7 +224,7 @@ void MemoryPressureObserverChromeOS::CheckMemoryPressure() { |
} |
// Gets the used ChromeOS memory in percent. |
-int MemoryPressureObserverChromeOS::GetUsedMemoryInPercent() { |
+int MemoryPressureMonitorChromeOS::GetUsedMemoryInPercent() { |
base::SystemMemoryInfoKB info; |
if (!base::GetSystemMemoryInfo(&info)) { |
VLOG(1) << "Cannot determine the free memory of the system."; |