blob: 35f93281a086c132f738c3fab8fbc70e71033bbd [file] [log] [blame]
// 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