| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/performance_manager/performance_manager_impl.h" |
| |
| #include <atomic> |
| #include <memory> |
| #include <utility> |
| |
| #include "base/check_op.h" |
| #include "base/containers/flat_set.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/location.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/no_destructor.h" |
| #include "base/notreached.h" |
| #include "base/task/delayed_task_handle.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/task/task_traits.h" |
| #include "base/time/time.h" |
| #include "components/performance_manager/graph/frame_node_impl.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 "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/web_contents.h" |
| #include "url/origin.h" |
| |
| namespace performance_manager { |
| |
| namespace { |
| |
| // Singleton instance of PerformanceManagerImpl. Set from the constructor, and |
| // reset from the destructor. Null if the singleton instance doesn't exist, |
| // which only happens very early or very late in the process lifetime (or in |
| // some tests). |
| PerformanceManagerImpl* g_performance_manager = nullptr; |
| |
| // Removes a frame tree from the graph starting from the leaf nodes. |
| void RemoveFrameAndChildrenFromGraph(FrameNodeImpl* frame_node, |
| GraphImpl* graph) { |
| // Recurse on the first child while there is one. |
| while (!frame_node->child_frame_nodes().empty()) { |
| RemoveFrameAndChildrenFromGraph(*(frame_node->child_frame_nodes().begin()), |
| graph); |
| } |
| |
| // Now that all children are deleted, delete this frame. |
| graph->RemoveNode(frame_node); |
| } |
| |
| } // namespace |
| |
| // static |
| bool PerformanceManager::IsAvailable() { |
| return g_performance_manager; |
| } |
| |
| PerformanceManagerImpl::~PerformanceManagerImpl() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| CHECK_EQ(g_performance_manager, this); |
| // TODO(crbug.com/40629049): Move this to a TearDown function. |
| graph_.TearDown(); |
| g_performance_manager = nullptr; |
| } |
| |
| // static |
| GraphImpl* PerformanceManagerImpl::GetGraphImpl() { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| CHECK(g_performance_manager); |
| return &g_performance_manager->graph_; |
| } |
| |
| // static |
| std::unique_ptr<PerformanceManagerImpl> PerformanceManagerImpl::Create() { |
| return base::WrapUnique(new PerformanceManagerImpl()); |
| } |
| |
| // static |
| void PerformanceManagerImpl::Destroy( |
| std::unique_ptr<PerformanceManager> instance) { |
| // `instance` is deleted at the end of this function. |
| } |
| |
| // static |
| std::unique_ptr<FrameNodeImpl> PerformanceManagerImpl::CreateFrameNode( |
| ProcessNodeImpl* process_node, |
| PageNodeImpl* page_node, |
| FrameNodeImpl* parent_frame_node, |
| FrameNodeImpl* outer_document_for_fenced_frame, |
| int render_frame_id, |
| const blink::LocalFrameToken& frame_token, |
| content::BrowsingInstanceId browsing_instance_id, |
| content::SiteInstanceGroupId site_instance_group_id, |
| bool is_current) { |
| return CreateNodeImpl<FrameNodeImpl>( |
| process_node, page_node, parent_frame_node, |
| outer_document_for_fenced_frame, render_frame_id, frame_token, |
| browsing_instance_id, site_instance_group_id, is_current); |
| } |
| |
| // static |
| std::unique_ptr<PageNodeImpl> PerformanceManagerImpl::CreatePageNode( |
| base::WeakPtr<content::WebContents> web_contents, |
| const std::string& browser_context_id, |
| const GURL& visible_url, |
| PagePropertyFlags initial_property_flags, |
| base::TimeTicks visibility_change_time) { |
| return CreateNodeImpl<PageNodeImpl>( |
| std::move(web_contents), browser_context_id, visible_url, |
| initial_property_flags, visibility_change_time); |
| } |
| |
| // static |
| std::unique_ptr<ProcessNodeImpl> PerformanceManagerImpl::CreateProcessNode( |
| BrowserProcessNodeTag tag) { |
| return CreateNodeImpl<ProcessNodeImpl>(tag); |
| } |
| |
| // static |
| std::unique_ptr<ProcessNodeImpl> PerformanceManagerImpl::CreateProcessNode( |
| RenderProcessHostProxy render_process_host_proxy, |
| base::TaskPriority priority) { |
| return CreateNodeImpl<ProcessNodeImpl>(std::move(render_process_host_proxy), |
| priority); |
| } |
| |
| // static |
| std::unique_ptr<ProcessNodeImpl> PerformanceManagerImpl::CreateProcessNode( |
| content::ProcessType process_type, |
| BrowserChildProcessHostProxy browser_child_process_host_proxy) { |
| return CreateNodeImpl<ProcessNodeImpl>( |
| process_type, std::move(browser_child_process_host_proxy)); |
| } |
| |
| // static |
| std::unique_ptr<WorkerNodeImpl> PerformanceManagerImpl::CreateWorkerNode( |
| const std::string& browser_context_id, |
| WorkerNode::WorkerType worker_type, |
| ProcessNodeImpl* process_node, |
| const blink::WorkerToken& worker_token, |
| const url::Origin& origin) { |
| return CreateNodeImpl<WorkerNodeImpl>(browser_context_id, worker_type, |
| process_node, worker_token, origin); |
| } |
| |
| // static |
| void PerformanceManagerImpl::DeleteNode(std::unique_ptr<NodeBase> node) { |
| CHECK(IsAvailable()); |
| GetGraphImpl()->RemoveNode(node.get()); |
| // The node is deleted at the end of this function. |
| } |
| |
| // static |
| void PerformanceManagerImpl::BatchDeleteNodes( |
| std::vector<std::unique_ptr<NodeBase>> nodes) { |
| GraphImpl* graph = GetGraphImpl(); |
| |
| base::flat_set<ProcessNodeImpl*> process_nodes; |
| |
| for (const auto& node : nodes) { |
| switch (node->GetNodeType()) { |
| case PageNodeImpl::Type(): { |
| auto* page_node = PageNodeImpl::FromNodeBase(node.get()); |
| |
| // Delete the main frame nodes until no more exist. |
| while (!page_node->main_frame_nodes().empty()) { |
| RemoveFrameAndChildrenFromGraph( |
| *(page_node->main_frame_nodes().begin()), graph); |
| } |
| |
| graph->RemoveNode(page_node); |
| break; |
| } |
| case ProcessNodeImpl::Type(): { |
| // Keep track of the process nodes for removing once all frames nodes |
| // are removed. |
| auto* process_node = ProcessNodeImpl::FromNodeBase(node.get()); |
| process_nodes.insert(process_node); |
| break; |
| } |
| case FrameNodeImpl::Type(): |
| break; |
| case WorkerNodeImpl::Type(): { |
| auto* worker_node = WorkerNodeImpl::FromNodeBase(node.get()); |
| graph->RemoveNode(worker_node); |
| break; |
| } |
| case SystemNodeImpl::Type(): { |
| NOTREACHED(); |
| } |
| } |
| } |
| |
| // Remove the process nodes from the graph. |
| for (auto* process_node : process_nodes) |
| graph->RemoveNode(process_node); |
| |
| // When |nodes| goes out of scope, all nodes are deleted. |
| } |
| |
| PerformanceManagerImpl::PerformanceManagerImpl() { |
| DETACH_FROM_SEQUENCE(sequence_checker_); |
| CHECK(!g_performance_manager); |
| g_performance_manager = this; |
| |
| graph_.SetUp(); |
| graph_.set_ukm_recorder(ukm::UkmRecorder::Get()); |
| } |
| |
| // static |
| template <typename NodeType, typename... Args> |
| std::unique_ptr<NodeType> PerformanceManagerImpl::CreateNodeImpl( |
| Args&&... constructor_args) { |
| std::unique_ptr<NodeType> new_node = |
| std::make_unique<NodeType>(std::forward<Args>(constructor_args)...); |
| PerformanceManagerImpl::GetGraphImpl()->AddNewNode(new_node.get()); |
| return new_node; |
| } |
| |
| } // namespace performance_manager |