| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/performance_manager/graph/graph_impl.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/macros.h" |
| #include "chrome/browser/performance_manager/graph/frame_node_impl.h" |
| #include "chrome/browser/performance_manager/graph/node_base.h" |
| #include "chrome/browser/performance_manager/graph/page_node_impl.h" |
| #include "chrome/browser/performance_manager/graph/process_node_impl.h" |
| #include "chrome/browser/performance_manager/graph/system_node_impl.h" |
| #include "chrome/browser/performance_manager/observers/graph_observer.h" |
| |
| namespace ukm { |
| class UkmEntryBuilder; |
| } // namespace ukm |
| |
| namespace performance_manager { |
| |
| GraphImpl::GraphImpl() { |
| DETACH_FROM_SEQUENCE(sequence_checker_); |
| } |
| |
| GraphImpl::~GraphImpl() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| // All observers should have been removed before the graph is deleted. |
| DCHECK(observers_.empty()); |
| // All process nodes should have been removed already. |
| DCHECK(processes_by_pid_.empty()); |
| |
| // Remove the system node from the graph, this should be the only node left. |
| if (system_node_.get()) { |
| RemoveNode(system_node_.get()); |
| system_node_.reset(); |
| } |
| |
| DCHECK(nodes_.empty()); |
| } |
| |
| void GraphImpl::RegisterObserver(GraphObserver* observer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| observer->set_node_graph(this); |
| observers_.push_back(observer); |
| observer->OnRegistered(); |
| } |
| |
| void GraphImpl::UnregisterObserver(GraphObserver* observer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| bool removed = false; |
| for (auto it = observers_.begin(); it != observers_.end(); ++it) { |
| if (*it == observer) { |
| observers_.erase(it); |
| removed = true; |
| observer->OnUnregistered(); |
| break; |
| } |
| } |
| DCHECK(removed); |
| } |
| |
| void GraphImpl::OnNodeAdded(NodeBase* node) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| for (auto* observer : observers_) { |
| if (observer->ShouldObserve(node)) { |
| node->AddObserver(observer); |
| observer->OnNodeAdded(node); |
| } |
| } |
| } |
| |
| void GraphImpl::OnBeforeNodeRemoved(NodeBase* node) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| node->LeaveGraph(); |
| } |
| |
| int64_t GraphImpl::GetNextNodeSerializationId() { |
| return ++current_node_serialization_id_; |
| } |
| |
| SystemNodeImpl* GraphImpl::FindOrCreateSystemNode() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (!system_node_) { |
| // Create the singleton system node instance. Ownership is taken by the |
| // graph. |
| system_node_ = std::make_unique<SystemNodeImpl>(this); |
| AddNewNode(system_node_.get()); |
| } |
| |
| return system_node_.get(); |
| } |
| |
| bool GraphImpl::NodeInGraph(const NodeBase* node) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| const auto& it = nodes_.find(const_cast<NodeBase*>(node)); |
| return it != nodes_.end(); |
| } |
| |
| ProcessNodeImpl* GraphImpl::GetProcessNodeByPid(base::ProcessId pid) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| auto it = processes_by_pid_.find(pid); |
| if (it == processes_by_pid_.end()) |
| return nullptr; |
| |
| return ProcessNodeImpl::FromNodeBase(it->second); |
| } |
| |
| std::vector<ProcessNodeImpl*> GraphImpl::GetAllProcessNodes() { |
| return GetAllNodesOfType<ProcessNodeImpl>(); |
| } |
| |
| std::vector<FrameNodeImpl*> GraphImpl::GetAllFrameNodes() { |
| return GetAllNodesOfType<FrameNodeImpl>(); |
| } |
| |
| std::vector<PageNodeImpl*> GraphImpl::GetAllPageNodes() { |
| return GetAllNodesOfType<PageNodeImpl>(); |
| } |
| |
| size_t GraphImpl::GetNodeAttachedDataCountForTesting(NodeBase* node, |
| const void* key) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (!node && !key) |
| return node_attached_data_map_.size(); |
| |
| size_t count = 0; |
| for (auto& node_data : node_attached_data_map_) { |
| if (node && node_data.first.first != node) |
| continue; |
| if (key && node_data.first.second != key) |
| continue; |
| ++count; |
| } |
| |
| return count; |
| } |
| |
| void GraphImpl::AddNewNode(NodeBase* new_node) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| auto it = nodes_.insert(new_node); |
| DCHECK(it.second); // Inserted successfully |
| |
| // Allow the node to initialize itself now that it's been added. |
| new_node->JoinGraph(); |
| OnNodeAdded(new_node); |
| } |
| |
| void GraphImpl::RemoveNode(NodeBase* node) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| OnBeforeNodeRemoved(node); |
| |
| // Remove any node attached data affiliated with this node. |
| auto lower = |
| node_attached_data_map_.lower_bound(std::make_pair(node, nullptr)); |
| auto upper = |
| node_attached_data_map_.lower_bound(std::make_pair(node + 1, nullptr)); |
| node_attached_data_map_.erase(lower, upper); |
| |
| // Before removing the node itself. |
| size_t erased = nodes_.erase(node); |
| DCHECK_EQ(1u, erased); |
| } |
| |
| void GraphImpl::BeforeProcessPidChange(ProcessNodeImpl* process, |
| base::ProcessId new_pid) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| // On Windows, PIDs are aggressively reused, and because not all process |
| // creation/death notifications are synchronized, it's possible for more than |
| // one process node to have the same PID. To handle this, the second and |
| // subsequent registration override earlier registrations, while |
| // unregistration will only unregister the current holder of the PID. |
| if (process->process_id() != base::kNullProcessId) { |
| auto it = processes_by_pid_.find(process->process_id()); |
| if (it != processes_by_pid_.end() && it->second == process) |
| processes_by_pid_.erase(it); |
| } |
| if (new_pid != base::kNullProcessId) |
| processes_by_pid_[new_pid] = process; |
| } |
| |
| template <typename NodeType> |
| std::vector<NodeType*> GraphImpl::GetAllNodesOfType() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| const auto type = NodeType::Type(); |
| std::vector<NodeType*> ret; |
| for (auto* node : nodes_) { |
| if (node->type() == type) |
| ret.push_back(NodeType::FromNodeBase(node)); |
| } |
| return ret; |
| } |
| |
| } // namespace performance_manager |