blob: 49522c80b01d6e0f47b82b75a0cd2847fac03439 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_FREEZING_FREEZING_VOTE_AGGREGATOR_H_
#define COMPONENTS_PERFORMANCE_MANAGER_FREEZING_FREEZING_VOTE_AGGREGATOR_H_
#include "base/compiler_specific.h"
#include "base/containers/circular_deque.h"
#include "base/containers/flat_map.h"
#include "base/values.h"
#include "components/performance_manager/public/freezing/freezing.h"
#include "components/performance_manager/public/graph/graph_registered.h"
#include "components/performance_manager/public/graph/node_data_describer.h"
#include "components/performance_manager/public/voting/voting.h"
namespace performance_manager {
class FreezingVoteDecorator;
class PageNode;
namespace freezing {
// An aggregator for freezing votes. It upstreams an aggregated vote to an
// upstream channel every time the freezing decision changes for a PageNode. It
// allows freezing of a given PageNode upon reception of one or several
// kCanFreeze vote for this node. Any kCannotFreeze vote received will have
// priority over the kCanFreeze votes and will prevent the PageNode from being
// frozen.
//
// This is a GraphRegistered object, once created this instance can be
// retrieved via:
// graph()->GetRegisteredObjectAs<freezing::FreezingVoteAggregator>();
class FreezingVoteAggregator final
: public FreezingVoteObserver,
public NodeDataDescriberDefaultImpl,
public GraphRegisteredImpl<FreezingVoteAggregator> {
public:
FreezingVoteAggregator(const FreezingVoteAggregator& rhs) = delete;
FreezingVoteAggregator& operator=(const FreezingVoteAggregator& rhs) = delete;
~FreezingVoteAggregator() override;
// Issues a voting channel (effectively registered a voter).
FreezingVotingChannel GetVotingChannel();
// Sets the upstream voting channel. Should only be called once.
void SetUpstreamVotingChannel(FreezingVotingChannel&& channel);
// FreezingVoteObserver implementation:
void OnVoteSubmitted(FreezingVoterId voter_id,
const PageNode* page_node,
const FreezingVote& vote) override;
void OnVoteChanged(FreezingVoterId voter_id,
const PageNode* page_node,
const FreezingVote& new_vote) override;
void OnVoteInvalidated(FreezingVoterId voter_id,
const PageNode* page_node) override;
void RegisterNodeDataDescriber(Graph* graph);
void UnregisterNodeDataDescriber(Graph* graph);
// NodeDataDescriber implementation:
base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
private:
friend class performance_manager::FreezingVoteDecorator;
friend class FreezingVoteAggregatorTest;
friend class FreezingVoteAggregatorTestAccess;
// Private constructor, in practice the FreezingVoteDecorator is responsible
// for maintaining the lifetime of this object.
FreezingVoteAggregator();
// Contains the freezing votes for a given PageNode.
class FreezingVoteData {
public:
// The consequence that adding, removing or updating a vote has on the
// upstreamed vote. The caller is responsible for calling UpstreamVote or
// invalidating the vote (by destroying the instance of this class that owns
// it).
enum class UpstreamVoteImpact {
// The upstream vote has changed. UpstreamVote should be called.
kUpstreamVoteChanged,
// The upstream vote has been removed and should be invalidated.
kUpstreamVoteRemoved,
// The operation had no impact on the upstreamed vote.
kUpstreamVoteUnchanged,
};
FreezingVoteData();
FreezingVoteData(FreezingVoteData&&);
FreezingVoteData& operator=(FreezingVoteData&&);
FreezingVoteData(const FreezingVoteData& rhs) = delete;
FreezingVoteData& operator=(const FreezingVoteData& rhs) = delete;
~FreezingVoteData();
// Adds a new vote.
void AddVote(FreezingVoterId voter_id, const FreezingVote& vote);
// Updates an existing vote.
void UpdateVote(FreezingVoterId voter_id, const FreezingVote& new_vote);
// Removes an existing vote
void RemoveVote(FreezingVoterId voter_id);
// Upstreams the vote for this vote data, using the given voting |channel|.
void UpstreamVote(const PageNode* page_node,
FreezingVotingChannel* channel);
bool IsEmpty() { return votes_.empty(); }
// Returns the chosen vote. Invalid to call if IsEmpty() is true.
const FreezingVote& GetChosenVote();
// Helper for FreezingVoteAggregator::DescribePageNodeData.
void DescribeVotes(base::Value::Dict& ret) const;
private:
friend class FreezingVoteAggregatorTestAccess;
// The current set of votes.
using VotesDeque =
base::circular_deque<std::pair<FreezingVoterId, FreezingVote>>;
const VotesDeque& GetVotesForTesting() { return votes_; }
// Returns the iterator of |voter_id| in |votes_|. |voter_id| is expected
// to be in the deque, this is enforced by a DCHECK.
VotesDeque::iterator FindVote(FreezingVoterId voter_id);
void AddVoteToDeque(FreezingVoterId voter_id, const FreezingVote& vote);
// kCannotFreeze votes are always at the beginning of the deque.
VotesDeque votes_;
};
using VoteDataMap = base::flat_map<const PageNode*, FreezingVoteData>;
// Looks up the VoteData associated with the provided |page_node|. The data is
// expected to already exist (enforced by a DCHECK).
VoteDataMap::iterator GetVoteData(const PageNode* page_node);
// A map that associates a PageNode with a FreezingVoteData structure.
VoteDataMap vote_data_map_;
// The channel for upstreaming our votes.
FreezingVotingChannel channel_;
// Provides FreezingVotingChannels to our input voters.
FreezingVotingChannelFactory freezing_voting_channel_factory_{this};
};
} // namespace freezing
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_FREEZING_FREEZING_VOTE_AGGREGATOR_H_