 Chromium Code Reviews
 Chromium Code Reviews Issue 1250093006:
  Added memory pressure monitor for linux.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 1250093006:
  Added memory pressure monitor for linux.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| 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 45% | 
| copy from base/memory/memory_pressure_monitor_chromeos.cc | 
| copy to base/memory/memory_pressure_monitor_linux.cc | 
| index 640e4633fd51c7cb9d3e820af18c62a17ea14f0b..706ad1f60c6f797b8226674fc7d1551fd32ada9e 100644 | 
| --- a/base/memory/memory_pressure_monitor_chromeos.cc | 
| +++ b/base/memory/memory_pressure_monitor_linux.cc | 
| @@ -1,21 +1,17 @@ | 
| -// 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_linux.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 nix { | 
| namespace { | 
| @@ -33,88 +29,35 @@ 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, | 
| 
chrisha
2015/07/24 13:25:45
If we're going to change the name here, I'd make i
 
proberge
2015/07/24 14:37:37
It's to be consistent with the enum in memory_pres
 | 
| + 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) { | 
| StartObserving(); | 
| - LOG_IF(ERROR, !low_mem_file_.is_valid()) << "Cannot open kernel listener"; | 
| } | 
| MemoryPressureMonitor::~MemoryPressureMonitor() { | 
| @@ -139,11 +82,10 @@ MemoryPressureMonitor* 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,22 +97,22 @@ 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() { | 
| @@ -183,44 +125,28 @@ void MemoryPressureMonitor::CheckMemoryPressure() { | 
| // 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. | 
| 
chrisha
2015/07/24 13:25:45
These comments probably don't apply to the Linux o
 
proberge
2015/07/24 14:37:37
Done.
 | 
| - 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 +156,24 @@ 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; | 
| 
chrisha
2015/07/24 13:25:45
Is this not also true on Linux? ChromeOS is linux
 
proberge
2015/07/24 14:37:37
My methodology could be wrong (writing large files
 | 
| - // 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 nix | 
| } // namespace base |