123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- // Copyright 2020 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 "components/memory_pressure/system_memory_pressure_evaluator_linux.h"
- #include "base/bind.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/process/process_metrics.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/task/task_traits.h"
- #include "base/threading/sequenced_task_runner_handle.h"
- #include "base/time/time.h"
- #include "components/memory_pressure/multi_source_memory_pressure_monitor.h"
- namespace {
- constexpr int kKiBperMiB = 1024;
- int GetAvailableSystemMemoryMiB(const base::SystemMemoryInfoKB& mem_info) {
- // Use 'available' metric if is is present,
- // if no (kernels < 3.14), let's make a rough evaluation using free physical
- // memory plus buffers and caches (that OS can free in case of low memory
- // state)
- int mem_available =
- mem_info.available ? mem_info.available
- : (mem_info.free + mem_info.buffers + mem_info.cached);
- // How much physical memory is actively available for use right now, in MBs.
- return mem_available / kKiBperMiB;
- }
- } // namespace
- namespace memory_pressure {
- namespace os_linux {
- const base::TimeDelta SystemMemoryPressureEvaluator::kMemorySamplingPeriod =
- base::Seconds(5);
- const base::TimeDelta SystemMemoryPressureEvaluator::kModeratePressureCooldown =
- base::Seconds(10);
- const int SystemMemoryPressureEvaluator::kDefaultModerateThresholdPc = 75;
- const int SystemMemoryPressureEvaluator::kDefaultCriticalThresholdPc = 85;
- SystemMemoryPressureEvaluator::SystemMemoryPressureEvaluator(
- std::unique_ptr<MemoryPressureVoter> voter)
- : memory_pressure::SystemMemoryPressureEvaluator(std::move(voter)),
- moderate_pressure_repeat_count_(0) {
- if (InferThresholds())
- StartObserving();
- }
- SystemMemoryPressureEvaluator::SystemMemoryPressureEvaluator(
- int moderate_threshold_mb,
- int critical_threshold_mb,
- std::unique_ptr<MemoryPressureVoter> voter)
- : memory_pressure::SystemMemoryPressureEvaluator(std::move(voter)),
- moderate_threshold_mb_(moderate_threshold_mb),
- critical_threshold_mb_(critical_threshold_mb),
- moderate_pressure_repeat_count_(0) {
- DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
- DCHECK_GT(critical_threshold_mb_, 0);
- StartObserving();
- }
- void SystemMemoryPressureEvaluator::StartObserving() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- timer_.Start(
- FROM_HERE, kMemorySamplingPeriod,
- base::BindRepeating(&SystemMemoryPressureEvaluator::CheckMemoryPressure,
- base::Unretained(this)));
- }
- void SystemMemoryPressureEvaluator::StopObserving() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // If StartObserving failed, StopObserving will still get called.
- timer_.Stop();
- }
- bool SystemMemoryPressureEvaluator::GetSystemMemoryInfo(
- base::SystemMemoryInfoKB* mem_info) {
- return base::GetSystemMemoryInfo(mem_info);
- }
- void SystemMemoryPressureEvaluator::CheckMemoryPressure() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // Get the previous pressure level and update the current one.
- MemoryPressureLevel old_vote = current_vote();
- SetCurrentVote(CalculateCurrentPressureLevel());
- // |notify| will be set to true if MemoryPressureListeners need to be
- // notified of a memory pressure level state change.
- bool notify = false;
- switch (current_vote()) {
- case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
- break;
- case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
- if (old_vote != current_vote()) {
- // This is a new transition to moderate pressure so notify.
- moderate_pressure_repeat_count_ = 0;
- notify = true;
- } else {
- // Already in moderate pressure, only notify if sustained over the
- // cooldown period.
- const int kModeratePressureCooldownCycles =
- kModeratePressureCooldown / kMemorySamplingPeriod;
- if (++moderate_pressure_repeat_count_ ==
- kModeratePressureCooldownCycles) {
- moderate_pressure_repeat_count_ = 0;
- notify = true;
- }
- }
- break;
- case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
- // Always notify of critical pressure levels.
- notify = true;
- break;
- }
- SendCurrentVote(notify);
- }
- bool SystemMemoryPressureEvaluator::InferThresholds() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- base::SystemMemoryInfoKB mem_info;
- if (!GetSystemMemoryInfo(&mem_info))
- return false;
- // The computation of the different thresholds assumes that
- // SystemMemoryInfoKB::total is stored as an integer and so the result of
- // |static_cast<uint64_t>(mem_info.total) * (100 - kThresholdPc)| won't
- // overflow.
- static_assert(
- std::is_same<decltype(mem_info.total), int>::value,
- "SystemMemoryInfoKB::total is expected to be stored as an integer.");
- critical_threshold_mb_ = base::checked_cast<int>(
- static_cast<uint64_t>(mem_info.total) *
- (100 - kDefaultCriticalThresholdPc) / 100 / kKiBperMiB);
- moderate_threshold_mb_ = base::checked_cast<int>(
- static_cast<uint64_t>(mem_info.total) *
- (100 - kDefaultModerateThresholdPc) / 100 / kKiBperMiB);
- return true;
- }
- base::MemoryPressureListener::MemoryPressureLevel
- SystemMemoryPressureEvaluator::CalculateCurrentPressureLevel() {
- base::SystemMemoryInfoKB mem_info;
- if (GetSystemMemoryInfo(&mem_info)) {
- // How much system memory is actively available for use right now, in MBs.
- int available = GetAvailableSystemMemoryMiB(mem_info);
- // Determine if the available memory is under critical memory pressure.
- if (available <= critical_threshold_mb_)
- return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
- // Determine if the available memory is under moderate memory pressure.
- if (available <= moderate_threshold_mb_)
- return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
- }
- // No memory pressure was detected.
- return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
- }
- } // namespace os_linux
- } // namespace memory_pressure
|