1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
// Copyright 2016 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/direct_memory_pressure_calculator_linux.h"
#include "base/files/file_util.h"
#include "base/process/process_metrics.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
#include "base/threading/thread_restrictions.h"
namespace memory_pressure {
namespace {
const int kKiBperMiB = 1024;
// Used to calculate a moving average of faults/sec. Our sample times are
// inconsistent because MemoryPressureMonitor calls
// CalculateCurrentPressureLevel more frequently when memory pressure is high,
// and because we're measuring CPU time instead of real time. So our
// exponentially weighted moving average is generalized to a low-pass filter.
//
// Represents the amount of CPU time, in seconds, for a sample to be 50%
// forgotten in our moving average. Systems with more CPUs that are under high
// load will have a moving average that changes more quickly than a system with
// fewer CPUs under the same load. Do not normalize based on the number of CPUs
// because this behavior is accurate: if a system with a large number of CPUs
// is getting lots of work done without page faulting, it must not be under
// memory pressure.
//
// TODO(thomasanderson): Experimentally determine the correct value for this
// constant.
const double kLowPassHalfLife = 30.0;
// Returns the amount of memory that is available for use right now, or that can
// be easily reclaimed by the OS, in MBs.
int GetAvailableSystemMemoryMiB(const base::SystemMemoryInfoKB* mem_info) {
return mem_info->available
? mem_info->available / kKiBperMiB
: (mem_info->free + mem_info->buffers + mem_info->cached) /
kKiBperMiB;
}
} // namespace
// Thresholds at which we consider the system being under moderate/critical
// memory pressure. They represent the percentage of system memory in use.
const int DirectMemoryPressureCalculator::kDefaultModerateThresholdPc = 70;
const int DirectMemoryPressureCalculator::kDefaultCriticalThresholdPc = 90;
DirectMemoryPressureCalculator::DirectMemoryPressureCalculator()
: moderate_threshold_mb_(0),
critical_threshold_mb_(0) {
InferThresholds();
InitPageFaultMonitor();
}
DirectMemoryPressureCalculator::DirectMemoryPressureCalculator(
int moderate_threshold_mb,
int critical_threshold_mb)
: moderate_threshold_mb_(moderate_threshold_mb),
critical_threshold_mb_(critical_threshold_mb) {
DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
DCHECK_LE(0, critical_threshold_mb_);
InitPageFaultMonitor();
}
DirectMemoryPressureCalculator::MemoryPressureLevel
DirectMemoryPressureCalculator::PressureCausedByThrashing(
const base::SystemMemoryInfoKB& mem_info) {
base::TimeDelta new_user_exec_time = GetUserCpuTimeSinceBoot();
if (new_user_exec_time == base::TimeDelta())
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
uint64_t new_major_page_faults = mem_info.pgmajfault;
if (new_user_exec_time != base::TimeDelta() && new_major_page_faults &&
(new_user_exec_time - last_user_exec_time_) != base::TimeDelta()) {
double delta_user_exec_time =
(new_user_exec_time - last_user_exec_time_).InSecondsF();
double delta_major_page_faults =
new_major_page_faults - last_major_page_faults_;
double sampled_faults_per_second =
delta_major_page_faults / delta_user_exec_time;
double adjusted_ewma_coefficient =
1 - exp2(-delta_user_exec_time / low_pass_half_life_seconds_);
current_faults_per_second_ =
adjusted_ewma_coefficient * sampled_faults_per_second +
(1 - adjusted_ewma_coefficient) * current_faults_per_second_;
last_user_exec_time_ = new_user_exec_time;
last_major_page_faults_ = new_major_page_faults;
}
if (current_faults_per_second_ >
critical_multiplier_ * AverageFaultsPerSecond()) {
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
}
if (current_faults_per_second_ >
moderate_multiplier_ * AverageFaultsPerSecond()) {
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
}
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
}
DirectMemoryPressureCalculator::MemoryPressureLevel
DirectMemoryPressureCalculator::PressureCausedByOOM(
const base::SystemMemoryInfoKB& mem_info) {
int phys_free = GetAvailableSystemMemoryMiB(&mem_info);
if (phys_free <= critical_threshold_mb_)
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
if (phys_free <= moderate_threshold_mb_)
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
}
DirectMemoryPressureCalculator::MemoryPressureLevel
DirectMemoryPressureCalculator::CalculateCurrentPressureLevel() {
base::SystemMemoryInfoKB mem_info = {};
if (!GetSystemMemoryInfo(&mem_info))
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
return std::max(PressureCausedByThrashing(mem_info),
PressureCausedByOOM(mem_info));
}
bool DirectMemoryPressureCalculator::GetSystemMemoryInfo(
base::SystemMemoryInfoKB* mem_info) const {
return base::GetSystemMemoryInfo(mem_info);
}
base::TimeDelta DirectMemoryPressureCalculator::GetUserCpuTimeSinceBoot()
const {
return base::GetUserCpuTimeSinceBoot();
}
void DirectMemoryPressureCalculator::InferThresholds() {
base::SystemMemoryInfoKB mem_info = {};
if (!GetSystemMemoryInfo(&mem_info))
return;
moderate_threshold_mb_ =
mem_info.total * (100 - kDefaultModerateThresholdPc) / 100 / kKiBperMiB;
critical_threshold_mb_ =
mem_info.total * (100 - kDefaultCriticalThresholdPc) / 100 / kKiBperMiB;
}
void DirectMemoryPressureCalculator::InitPageFaultMonitor() {
low_pass_half_life_seconds_ = kLowPassHalfLife;
last_user_exec_time_ = GetUserCpuTimeSinceBoot();
base::SystemMemoryInfoKB mem_info = {};
last_major_page_faults_ =
GetSystemMemoryInfo(&mem_info) ? mem_info.pgmajfault : 0;
current_faults_per_second_ = AverageFaultsPerSecond();
}
double DirectMemoryPressureCalculator::AverageFaultsPerSecond() const {
return last_major_page_faults_ == 0
? last_user_exec_time_.InSecondsF() / last_major_page_faults_
: 0;
}
} // namespace memory_pressure
|