freezing_vote_aggregator.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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/performance_manager/freezing/freezing_vote_aggregator.h"
  5. #include <algorithm>
  6. #include "base/strings/stringprintf.h"
  7. #include "components/performance_manager/public/freezing/freezing.h"
  8. #include "components/performance_manager/public/graph/node_data_describer_registry.h"
  9. namespace performance_manager {
  10. namespace freezing {
  11. namespace {
  12. const char kDescriberName[] = "FreezingVoteAggregator";
  13. }
  14. FreezingVoteAggregator::FreezingVoteAggregator() = default;
  15. FreezingVoteAggregator::~FreezingVoteAggregator() = default;
  16. FreezingVotingChannel FreezingVoteAggregator::GetVotingChannel() {
  17. return freezing_voting_channel_factory_.BuildVotingChannel();
  18. }
  19. void FreezingVoteAggregator::SetUpstreamVotingChannel(
  20. FreezingVotingChannel&& channel) {
  21. channel_ = std::move(channel);
  22. }
  23. void FreezingVoteAggregator::OnVoteSubmitted(FreezingVoterId voter_id,
  24. const PageNode* page_node,
  25. const FreezingVote& vote) {
  26. DCHECK(channel_.IsValid());
  27. // Create the VoteData for this page node, if necessary.
  28. auto& vote_data = vote_data_map_[page_node];
  29. // Remember the previous chosen vote before adding the new vote. There
  30. // could be none if this is the first vote submitted for |page_node|.
  31. absl::optional<FreezingVoteValue> old_chosen_vote_value;
  32. if (!vote_data.IsEmpty())
  33. old_chosen_vote_value = vote_data.GetChosenVote().value();
  34. vote_data.AddVote(voter_id, vote);
  35. // If there was no previous chosen vote, the vote must be submitted.
  36. if (!old_chosen_vote_value) {
  37. channel_.SubmitVote(page_node, vote);
  38. return;
  39. }
  40. // Since there is a previous chosen vote, it must be modified if the chosen
  41. // vote changed.
  42. const FreezingVote new_chosen_vote = vote_data.GetChosenVote();
  43. if (*old_chosen_vote_value != new_chosen_vote.value())
  44. channel_.ChangeVote(page_node, new_chosen_vote);
  45. }
  46. void FreezingVoteAggregator::OnVoteChanged(FreezingVoterId voter_id,
  47. const PageNode* page_node,
  48. const FreezingVote& new_vote) {
  49. // The vote data for this page node is guaranteed to exist.
  50. auto& vote_data = GetVoteData(page_node)->second;
  51. // Remember the previous chosen vote before updating the vote for this
  52. // |voter_id|.
  53. const FreezingVoteValue old_chosen_vote_value =
  54. vote_data.GetChosenVote().value();
  55. vote_data.UpdateVote(voter_id, new_vote);
  56. // If the chosen vote changed, the upstream vote must also be changed.
  57. const FreezingVote new_chosen_vote = vote_data.GetChosenVote();
  58. if (old_chosen_vote_value != new_chosen_vote.value())
  59. channel_.ChangeVote(page_node, new_chosen_vote);
  60. }
  61. void FreezingVoteAggregator::OnVoteInvalidated(FreezingVoterId voter_id,
  62. const PageNode* page_node) {
  63. // The VoteData for this page node is guaranteed to exist.
  64. auto it = GetVoteData(page_node);
  65. auto& vote_data = it->second;
  66. // Remember the previous chosen vote before removing the vote for this
  67. // |voter_id|.
  68. const FreezingVoteValue old_chosen_vote_value =
  69. vote_data.GetChosenVote().value();
  70. vote_data.RemoveVote(voter_id);
  71. // In case the last vote for |page_node| was invalidated, the upstream vote
  72. // must also be invalidated.
  73. if (vote_data.IsEmpty()) {
  74. channel_.InvalidateVote(page_node);
  75. // Clean up the VoteData for |page_node| since it is empty.
  76. vote_data_map_.erase(it);
  77. return;
  78. }
  79. // If the chosen vote changed, the upstream vote must also be changed.
  80. const FreezingVote new_chosen_vote = vote_data.GetChosenVote();
  81. if (old_chosen_vote_value != new_chosen_vote.value())
  82. channel_.ChangeVote(page_node, new_chosen_vote);
  83. }
  84. void FreezingVoteAggregator::RegisterNodeDataDescriber(Graph* graph) {
  85. graph->GetNodeDataDescriberRegistry()->RegisterDescriber(this,
  86. kDescriberName);
  87. }
  88. void FreezingVoteAggregator::UnregisterNodeDataDescriber(Graph* graph) {
  89. graph->GetNodeDataDescriberRegistry()->UnregisterDescriber(this);
  90. }
  91. base::Value FreezingVoteAggregator::DescribePageNodeData(
  92. const PageNode* node) const {
  93. auto votes_for_page = vote_data_map_.find(node);
  94. if (votes_for_page == vote_data_map_.end())
  95. return base::Value();
  96. base::Value ret(base::Value::Type::DICTIONARY);
  97. votes_for_page->second.DescribeVotes(&ret);
  98. return ret;
  99. }
  100. FreezingVoteAggregator::FreezingVoteData::FreezingVoteData() = default;
  101. FreezingVoteAggregator::FreezingVoteData::FreezingVoteData(FreezingVoteData&&) =
  102. default;
  103. FreezingVoteAggregator::FreezingVoteData&
  104. FreezingVoteAggregator::FreezingVoteData::operator=(
  105. FreezingVoteAggregator::FreezingVoteData&& rhs) = default;
  106. FreezingVoteAggregator::FreezingVoteData::~FreezingVoteData() = default;
  107. void FreezingVoteAggregator::FreezingVoteData::AddVote(
  108. FreezingVoterId voter_id,
  109. const FreezingVote& vote) {
  110. AddVoteToDeque(voter_id, vote);
  111. }
  112. void FreezingVoteAggregator::FreezingVoteData::UpdateVote(
  113. FreezingVoterId voter_id,
  114. const FreezingVote& new_vote) {
  115. // The vote is removed from the deque and then re-inserted.
  116. auto it = FindVote(voter_id);
  117. DCHECK(it != votes_.end());
  118. votes_.erase(it);
  119. AddVoteToDeque(voter_id, new_vote);
  120. }
  121. void FreezingVoteAggregator::FreezingVoteData::RemoveVote(
  122. FreezingVoterId voter_id) {
  123. votes_.erase(FindVote(voter_id));
  124. }
  125. const FreezingVote& FreezingVoteAggregator::FreezingVoteData::GetChosenVote() {
  126. DCHECK(!IsEmpty());
  127. // The set of votes is ordered and the first one in the set is the one that
  128. // should be sent to the consumer.
  129. return votes_.begin()->second;
  130. }
  131. void FreezingVoteAggregator::FreezingVoteData::DescribeVotes(
  132. base::Value* ret) const {
  133. size_t i = 0;
  134. for (const auto& it : votes_) {
  135. ret->SetStringKey(
  136. base::StringPrintf("Vote %zu (%s)", i++,
  137. FreezingVoteValueToString(it.second.value())),
  138. it.second.reason());
  139. }
  140. }
  141. FreezingVoteAggregator::FreezingVoteData::VotesDeque::iterator
  142. FreezingVoteAggregator::FreezingVoteData::FindVote(FreezingVoterId voter_id) {
  143. // TODO(sebmarchand): Consider doing a reverse search for kCanFreeze votes and
  144. // a normal one for kCannotFreeze votes.
  145. auto it =
  146. std::find_if(votes_.begin(), votes_.end(),
  147. [voter_id](const auto& e) { return e.first == voter_id; });
  148. DCHECK(it != votes_.end());
  149. return it;
  150. }
  151. void FreezingVoteAggregator::FreezingVoteData::AddVoteToDeque(
  152. FreezingVoterId voter_id,
  153. const FreezingVote& vote) {
  154. DCHECK(std::find_if(votes_.begin(), votes_.end(), [voter_id](const auto& e) {
  155. return e.first == voter_id;
  156. }) == votes_.end());
  157. if (vote.value() == FreezingVoteValue::kCannotFreeze) {
  158. votes_.emplace_front(voter_id, vote);
  159. } else {
  160. votes_.emplace_back(voter_id, vote);
  161. }
  162. }
  163. FreezingVoteAggregator::VoteDataMap::iterator
  164. FreezingVoteAggregator::GetVoteData(const PageNode* page_node) {
  165. auto it = vote_data_map_.find(page_node);
  166. DCHECK(it != vote_data_map_.end());
  167. return it;
  168. }
  169. } // namespace freezing
  170. } // namespace performance_manager