File: direct_memory_pressure_calculator_linux.cc

package info (click to toggle)
chromium-browser 57.0.2987.98-1~deb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 2,637,852 kB
  • ctags: 2,544,394
  • sloc: cpp: 12,815,961; ansic: 3,676,222; python: 1,147,112; asm: 526,608; java: 523,212; xml: 286,794; perl: 92,654; sh: 86,408; objc: 73,271; makefile: 27,698; cs: 18,487; yacc: 13,031; tcl: 12,957; pascal: 4,875; ml: 4,716; lex: 3,904; sql: 3,862; ruby: 1,982; lisp: 1,508; php: 1,368; exp: 404; awk: 325; csh: 117; jsp: 39; sed: 37
file content (169 lines) | stat: -rw-r--r-- 6,546 bytes parent folder | download
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