blob: 7f8b729d18045f69c82505ad9f6a64eb19878a14 [file] [log] [blame]
// 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 "components/performance_manager/graph/graph_impl.h"
#include <algorithm>
#include <utility>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/notreached.h"
#include "base/strings/string_piece.h"
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/node_base.h"
#include "components/performance_manager/graph/page_node_impl.h"
#include "components/performance_manager/graph/process_node_impl.h"
#include "components/performance_manager/graph/system_node_impl.h"
#include "components/performance_manager/graph/worker_node_impl.h"
#include "components/performance_manager/public/graph/node_data_describer.h"
#include "components/performance_manager/public/graph/node_data_describer_registry.h"
namespace ukm {
class UkmEntryBuilder;
} // namespace ukm
namespace performance_manager {
namespace {
// A unique type ID for this implementation.
const uintptr_t kGraphImplType = reinterpret_cast<uintptr_t>(&kGraphImplType);
template <typename NodeObserverType>
void AddObserverImpl(std::vector<NodeObserverType*>* observers,
NodeObserverType* observer) {
DCHECK(observers);
DCHECK(observer);
auto it = std::find(observers->begin(), observers->end(), observer);
DCHECK(it == observers->end());
observers->push_back(observer);
}
template <typename NodeObserverType>
void RemoveObserverImpl(std::vector<NodeObserverType*>* observers,
NodeObserverType* observer) {
DCHECK(observers);
DCHECK(observer);
// We expect to find the observer in the array.
auto it = std::find(observers->begin(), observers->end(), observer);
DCHECK(it != observers->end());
observers->erase(it);
// There should only have been one copy of the observer.
it = std::find(observers->begin(), observers->end(), observer);
DCHECK(it == observers->end());
}
class NodeDataDescriberRegistryImpl : public NodeDataDescriberRegistry {
public:
~NodeDataDescriberRegistryImpl() override;
// NodeDataDescriberRegistry impl:
void RegisterDescriber(const NodeDataDescriber* describer,
base::StringPiece name) override;
void UnregisterDescriber(const NodeDataDescriber* describer) override;
base::Value DescribeNodeData(const Node* node) const override;
size_t size() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return describers_.size();
}
private:
template <typename NodeType, typename NodeImplType>
base::Value DescribeNodeImpl(
base::Value (NodeDataDescriber::*DescribeFn)(const NodeType*) const,
const NodeImplType* node) const VALID_CONTEXT_REQUIRED(sequence_checker_);
base::flat_map<const NodeDataDescriber*, std::string> describers_
GUARDED_BY_CONTEXT(sequence_checker_);
SEQUENCE_CHECKER(sequence_checker_);
};
template <typename NodeType, typename NodeImplType>
base::Value NodeDataDescriberRegistryImpl::DescribeNodeImpl(
base::Value (NodeDataDescriber::*Describe)(const NodeType*) const,
const NodeImplType* node) const {
base::Value result(base::Value::Type::DICTIONARY);
for (const auto& name_and_describer : describers_) {
base::Value description = (name_and_describer.first->*Describe)(node);
if (!description.is_none()) {
DCHECK_EQ(nullptr, result.FindDictKey(name_and_describer.second));
result.SetKey(name_and_describer.second, std::move(description));
}
}
return result;
}
NodeDataDescriberRegistryImpl::~NodeDataDescriberRegistryImpl() {
// All describers should have unregistered before the graph is destroyed.
DCHECK(describers_.empty());
}
void NodeDataDescriberRegistryImpl::RegisterDescriber(
const NodeDataDescriber* describer,
base::StringPiece name) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
#if DCHECK_IS_ON()
for (const auto& kv : describers_) {
DCHECK_NE(kv.second, name) << "Name must be unique";
}
#endif
bool inserted =
describers_.insert(std::make_pair(describer, std::string(name))).second;
DCHECK(inserted);
}
void NodeDataDescriberRegistryImpl::UnregisterDescriber(
const NodeDataDescriber* describer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
size_t erased = describers_.erase(describer);
DCHECK_EQ(1u, erased);
}
base::Value NodeDataDescriberRegistryImpl::DescribeNodeData(
const Node* node) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const NodeBase* node_base = NodeBase::FromNode(node);
switch (node_base->type()) {
case NodeTypeEnum::kInvalidType:
NOTREACHED();
return base::Value();
case NodeTypeEnum::kFrame:
return DescribeNodeImpl(&NodeDataDescriber::DescribeFrameNodeData,
FrameNodeImpl::FromNodeBase(node_base));
case NodeTypeEnum::kPage:
return DescribeNodeImpl(&NodeDataDescriber::DescribePageNodeData,
PageNodeImpl::FromNodeBase(node_base));
case NodeTypeEnum::kProcess:
return DescribeNodeImpl(&NodeDataDescriber::DescribeProcessNodeData,
ProcessNodeImpl::FromNodeBase(node_base));
case NodeTypeEnum::kSystem:
return DescribeNodeImpl(&NodeDataDescriber::DescribeSystemNodeData,
SystemNodeImpl::FromNodeBase(node_base));
case NodeTypeEnum::kWorker:
return DescribeNodeImpl(&NodeDataDescriber::DescribeWorkerNodeData,
WorkerNodeImpl::FromNodeBase(node_base));
}
}
} // namespace
GraphImpl::GraphImpl() {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
GraphImpl::~GraphImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// All graph registered and owned objects should have been cleaned up.
DCHECK(graph_owned_.empty());
DCHECK(registered_objects_.empty());
// At this point, all typed observers should be empty.
DCHECK(graph_observers_.empty());
DCHECK(frame_node_observers_.empty());
DCHECK(page_node_observers_.empty());
DCHECK(process_node_observers_.empty());
DCHECK(system_node_observers_.empty());
// All process and frame nodes should have been removed already.
DCHECK(processes_by_pid_.empty());
DCHECK(frames_by_id_.empty());
// All nodes should have been removed.
DCHECK(nodes_.empty());
}
void GraphImpl::TearDown() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Notify graph observers that the graph is being destroyed.
for (auto* observer : graph_observers_)
observer->OnBeforeGraphDestroyed(this);
// Clean up graph owned objects. This causes their TakeFromGraph callbacks to
// be invoked, and ideally they clean up any observers they may have, etc.
graph_owned_.ReleaseObjects(this);
// At this point, all typed observers should be empty.
DCHECK(graph_observers_.empty());
DCHECK(frame_node_observers_.empty());
DCHECK(page_node_observers_.empty());
DCHECK(process_node_observers_.empty());
DCHECK(system_node_observers_.empty());
// Remove the system node from the graph, this should be the only node left.
ReleaseSystemNode();
DCHECK(nodes_.empty());
}
void GraphImpl::AddGraphObserver(GraphObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
AddObserverImpl(&graph_observers_, observer);
}
void GraphImpl::AddFrameNodeObserver(FrameNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
AddObserverImpl(&frame_node_observers_, observer);
}
void GraphImpl::AddPageNodeObserver(PageNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
AddObserverImpl(&page_node_observers_, observer);
}
void GraphImpl::AddProcessNodeObserver(ProcessNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
AddObserverImpl(&process_node_observers_, observer);
}
void GraphImpl::AddSystemNodeObserver(SystemNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
AddObserverImpl(&system_node_observers_, observer);
}
void GraphImpl::AddWorkerNodeObserver(WorkerNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
AddObserverImpl(&worker_node_observers_, observer);
}
void GraphImpl::RemoveGraphObserver(GraphObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RemoveObserverImpl(&graph_observers_, observer);
}
void GraphImpl::RemoveFrameNodeObserver(FrameNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RemoveObserverImpl(&frame_node_observers_, observer);
}
void GraphImpl::RemovePageNodeObserver(PageNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RemoveObserverImpl(&page_node_observers_, observer);
}
void GraphImpl::RemoveProcessNodeObserver(ProcessNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RemoveObserverImpl(&process_node_observers_, observer);
}
void GraphImpl::RemoveSystemNodeObserver(SystemNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RemoveObserverImpl(&system_node_observers_, observer);
}
void GraphImpl::RemoveWorkerNodeObserver(WorkerNodeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RemoveObserverImpl(&worker_node_observers_, observer);
}
void GraphImpl::PassToGraphImpl(std::unique_ptr<GraphOwned> graph_owned) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
graph_owned_.PassObject(std::move(graph_owned), this);
}
std::unique_ptr<GraphOwned> GraphImpl::TakeFromGraph(GraphOwned* graph_owned) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return graph_owned_.TakeObject(graph_owned, this);
}
void GraphImpl::RegisterObject(GraphRegistered* object) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
registered_objects_.RegisterObject(object);
}
void GraphImpl::UnregisterObject(GraphRegistered* object) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
registered_objects_.UnregisterObject(object);
}
const SystemNode* GraphImpl::FindOrCreateSystemNode() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return FindOrCreateSystemNodeImpl();
}
std::vector<const ProcessNode*> GraphImpl::GetAllProcessNodes() const {
return GetAllNodesOfType<ProcessNodeImpl, const ProcessNode*>();
}
std::vector<const FrameNode*> GraphImpl::GetAllFrameNodes() const {
return GetAllNodesOfType<FrameNodeImpl, const FrameNode*>();
}
std::vector<const PageNode*> GraphImpl::GetAllPageNodes() const {
return GetAllNodesOfType<PageNodeImpl, const PageNode*>();
}
std::vector<const WorkerNode*> GraphImpl::GetAllWorkerNodes() const {
return GetAllNodesOfType<WorkerNodeImpl, const WorkerNode*>();
}
bool GraphImpl::IsEmpty() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return nodes_.empty();
}
ukm::UkmRecorder* GraphImpl::GetUkmRecorder() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return ukm_recorder();
}
NodeDataDescriberRegistry* GraphImpl::GetNodeDataDescriberRegistry() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!describer_registry_)
describer_registry_ = std::make_unique<NodeDataDescriberRegistryImpl>();
return describer_registry_.get();
}
uintptr_t GraphImpl::GetImplType() const {
return kGraphImplType;
}
const void* GraphImpl::GetImpl() const {
return this;
}
#if DCHECK_IS_ON()
bool GraphImpl::IsOnGraphSequence() const {
return sequence_checker_.CalledOnValidSequence();
}
#endif
GraphRegistered* GraphImpl::GetRegisteredObject(uintptr_t type_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return registered_objects_.GetRegisteredObject(type_id);
}
// static
GraphImpl* GraphImpl::FromGraph(const Graph* graph) {
CHECK_EQ(kGraphImplType, graph->GetImplType());
return reinterpret_cast<GraphImpl*>(const_cast<void*>(graph->GetImpl()));
}
SystemNodeImpl* GraphImpl::FindOrCreateSystemNodeImpl() {
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>();
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) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = processes_by_pid_.find(pid);
if (it == processes_by_pid_.end())
return nullptr;
return it->second;
}
FrameNodeImpl* GraphImpl::GetFrameNodeById(
RenderProcessHostId render_process_id,
int render_frame_id) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it =
frames_by_id_.find(ProcessAndFrameId(render_process_id, render_frame_id));
if (it == frames_by_id_.end())
return nullptr;
return it->second;
}
std::vector<ProcessNodeImpl*> GraphImpl::GetAllProcessNodeImpls() const {
return GetAllNodesOfType<ProcessNodeImpl, ProcessNodeImpl*>();
}
std::vector<FrameNodeImpl*> GraphImpl::GetAllFrameNodeImpls() const {
return GetAllNodesOfType<FrameNodeImpl, FrameNodeImpl*>();
}
std::vector<PageNodeImpl*> GraphImpl::GetAllPageNodeImpls() const {
return GetAllNodesOfType<PageNodeImpl, PageNodeImpl*>();
}
std::vector<WorkerNodeImpl*> GraphImpl::GetAllWorkerNodeImpls() const {
return GetAllNodesOfType<WorkerNodeImpl, WorkerNodeImpl*>();
}
size_t GraphImpl::GetNodeAttachedDataCountForTesting(const Node* 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_);
DCHECK(!node_in_transition_);
// Add the node to the graph.
auto it = nodes_.insert(new_node);
DCHECK(it.second); // Inserted successfully
// Advance the node through its lifecycle until it is active in the graph. See
// NodeBase and NodeState for full details of the lifecycle.
node_in_transition_ = new_node;
node_in_transition_state_ = NodeState::kNotInGraph;
new_node->JoinGraph(this);
node_in_transition_state_ = NodeState::kInitializing;
new_node->OnJoiningGraph();
node_in_transition_state_ = NodeState::kJoiningGraph;
DispatchNodeAddedNotifications(new_node);
node_in_transition_ = nullptr;
node_in_transition_state_ = NodeState::kNotInGraph;
}
void GraphImpl::RemoveNode(NodeBase* node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(NodeInGraph(node));
DCHECK_EQ(this, node->graph());
DCHECK(!node_in_transition_);
// Walk the node through the latter half of its lifecycle. See NodeBase and
// NodeState for full details of the lifecycle.
node->OnBeforeLeavingGraph();
node_in_transition_ = node;
node_in_transition_state_ = NodeState::kLeavingGraph;
DispatchNodeRemovedNotifications(node);
RemoveNodeAttachedData(node); // Data added via the public interface.
node->RemoveNodeAttachedData(); // Data added via the private interface.
node->LeaveGraph();
node_in_transition_ = nullptr;
node_in_transition_state_ = NodeState::kNotInGraph;
// Remove the node itself.
size_t erased = nodes_.erase(node);
DCHECK_EQ(1u, erased);
}
size_t GraphImpl::NodeDataDescriberCountForTesting() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!describer_registry_)
return 0;
auto* registry = static_cast<const NodeDataDescriberRegistryImpl*>(
describer_registry_.get());
return registry->size();
}
NodeState GraphImpl::GetNodeState(const NodeBase* node) const {
DCHECK_EQ(this, node->graph());
// If this is a transitioning node (being added to or removed from the graph)
// then return the appropriate state.
if (node == node_in_transition_)
return node_in_transition_state_;
// Otherwise, this is a node at steady state.
return NodeState::kActiveInGraph;
}
template <>
const std::vector<FrameNodeObserver*>& GraphImpl::GetObservers() const {
return frame_node_observers_;
}
template <>
const std::vector<PageNodeObserver*>& GraphImpl::GetObservers() const {
return page_node_observers_;
}
template <>
const std::vector<ProcessNodeObserver*>& GraphImpl::GetObservers() const {
return process_node_observers_;
}
template <>
const std::vector<SystemNodeObserver*>& GraphImpl::GetObservers() const {
return system_node_observers_;
}
template <>
const std::vector<WorkerNodeObserver*>& GraphImpl::GetObservers() const {
return worker_node_observers_;
}
GraphImpl::ProcessAndFrameId::ProcessAndFrameId(
RenderProcessHostId render_process_id,
int render_frame_id)
: render_process_id(render_process_id), render_frame_id(render_frame_id) {}
bool GraphImpl::ProcessAndFrameId::operator<(
const ProcessAndFrameId& other) const {
return std::tie(render_process_id, render_frame_id) <
std::tie(other.render_process_id, other.render_frame_id);
}
GraphImpl::ProcessAndFrameId::~ProcessAndFrameId() = default;
GraphImpl::ProcessAndFrameId::ProcessAndFrameId(
const GraphImpl::ProcessAndFrameId& other) = default;
GraphImpl::ProcessAndFrameId& GraphImpl::ProcessAndFrameId::operator=(
const GraphImpl::ProcessAndFrameId& other) = default;
void GraphImpl::DispatchNodeAddedNotifications(NodeBase* node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This handles the strongly typed observer notifications.
switch (node->type()) {
case NodeTypeEnum::kFrame: {
auto* frame_node = FrameNodeImpl::FromNodeBase(node);
for (auto* observer : frame_node_observers_)
observer->OnFrameNodeAdded(frame_node);
} break;
case NodeTypeEnum::kPage: {
auto* page_node = PageNodeImpl::FromNodeBase(node);
for (auto* observer : page_node_observers_)
observer->OnPageNodeAdded(page_node);
} break;
case NodeTypeEnum::kProcess: {
auto* process_node = ProcessNodeImpl::FromNodeBase(node);
for (auto* observer : process_node_observers_)
observer->OnProcessNodeAdded(process_node);
} break;
case NodeTypeEnum::kSystem: {
auto* system_node = SystemNodeImpl::FromNodeBase(node);
for (auto* observer : system_node_observers_)
observer->OnSystemNodeAdded(system_node);
} break;
case NodeTypeEnum::kWorker: {
auto* worker_node = WorkerNodeImpl::FromNodeBase(node);
for (auto* observer : worker_node_observers_)
observer->OnWorkerNodeAdded(worker_node);
} break;
case NodeTypeEnum::kInvalidType: {
NOTREACHED();
} break;
}
}
void GraphImpl::DispatchNodeRemovedNotifications(NodeBase* node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (node->type()) {
case NodeTypeEnum::kFrame: {
auto* frame_node = FrameNodeImpl::FromNodeBase(node);
for (auto* observer : frame_node_observers_)
observer->OnBeforeFrameNodeRemoved(frame_node);
} break;
case NodeTypeEnum::kPage: {
auto* page_node = PageNodeImpl::FromNodeBase(node);
for (auto* observer : page_node_observers_)
observer->OnBeforePageNodeRemoved(page_node);
} break;
case NodeTypeEnum::kProcess: {
auto* process_node = ProcessNodeImpl::FromNodeBase(node);
for (auto* observer : process_node_observers_)
observer->OnBeforeProcessNodeRemoved(process_node);
} break;
case NodeTypeEnum::kSystem: {
auto* system_node = SystemNodeImpl::FromNodeBase(node);
for (auto* observer : system_node_observers_)
observer->OnBeforeSystemNodeRemoved(system_node);
} break;
case NodeTypeEnum::kWorker: {
auto* worker_node = WorkerNodeImpl::FromNodeBase(node);
for (auto* observer : worker_node_observers_)
observer->OnBeforeWorkerNodeRemoved(worker_node);
} break;
case NodeTypeEnum::kInvalidType: {
NOTREACHED();
} break;
}
}
void GraphImpl::RemoveNodeAttachedData(NodeBase* node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const Node* public_node = node->ToNode();
auto lower =
node_attached_data_map_.lower_bound(std::make_pair(public_node, nullptr));
auto upper = node_attached_data_map_.lower_bound(
std::make_pair(public_node + 1, nullptr));
node_attached_data_map_.erase(lower, upper);
}
int64_t GraphImpl::GetNextNodeSerializationId() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return ++current_node_serialization_id_;
}
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;
}
void GraphImpl::RegisterFrameNodeForId(RenderProcessHostId render_process_id,
int render_frame_id,
FrameNodeImpl* frame_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto insert_result = frames_by_id_.insert(
{ProcessAndFrameId(render_process_id, render_frame_id), frame_node});
DCHECK(insert_result.second);
}
void GraphImpl::UnregisterFrameNodeForId(RenderProcessHostId render_process_id,
int render_frame_id,
FrameNodeImpl* frame_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const ProcessAndFrameId process_and_frame_id(render_process_id,
render_frame_id);
DCHECK_EQ(frames_by_id_.find(process_and_frame_id)->second, frame_node);
frames_by_id_.erase(process_and_frame_id);
}
template <typename NodeType, typename ReturnNodeType>
std::vector<ReturnNodeType> GraphImpl::GetAllNodesOfType() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const auto type = NodeType::Type();
std::vector<ReturnNodeType> ret;
for (auto* node : nodes_) {
if (node->type() == type)
ret.push_back(NodeType::FromNodeBase(node));
}
return ret;
}
void GraphImpl::ReleaseSystemNode() {
if (!system_node_.get())
return;
RemoveNode(system_node_.get());
system_node_.reset();
}
} // namespace performance_manager