File: memory_pressure_monitor.h

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 (210 lines) | stat: -rw-r--r-- 9,291 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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// 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.
//
// Declares the MemoryPressureMonitor class. This is responsible for monitoring
// system-wide memory pressure and dispatching memory pressure signals to
// MemoryPressureListener. It is also responsible for rate limiting calls to the
// memory pressure subsytem and gathering statistics for UMA.
//
// The class has a few compile time differences depending on if
// MEMORY_PRESSURE_IS_POLLING is defined. For Windows, ChromeOS and Linux
// the implementation is polling so MEMORY_PRESSURE_IS_POLLING is defined. For
// Mac, iOS and Android it is not defined.
//
// The difference is that "polling" platforms have no native OS signals
// indicating memory pressure. These platforms implement
// DirectMemoryPressureCalculator, which is polled on a schedule to check for
// memory pressure changes. On non-polling platforms the OS provides a native
// signal. This signal is observed by the platform-specific implementation of
// MemoryPressureMonitorImpl.
//
// The memory pressure system periodically repeats memory pressure signals while
// under memory pressure (the interval varying depending on the pressure level).
// As such, even non-polling platforms require a scheduling mechanism for
// repeating notifications. Both implementations share this basic scheduling
// subsystem, and also leverage it to make timely UMA reports.

#ifndef COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_MONITOR_H_
#define COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_MONITOR_H_

#include <map>
#include <memory>

#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "components/memory_pressure/memory_pressure_listener.h"

namespace base {
class TaskRunner;
class TickClock;
}  // namespace

namespace memory_pressure {

class MemoryPressureCalculator;
class MemoryPressureStatsCollector;

#if !defined(MEMORY_PRESSURE_IS_POLLING)
// For non-polling platform specific implementation details. An instance of
// this class will be encapsulated in the monitor. It will received an injected
// callback that routes messages to OnMemoryPressureChanged.
class MemoryPressureMonitorImpl;
#endif

// A thread-safe class for directly querying and automatically monitoring
// memory pressure. When system memory pressure levels change this class is
// responsible for notifying MemoryPressureListeners, and periodically
// renotifying them as conditions persist. This class will do its periodic work
// on the thread on which it was created. However, it is safe to call
// GetCurrentPressureLevel from any thread.
//
// This class doesn't make use of base::RepeatingTimer as it leaves an orphaned
// scheduled task every time it is canceled. This can occur every time a memory
// pressure level transition occurs, which has no strict upper bound. Instead
// a collection of at most "number of memory pressure level" scheduled tasks
// is used, with these tasks being reused as transition levels are crossed and
// polling requirements change. See |scheduled_checks_| and
// "ScheduleTaskIfNeededLocked" for details.
class MemoryPressureMonitor {
 public:
  using MemoryPressureLevel = MemoryPressureListener::MemoryPressureLevel;

  // A simple dispatch delegate as a testing seam. Makes unittests much simpler
  // as they don't need to setup a multithreaded environment.
  using DispatchCallback = base::Callback<void(MemoryPressureLevel)>;

#if defined(MEMORY_PRESSURE_IS_POLLING)
  // The minimum time that must pass between successive polls. This enforces an
  // upper bound on the rate of calls to the contained MemoryPressureCalculator.
  // 100ms (10Hz) allows a relatively fast respsonse time for rapidly increasing
  // memory usage, but limits the amount of work done in the calculator and
  // stats collection.
  enum : int { kMinimumTimeBetweenSamplesMs = 100 };
  // On polling platforms this is required to be somewhat short in order to
  // observe memory pressure changes as they occur.
  enum : int { kDefaultPollingIntervalMs = 5000 };
#else
  // On non-polling platforms this is only required for keeping statistics up to
  // date so can be quite a long period.
  enum : int { kDefaultPollingIntervalMs = 60000 };
#endif

  // Renotification intervals, per pressure level. These are the same on all
  // platforms. These act as an upper bound on the polling interval when under
  // the corresponding memory pressure.
  enum : int { kNotificationIntervalPressureModerateMs = 5000 };
  enum : int { kNotificationIntervalPressureCriticalMs = 1000 };

#if defined(MEMORY_PRESSURE_IS_POLLING)
  // Fully configurable constructor for polling platforms.
  MemoryPressureMonitor(const scoped_refptr<base::TaskRunner>& task_runner,
                        base::TickClock* tick_clock,
                        MemoryPressureStatsCollector* stats_collector,
                        MemoryPressureCalculator* calculator,
                        const DispatchCallback& dispatch_callback);
#else
  // Constructor for non-polling platforms.
  MemoryPressureMonitor(const scoped_refptr<base::TaskRunner>& task_runner,
                        base::TickClock* tick_clock,
                        MemoryPressureStatsCollector* stats_collector,
                        const DispatchCallback& dispatch_callback,
                        MemoryPressureLevel initial_pressure_level);
#endif

  ~MemoryPressureMonitor();

  // Returns the current memory pressure level. On polling platforms this may
  // result in a forced calculation of the current pressure level (a cheap
  // operation). Can be called from any thread.
  MemoryPressureLevel GetCurrentPressureLevel();

  // Schedules a memory pressure check to run soon. This can be called from any
  // thread.
  void CheckMemoryPressureSoon();

 private:
  // For unittesting.
  friend class TestMemoryPressureMonitor;

#if !defined(MEMORY_PRESSURE_IS_POLLING)
  // Notifications from the OS will be routed here by the contained
  // MemoryPressureMonitorImpl instance. For statistics and renotification to
  // work properly this must be notified of all pressure level changes, even
  // those indicating a return to a state of no pressure.
  void OnMemoryPressureChanged(MemoryPressureLevel level);
#endif

  // Starts the memory pressure monitor. To be called in the constructor.
  void Start();

  // Checks memory pressure and updates stats. This is the entry point for all
  // scheduled checks. Each scheduled check is assigned a |serial| id
  // (monotonically increasing) which is used to tie the task to the time at
  // which it was scheduled via the |scheduled_checks_| map.
  void CheckPressureAndUpdateStats(int serial);
  void CheckPressureAndUpdateStatsLocked(int serial);

  // Ensures that a task is scheduled for renotification/recalculation/stats
  // updating. Uses the |serial| id of the current task to determine the time at
  // which the next scheduled check should run. Assumes |lock_| is held.
  void ScheduleTaskIfNeededLocked(int serial);

  // Schedules a task.
  void ScheduleTaskLocked(base::TimeTicks when);

  // A lock for synchronization.
  base::Lock lock_;

  // Injected dependencies.
  // The task runner on which periodic pressure checks and statistics uploading
  // are run.
  scoped_refptr<base::TaskRunner> task_runner_;
  // The tick clock in use. Used under |lock_|.
  base::TickClock* tick_clock_;
  // The stats collector in use. Used under |lock_|.
  MemoryPressureStatsCollector* stats_collector_;
  // The memory pressure calculator in use. Used under |lock_|.
  MemoryPressureCalculator* calculator_;
  // The dispatch callback to use.
  DispatchCallback dispatch_callback_;

#if !defined(MEMORY_PRESSURE_IS_POLLING)
  // On non-polling platforms this object is responsible for routing OS
  // notifications to OnMemoryPressureChanged, and setting the initial pressure
  // value. The OS specific implementation is responsible for allocating this
  // object.
  std::unique_ptr<MemoryPressureMonitorImpl> monitor_impl_;
#endif

  // Object state.
  // The pressure level as of the most recent poll or notification. Under
  // |lock_|.
  MemoryPressureLevel current_memory_pressure_level_;
#if defined(MEMORY_PRESSURE_IS_POLLING)
  // Time of the last pressure check. Under |lock_|. Only needed for polling
  // implementations.
  base::TimeTicks last_check_;
#endif
  // Time of the last pressure notification. Under |lock_|.
  base::TimeTicks last_notification_;
  // A map of scheduled pressure checks/statistics updates and their serial
  // numbers. Under |lock_|.
  std::map<int, base::TimeTicks> scheduled_checks_;
  // The most recently assigned serial number for a pressure check. The number
  // 0 will never be assigned but will instead be reserved for unscheduled
  // checks initiated externally. Under |lock_|.
  int serial_number_;

  // Weak pointer factory to ourself used for posting delayed tasks to
  // task_runner_.
  base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
};

}  // namespace memory_pressure

#endif  // COMPONENTS_MEMORY_PRESSURE_MEMORY_PRESSURE_MONITOR_H_