1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #ifndef BASE_UTIL_MEMORY_PRESSURE_SYSTEM_MEMORY_PRESSURE_EVALUATOR_CHROMEOS_H_
5 #define BASE_UTIL_MEMORY_PRESSURE_SYSTEM_MEMORY_PRESSURE_EVALUATOR_CHROMEOS_H_
6 
7 #include <vector>
8 
9 #include "base/base_export.h"
10 #include "base/feature_list.h"
11 #include "base/files/scoped_file.h"
12 #include "base/macros.h"
13 #include "base/memory/memory_pressure_listener.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/process/process_metrics.h"
16 #include "base/time/time.h"
17 #include "base/timer/timer.h"
18 #include "base/util/memory_pressure/memory_pressure_voter.h"
19 #include "base/util/memory_pressure/system_memory_pressure_evaluator.h"
20 
21 namespace util {
22 namespace chromeos {
23 
24 // A feature which controls user space low memory notification.
25 extern const base::Feature kCrOSUserSpaceLowMemoryNotification;
26 
27 ////////////////////////////////////////////////////////////////////////////////
28 // SystemMemoryPressureEvaluator
29 //
30 // A class to handle the observation of our free memory. It notifies the
31 // MemoryPressureListener of memory fill level changes, so that it can take
32 // action to reduce memory resources accordingly.
33 class SystemMemoryPressureEvaluator
34     : public util::SystemMemoryPressureEvaluator {
35  public:
36   // The SystemMemoryPressureEvaluator reads the pressure levels from the
37   // /sys/kernel/mm/chromeos-low_mem/margin and does not need to be configured.
38   //
39   // NOTE: You should check that the kernel supports notifications by calling
40   // SupportsKernelNotifications() before constructing a new instance of this
41   // class.
42   explicit SystemMemoryPressureEvaluator(
43       std::unique_ptr<MemoryPressureVoter> voter);
44   ~SystemMemoryPressureEvaluator() override;
45 
46   // GetMarginFileParts returns a vector of the configured margin file values.
47   // The margin file contains two or more values, but we're only concerned with
48   // the first two. The first represents critical memory pressure, the second
49   // is moderate memory pressure level.
50   static std::vector<int> GetMarginFileParts();
51 
52   // GetAvailableMemoryKB returns the available memory in KiB.
53   uint64_t GetAvailableMemoryKB();
54 
55   // SupportsKernelNotifications will return true if the kernel supports and is
56   // configured for notifications on memory availability changes.
57   static bool SupportsKernelNotifications();
58 
59   // ScheduleEarlyCheck is used by the ChromeOS tab manager delegate to force it
60   // to quickly recheck pressure levels after a tab discard or some other
61   // action.
62   void ScheduleEarlyCheck();
63 
64   // Returns the moderate pressure threshold as read from the margin file.
ModeratePressureThresholdMBForTesting()65   int ModeratePressureThresholdMBForTesting() const {
66     return moderate_pressure_threshold_mb_;
67   }
68 
69   // Returns the critical pressure threshold as read from the margin file.
CriticalPressureThresholdMBForTesting()70   int CriticalPressureThresholdMBForTesting() const {
71     return critical_pressure_threshold_mb_;
72   }
73 
74   // The memory parameters are saved for optimization.  If these memory
75   // parameters are changed, call this function to update the saved values.
76   void UpdateMemoryParameters();
77 
78   // Returns the current system memory pressure evaluator.
79   static SystemMemoryPressureEvaluator* Get();
80 
81  protected:
82   // This constructor is only used for testing.
83   SystemMemoryPressureEvaluator(
84       const std::string& margin_file,
85       const std::string& available_file,
86       base::RepeatingCallback<bool(int)> kernel_waiting_callback,
87       bool disable_timer_for_testing,
88       bool is_user_space_notify,
89       std::unique_ptr<MemoryPressureVoter> voter);
90 
91   static std::vector<int> GetMarginFileParts(const std::string& margin_file);
92 
93   static uint64_t CalculateReservedFreeKB(const std::string& zoneinfo);
94 
95   static uint64_t GetReservedMemoryKB();
96 
97   static uint64_t CalculateAvailableMemoryUserSpaceKB(
98       const base::SystemMemoryInfoKB& info,
99       uint64_t reserved_free,
100       uint64_t min_filelist,
101       uint64_t ram_swap_weight);
102 
103   void CheckMemoryPressure();
104 
105  private:
106   void HandleKernelNotification(bool result);
107   void ScheduleWaitForKernelNotification();
108   void CheckMemoryPressureAndRecordStatistics();
109   int moderate_pressure_threshold_mb_ = 0;
110   int critical_pressure_threshold_mb_ = 0;
111 
112   // We keep track of how long it has been since we last notified at the
113   // moderate level.
114   base::TimeTicks last_moderate_notification_;
115 
116   // We keep track of how long it's been since we notified on the
117   // Memory.PressureLevel metric.
118   base::TimeTicks last_pressure_level_report_;
119 
120   // File descriptor used to read and poll(2) available memory from sysfs,
121   // In /sys/kernel/mm/chromeos-low_mem/available.
122   base::ScopedFD available_mem_file_;
123 
124   // A timer to check the memory pressure and to report an UMA metric
125   // periodically.
126   base::RepeatingTimer checking_timer_;
127 
128   // Kernel waiting callback which is responsible for blocking on the
129   // available file until it receives a kernel notification, this is
130   // configurable to make testing easier.
131   base::RepeatingCallback<bool()> kernel_waiting_callback_;
132 
133   // User space low memory notification mode.
134   const bool is_user_space_notify_;
135 
136   // Values saved for user space available memory calculation.  The value of
137   // |reserved_free_| should not change unless min_free_kbytes or
138   // lowmem_reserve_ratio change.  The value of |min_filelist_| and
139   // |ram_swap_weight_| should not change unless the user sets them manually.
140   uint64_t reserved_free_;
141   uint64_t min_filelist_;
142   uint64_t ram_swap_weight_;
143 
144   SEQUENCE_CHECKER(sequence_checker_);
145 
146   base::WeakPtrFactory<SystemMemoryPressureEvaluator> weak_ptr_factory_;
147 
148   DISALLOW_COPY_AND_ASSIGN(SystemMemoryPressureEvaluator);
149 };
150 
151 }  // namespace chromeos
152 }  // namespace util
153 #endif  // BASE_UTIL_MEMORY_PRESSURE_SYSTEM_MEMORY_PRESSURE_EVALUATOR_CHROMEOS_H_
154