system_memory_pressure_evaluator_linux.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright 2020 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. #include "components/memory_pressure/system_memory_pressure_evaluator_linux.h"
  5. #include "base/bind.h"
  6. #include "base/numerics/safe_conversions.h"
  7. #include "base/process/process_metrics.h"
  8. #include "base/task/single_thread_task_runner.h"
  9. #include "base/task/task_traits.h"
  10. #include "base/threading/sequenced_task_runner_handle.h"
  11. #include "base/time/time.h"
  12. #include "components/memory_pressure/multi_source_memory_pressure_monitor.h"
  13. namespace {
  14. constexpr int kKiBperMiB = 1024;
  15. int GetAvailableSystemMemoryMiB(const base::SystemMemoryInfoKB& mem_info) {
  16. // Use 'available' metric if is is present,
  17. // if no (kernels < 3.14), let's make a rough evaluation using free physical
  18. // memory plus buffers and caches (that OS can free in case of low memory
  19. // state)
  20. int mem_available =
  21. mem_info.available ? mem_info.available
  22. : (mem_info.free + mem_info.buffers + mem_info.cached);
  23. // How much physical memory is actively available for use right now, in MBs.
  24. return mem_available / kKiBperMiB;
  25. }
  26. } // namespace
  27. namespace memory_pressure {
  28. namespace os_linux {
  29. const base::TimeDelta SystemMemoryPressureEvaluator::kMemorySamplingPeriod =
  30. base::Seconds(5);
  31. const base::TimeDelta SystemMemoryPressureEvaluator::kModeratePressureCooldown =
  32. base::Seconds(10);
  33. const int SystemMemoryPressureEvaluator::kDefaultModerateThresholdPc = 75;
  34. const int SystemMemoryPressureEvaluator::kDefaultCriticalThresholdPc = 85;
  35. SystemMemoryPressureEvaluator::SystemMemoryPressureEvaluator(
  36. std::unique_ptr<MemoryPressureVoter> voter)
  37. : memory_pressure::SystemMemoryPressureEvaluator(std::move(voter)),
  38. moderate_pressure_repeat_count_(0) {
  39. if (InferThresholds())
  40. StartObserving();
  41. }
  42. SystemMemoryPressureEvaluator::SystemMemoryPressureEvaluator(
  43. int moderate_threshold_mb,
  44. int critical_threshold_mb,
  45. std::unique_ptr<MemoryPressureVoter> voter)
  46. : memory_pressure::SystemMemoryPressureEvaluator(std::move(voter)),
  47. moderate_threshold_mb_(moderate_threshold_mb),
  48. critical_threshold_mb_(critical_threshold_mb),
  49. moderate_pressure_repeat_count_(0) {
  50. DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
  51. DCHECK_GT(critical_threshold_mb_, 0);
  52. StartObserving();
  53. }
  54. void SystemMemoryPressureEvaluator::StartObserving() {
  55. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  56. timer_.Start(
  57. FROM_HERE, kMemorySamplingPeriod,
  58. base::BindRepeating(&SystemMemoryPressureEvaluator::CheckMemoryPressure,
  59. base::Unretained(this)));
  60. }
  61. void SystemMemoryPressureEvaluator::StopObserving() {
  62. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  63. // If StartObserving failed, StopObserving will still get called.
  64. timer_.Stop();
  65. }
  66. bool SystemMemoryPressureEvaluator::GetSystemMemoryInfo(
  67. base::SystemMemoryInfoKB* mem_info) {
  68. return base::GetSystemMemoryInfo(mem_info);
  69. }
  70. void SystemMemoryPressureEvaluator::CheckMemoryPressure() {
  71. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  72. // Get the previous pressure level and update the current one.
  73. MemoryPressureLevel old_vote = current_vote();
  74. SetCurrentVote(CalculateCurrentPressureLevel());
  75. // |notify| will be set to true if MemoryPressureListeners need to be
  76. // notified of a memory pressure level state change.
  77. bool notify = false;
  78. switch (current_vote()) {
  79. case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
  80. break;
  81. case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
  82. if (old_vote != current_vote()) {
  83. // This is a new transition to moderate pressure so notify.
  84. moderate_pressure_repeat_count_ = 0;
  85. notify = true;
  86. } else {
  87. // Already in moderate pressure, only notify if sustained over the
  88. // cooldown period.
  89. const int kModeratePressureCooldownCycles =
  90. kModeratePressureCooldown / kMemorySamplingPeriod;
  91. if (++moderate_pressure_repeat_count_ ==
  92. kModeratePressureCooldownCycles) {
  93. moderate_pressure_repeat_count_ = 0;
  94. notify = true;
  95. }
  96. }
  97. break;
  98. case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
  99. // Always notify of critical pressure levels.
  100. notify = true;
  101. break;
  102. }
  103. SendCurrentVote(notify);
  104. }
  105. bool SystemMemoryPressureEvaluator::InferThresholds() {
  106. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  107. base::SystemMemoryInfoKB mem_info;
  108. if (!GetSystemMemoryInfo(&mem_info))
  109. return false;
  110. // The computation of the different thresholds assumes that
  111. // SystemMemoryInfoKB::total is stored as an integer and so the result of
  112. // |static_cast<uint64_t>(mem_info.total) * (100 - kThresholdPc)| won't
  113. // overflow.
  114. static_assert(
  115. std::is_same<decltype(mem_info.total), int>::value,
  116. "SystemMemoryInfoKB::total is expected to be stored as an integer.");
  117. critical_threshold_mb_ = base::checked_cast<int>(
  118. static_cast<uint64_t>(mem_info.total) *
  119. (100 - kDefaultCriticalThresholdPc) / 100 / kKiBperMiB);
  120. moderate_threshold_mb_ = base::checked_cast<int>(
  121. static_cast<uint64_t>(mem_info.total) *
  122. (100 - kDefaultModerateThresholdPc) / 100 / kKiBperMiB);
  123. return true;
  124. }
  125. base::MemoryPressureListener::MemoryPressureLevel
  126. SystemMemoryPressureEvaluator::CalculateCurrentPressureLevel() {
  127. base::SystemMemoryInfoKB mem_info;
  128. if (GetSystemMemoryInfo(&mem_info)) {
  129. // How much system memory is actively available for use right now, in MBs.
  130. int available = GetAvailableSystemMemoryMiB(mem_info);
  131. // Determine if the available memory is under critical memory pressure.
  132. if (available <= critical_threshold_mb_)
  133. return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
  134. // Determine if the available memory is under moderate memory pressure.
  135. if (available <= moderate_threshold_mb_)
  136. return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
  137. }
  138. // No memory pressure was detected.
  139. return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
  140. }
  141. } // namespace os_linux
  142. } // namespace memory_pressure