memory_pressure_voter.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. #include "components/memory_pressure/memory_pressure_voter.h"
  5. #include <numeric>
  6. #include "base/memory/raw_ptr.h"
  7. #include "base/trace_event/base_tracing.h"
  8. #include "third_party/abseil-cpp/absl/types/optional.h"
  9. namespace memory_pressure {
  10. class MemoryPressureVoterImpl : public MemoryPressureVoter {
  11. public:
  12. explicit MemoryPressureVoterImpl(MemoryPressureVoteAggregator* aggregator)
  13. : aggregator_(aggregator) {}
  14. ~MemoryPressureVoterImpl() override {
  15. // Remove this voter's vote.
  16. if (vote_)
  17. aggregator_->OnVote(vote_, absl::nullopt);
  18. }
  19. MemoryPressureVoterImpl(MemoryPressureVoterImpl&&) = delete;
  20. MemoryPressureVoterImpl& operator=(MemoryPressureVoterImpl&&) = delete;
  21. void SetVote(base::MemoryPressureListener::MemoryPressureLevel level,
  22. bool notify_listeners) override {
  23. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  24. auto old_vote = vote_;
  25. vote_ = level;
  26. aggregator_->OnVote(old_vote, vote_);
  27. if (notify_listeners)
  28. aggregator_->NotifyListeners();
  29. }
  30. private:
  31. // This is the aggregator to which this voter's votes will be cast.
  32. const raw_ptr<MemoryPressureVoteAggregator> aggregator_;
  33. // optional<> is used here as the vote will be null until the voter's
  34. // first vote calculation.
  35. absl::optional<base::MemoryPressureListener::MemoryPressureLevel> vote_;
  36. SEQUENCE_CHECKER(sequence_checker_);
  37. };
  38. MemoryPressureVoteAggregator::MemoryPressureVoteAggregator(Delegate* delegate)
  39. : delegate_(delegate) {}
  40. MemoryPressureVoteAggregator::~MemoryPressureVoteAggregator() {
  41. DCHECK_EQ(std::accumulate(votes_.begin(), votes_.end(), 0), 0);
  42. }
  43. std::unique_ptr<MemoryPressureVoter>
  44. MemoryPressureVoteAggregator::CreateVoter() {
  45. return std::make_unique<MemoryPressureVoterImpl>(this);
  46. }
  47. void MemoryPressureVoteAggregator::OnVoteForTesting(
  48. absl::optional<MemoryPressureLevel> old_vote,
  49. absl::optional<MemoryPressureLevel> new_vote) {
  50. OnVote(old_vote, new_vote);
  51. }
  52. void MemoryPressureVoteAggregator::NotifyListenersForTesting() {
  53. NotifyListeners();
  54. }
  55. base::MemoryPressureListener::MemoryPressureLevel
  56. MemoryPressureVoteAggregator::EvaluateVotesForTesting() {
  57. return EvaluateVotes();
  58. }
  59. void MemoryPressureVoteAggregator::OnVote(
  60. absl::optional<MemoryPressureLevel> old_vote,
  61. absl::optional<MemoryPressureLevel> new_vote) {
  62. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  63. DCHECK(old_vote || new_vote);
  64. if (old_vote) {
  65. DCHECK_LT(0u, votes_[old_vote.value()]);
  66. votes_[old_vote.value()]--;
  67. }
  68. if (new_vote)
  69. votes_[new_vote.value()]++;
  70. auto old_pressure_level = current_pressure_level_;
  71. // If the pressure level is not None then an asynchronous event will have been
  72. // started below, it needs to be ended.
  73. // Note that we record this event every time we receive a new vote to ensure
  74. // that the begin event doesn't get dropped during long pressure sessions.
  75. if (old_pressure_level ==
  76. MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL) {
  77. TRACE_EVENT_NESTABLE_ASYNC_END0("base", "MemoryPressure::CriticalPressure",
  78. this);
  79. } else if (old_pressure_level ==
  80. MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE) {
  81. TRACE_EVENT_NESTABLE_ASYNC_END0("base", "MemoryPressure::ModeratePressure",
  82. this);
  83. }
  84. current_pressure_level_ = EvaluateVotes();
  85. // Start an asynchronous tracing event to record this pressure session.
  86. if (current_pressure_level_ ==
  87. MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL) {
  88. TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("base",
  89. "MemoryPressure::CriticalPressure", this);
  90. } else if (current_pressure_level_ ==
  91. MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE) {
  92. TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("base",
  93. "MemoryPressure::ModeratePressure", this);
  94. }
  95. if (old_pressure_level != current_pressure_level_)
  96. delegate_->OnMemoryPressureLevelChanged(current_pressure_level_);
  97. }
  98. void MemoryPressureVoteAggregator::NotifyListeners() {
  99. delegate_->OnNotifyListenersRequested();
  100. }
  101. base::MemoryPressureListener::MemoryPressureLevel
  102. MemoryPressureVoteAggregator::EvaluateVotes() const {
  103. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  104. static_assert(
  105. base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL == 2,
  106. "Ensure that each memory pressure level is handled by this method.");
  107. if (votes_[2])
  108. return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
  109. if (votes_[1])
  110. return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
  111. return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
  112. }
  113. void MemoryPressureVoteAggregator::SetVotesForTesting(size_t none_votes,
  114. size_t moderate_votes,
  115. size_t critical_votes) {
  116. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  117. votes_[0] = none_votes;
  118. votes_[1] = moderate_votes;
  119. votes_[2] = critical_votes;
  120. }
  121. } // namespace memory_pressure