Index: base/memory/memory_pressure_monitor_linux.cc |
diff --git a/base/memory/memory_pressure_monitor_chromeos.cc b/base/memory/memory_pressure_monitor_linux.cc |
similarity index 39% |
copy from base/memory/memory_pressure_monitor_chromeos.cc |
copy to base/memory/memory_pressure_monitor_linux.cc |
index 640e4633fd51c7cb9d3e820af18c62a17ea14f0b..7034e14b7cacd7ed9a327b9febb13a892d025c26 100644 |
--- a/base/memory/memory_pressure_monitor_chromeos.cc |
+++ b/base/memory/memory_pressure_monitor_linux.cc |
@@ -1,21 +1,16 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
+// 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_chromeos.h" |
- |
-#include <fcntl.h> |
-#include <sys/select.h> |
+#include "base/memory/memory_pressure_monitor.h" |
#include "base/metrics/histogram_macros.h" |
-#include "base/posix/eintr_wrapper.h" |
#include "base/process/process_metrics.h" |
#include "base/single_thread_task_runner.h" |
#include "base/thread_task_runner_handle.h" |
#include "base/time/time.h" |
namespace base { |
-namespace chromeos { |
namespace { |
@@ -33,91 +28,44 @@ const int kModerateMemoryPressureCooldown = |
// Threshold constants to emit pressure events. |
const int kNormalMemoryPressureModerateThresholdPercent = 60; |
const int kNormalMemoryPressureCriticalThresholdPercent = 95; |
-const int kAggressiveMemoryPressureModerateThresholdPercent = 35; |
-const int kAggressiveMemoryPressureCriticalThresholdPercent = 70; |
// The possible state for memory pressure level. The values should be in line |
// with values in MemoryPressureListener::MemoryPressureLevel and should be |
// updated if more memory pressure levels are introduced. |
enum MemoryPressureLevelUMA { |
- MEMORY_PRESSURE_LEVEL_NONE = 0, |
- MEMORY_PRESSURE_LEVEL_MODERATE, |
- MEMORY_PRESSURE_LEVEL_CRITICAL, |
- NUM_MEMORY_PRESSURE_LEVELS |
+ UMA_MEMORY_PRESSURE_LEVEL_NONE = 0, |
+ UMA_MEMORY_PRESSURE_LEVEL_MODERATE = 1, |
+ UMA_MEMORY_PRESSURE_LEVEL_CRITICAL = 2, |
+ // This must be the last value in the enum. |
+ UMA_MEMORY_PRESSURE_LEVEL_COUNT, |
}; |
-// 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( |
- MemoryPressureMonitor::MemoryPressureThresholds thresholds) { |
- return thresholds == MemoryPressureMonitor:: |
- THRESHOLD_AGGRESSIVE_CACHE_DISCARD || |
- thresholds == MemoryPressureMonitor::THRESHOLD_AGGRESSIVE |
- ? kAggressiveMemoryPressureModerateThresholdPercent |
- : kNormalMemoryPressureModerateThresholdPercent; |
-} |
- |
-// Converts a |MemoryPressureThreshold| value into a used memory percentage for |
-// the critical pressure event. |
-int GetCriticalMemoryThresholdInPercent( |
- MemoryPressureMonitor::MemoryPressureThresholds thresholds) { |
- return thresholds == MemoryPressureMonitor:: |
- THRESHOLD_AGGRESSIVE_TAB_DISCARD || |
- thresholds == MemoryPressureMonitor::THRESHOLD_AGGRESSIVE |
- ? kAggressiveMemoryPressureCriticalThresholdPercent |
- : kNormalMemoryPressureCriticalThresholdPercent; |
-} |
- |
// Converts free percent of memory into a memory pressure value. |
MemoryPressureListener::MemoryPressureLevel GetMemoryPressureLevelFromFillLevel( |
- int actual_fill_level, |
- int moderate_threshold, |
- int critical_threshold) { |
- if (actual_fill_level < moderate_threshold) |
+ int actual_fill_level) { |
+ if (actual_fill_level < kNormalMemoryPressureModerateThresholdPercent) |
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; |
- return actual_fill_level < critical_threshold |
+ return actual_fill_level < kNormalMemoryPressureCriticalThresholdPercent |
? MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE |
: 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 |
-MemoryPressureMonitor::MemoryPressureMonitor( |
- MemoryPressureThresholds thresholds) |
+MemoryPressureMonitor::MemoryPressureMonitor() |
: current_memory_pressure_level_( |
MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE), |
moderate_pressure_repeat_count_(0), |
- moderate_pressure_threshold_percent_( |
- GetModerateMemoryThresholdInPercent(thresholds)), |
- critical_pressure_threshold_percent_( |
- GetCriticalMemoryThresholdInPercent(thresholds)), |
- low_mem_file_(HANDLE_EINTR(::open(kLowMemFile, O_RDONLY))), |
weak_ptr_factory_(this) { |
+ DCHECK(!g_monitor); |
+ g_monitor = this; |
+ |
StartObserving(); |
- LOG_IF(ERROR, !low_mem_file_.is_valid()) << "Cannot open kernel listener"; |
} |
MemoryPressureMonitor::~MemoryPressureMonitor() { |
+ DCHECK(g_monitor); |
+ g_monitor = nullptr; |
+ |
StopObserving(); |
} |
@@ -132,18 +80,11 @@ MemoryPressureMonitor::GetCurrentPressureLevel() const { |
return current_memory_pressure_level_; |
} |
-// static |
-MemoryPressureMonitor* MemoryPressureMonitor::Get() { |
- return static_cast<MemoryPressureMonitor*>( |
- base::MemoryPressureMonitor::Get()); |
-} |
- |
void MemoryPressureMonitor::StartObserving() { |
- timer_.Start(FROM_HERE, |
- TimeDelta::FromMilliseconds(kMemoryPressureIntervalMs), |
- Bind(&MemoryPressureMonitor:: |
- CheckMemoryPressureAndRecordStatistics, |
- weak_ptr_factory_.GetWeakPtr())); |
+ timer_.Start( |
+ FROM_HERE, TimeDelta::FromMilliseconds(kMemoryPressureIntervalMs), |
+ Bind(&MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics, |
+ weak_ptr_factory_.GetWeakPtr())); |
} |
void MemoryPressureMonitor::StopObserving() { |
@@ -155,72 +96,49 @@ void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() { |
CheckMemoryPressure(); |
// Record UMA histogram statistics for the current memory pressure level. |
- MemoryPressureLevelUMA memory_pressure_level_uma(MEMORY_PRESSURE_LEVEL_NONE); |
+ MemoryPressureLevelUMA memory_pressure_level_uma( |
+ UMA_MEMORY_PRESSURE_LEVEL_NONE); |
switch (current_memory_pressure_level_) { |
case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: |
- memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_NONE; |
+ memory_pressure_level_uma = UMA_MEMORY_PRESSURE_LEVEL_NONE; |
break; |
case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: |
- memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_MODERATE; |
+ memory_pressure_level_uma = UMA_MEMORY_PRESSURE_LEVEL_MODERATE; |
break; |
case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: |
- memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_CRITICAL; |
+ memory_pressure_level_uma = UMA_MEMORY_PRESSURE_LEVEL_CRITICAL; |
break; |
} |
- UMA_HISTOGRAM_ENUMERATION("ChromeOS.MemoryPressureLevel", |
- memory_pressure_level_uma, |
- NUM_MEMORY_PRESSURE_LEVELS); |
+ UMA_HISTOGRAM_ENUMERATION("Memory.PressureLevel", memory_pressure_level_uma, |
+ UMA_MEMORY_PRESSURE_LEVEL_COUNT); |
} |
void MemoryPressureMonitor::CheckMemoryPressure() { |
MemoryPressureListener::MemoryPressureLevel old_pressure = |
current_memory_pressure_level_; |
- |
- // 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; |
- } |
- } |
+ current_memory_pressure_level_ = |
+ GetMemoryPressureLevelFromFillLevel(GetUsedMemoryInPercent()); |
// In case there is no memory pressure we do not notify. |
if (current_memory_pressure_level_ == |
MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { |
return; |
} |
+ |
if (old_pressure == current_memory_pressure_level_) { |
// If the memory pressure is still at the same level, we notify again for a |
// critical level. In case of a moderate level repeat however, we only send |
// a notification after a certain time has passed. |
if (current_memory_pressure_level_ == |
- MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE && |
- ++moderate_pressure_repeat_count_ < |
- kModerateMemoryPressureCooldown) { |
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE && |
+ ++moderate_pressure_repeat_count_ < kModerateMemoryPressureCooldown) { |
return; |
} |
} else if (current_memory_pressure_level_ == |
- MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE && |
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE && |
old_pressure == |
- MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { |
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { |
// When we reducing the pressure level from critical to moderate, we |
// restart the timeout and do not send another notification. |
moderate_pressure_repeat_count_ = 0; |
@@ -230,43 +148,22 @@ void MemoryPressureMonitor::CheckMemoryPressure() { |
MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_); |
} |
-// Gets the used ChromeOS memory in percent. |
+// Gets the used memory in percent. |
int MemoryPressureMonitor::GetUsedMemoryInPercent() { |
base::SystemMemoryInfoKB info; |
if (!base::GetSystemMemoryInfo(&info)) { |
VLOG(1) << "Cannot determine the free memory of the system."; |
return 0; |
} |
- // TODO(skuhne): Instead of adding the kernel memory pressure calculation |
- // logic here, we should have a kernel mechanism similar to the low memory |
- // notifier in ChromeOS which offers multiple pressure states. |
- // To track this, we have crbug.com/381196. |
- |
- // The available memory consists of "real" and virtual (z)ram memory. |
- // Since swappable memory uses a non pre-deterministic compression and |
- // the compression creates its own "dynamic" in the system, it gets |
- // de-emphasized by the |kSwapWeight| factor. |
- const int kSwapWeight = 4; |
- |
- // The total memory we have is the "real memory" plus the virtual (z)ram. |
- int total_memory = info.total + info.swap_total / kSwapWeight; |
- |
- // The kernel internally uses 50MB. |
- const int kMinFileMemory = 50 * 1024; |
- |
- // Most file memory can be easily reclaimed. |
- int file_memory = info.active_file + info.inactive_file; |
- // unless it is dirty or it's a minimal portion which is required. |
- file_memory -= info.dirty + kMinFileMemory; |
- // Available memory is the sum of free, swap and easy reclaimable memory. |
- int available_memory = |
- info.free + info.swap_free / kSwapWeight + file_memory; |
+ // Cast to int64 to avoid integer overflows when calculating the percentage. |
+ int64 total_memory = info.total; |
+ int64 available_memory = info.free; |
DCHECK(available_memory < total_memory); |
- int percentage = ((total_memory - available_memory) * 100) / total_memory; |
+ int percentage = static_cast<int>(((total_memory - available_memory) * 100) / |
+ total_memory); |
return percentage; |
} |
-} // namespace chromeos |
} // namespace base |