blob: 2883d1f246f6bbcc4fd200c1f87b10ae68b0e780 [file] [log] [blame]
// Copyright 2019 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/graph/graph_impl_operations.h"
#include <set>
#include "base/memory/raw_ptr.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/worker_node_impl.h"
namespace performance_manager {
namespace {
bool VisitWorkerClientFrames(
const WorkerNodeImpl* worker,
GraphImplOperations::FrameNodeImplVisitor frame_visitor,
std::set<const FrameNodeImpl*>& visited_frames) {
for (FrameNodeImpl* f : worker->client_frames()) {
// Mark this frame as visited.
const auto [_, inserted] = visited_frames.insert(f);
if (!inserted) {
// Already visited.
continue;
}
if (!frame_visitor(f)) {
return false;
}
}
return true;
}
bool VisitWorkerAndClients(
WorkerNodeImpl* worker,
GraphImplOperations::FrameNodeImplVisitor frame_visitor,
GraphImplOperations::WorkerNodeImplVisitor worker_visitor,
std::set<const FrameNodeImpl*>& visited_frames,
std::set<const WorkerNodeImpl*>& visited_workers) {
// Mark this worker as visited.
const auto [_, inserted] = visited_workers.insert(worker);
if (!inserted) {
// Already visited.
return true;
}
if (!worker_visitor(worker)) {
return false;
}
if (!VisitWorkerClientFrames(worker, frame_visitor, visited_frames)) {
return false;
}
for (WorkerNodeImpl* w : worker->client_workers()) {
if (!VisitWorkerAndClients(w, frame_visitor, worker_visitor, visited_frames,
visited_workers)) {
return false;
}
}
return true;
}
} // namespace
// static
base::flat_set<raw_ptr<PageNodeImpl, CtnExperimental>>
GraphImplOperations::GetAssociatedPageNodes(const ProcessNodeImpl* process) {
std::vector<raw_ptr<PageNodeImpl, CtnExperimental>> page_nodes;
page_nodes.reserve(process->frame_nodes().size());
for (FrameNodeImpl* frame_node : process->frame_nodes()) {
page_nodes.push_back(frame_node->page_node());
}
return base::flat_set<raw_ptr<PageNodeImpl, CtnExperimental>>(
std::move(page_nodes));
}
// static
base::flat_set<raw_ptr<ProcessNodeImpl, CtnExperimental>>
GraphImplOperations::GetAssociatedProcessNodes(const PageNodeImpl* page) {
std::vector<raw_ptr<ProcessNodeImpl, CtnExperimental>> process_nodes;
process_nodes.reserve(10); // Avoid resizing in most cases.
VisitFrameTreePreOrder(page,
[&process_nodes](FrameNodeImpl* frame_node) -> bool {
process_nodes.push_back(frame_node->process_node());
return true;
});
return base::flat_set<raw_ptr<ProcessNodeImpl, CtnExperimental>>(
std::move(process_nodes));
}
// static
std::vector<FrameNodeImpl*> GraphImplOperations::GetFrameNodes(
const PageNodeImpl* page) {
std::vector<FrameNodeImpl*> frame_nodes;
frame_nodes.reserve(20); // This is in the 99.9th %ile of frame tree sizes.
for (FrameNodeImpl* main_frame_node : page->main_frame_nodes()) {
frame_nodes.push_back(main_frame_node);
}
for (size_t i = 0; i < frame_nodes.size(); ++i) {
auto* parent_frame_node = frame_nodes[i];
for (FrameNodeImpl* frame_node : parent_frame_node->child_frame_nodes()) {
frame_nodes.push_back(frame_node);
}
}
return frame_nodes;
}
// static
bool GraphImplOperations::VisitFrameAndChildrenPreOrder(
FrameNodeImpl* frame,
GraphImplOperations::FrameNodeImplVisitor visitor) {
if (!visitor(frame)) {
return false;
}
for (FrameNodeImpl* child : frame->child_frame_nodes()) {
if (!VisitFrameAndChildrenPreOrder(child, visitor)) {
return false;
}
}
return true;
}
// static
bool GraphImplOperations::VisitFrameAndChildrenPostOrder(
FrameNodeImpl* frame,
GraphImplOperations::FrameNodeImplVisitor visitor) {
for (FrameNodeImpl* child : frame->child_frame_nodes()) {
if (!VisitFrameAndChildrenPostOrder(child, visitor)) {
return false;
}
}
if (!visitor(frame)) {
return false;
}
return true;
}
// static
bool GraphImplOperations::VisitFrameTreePreOrder(const PageNodeImpl* page,
FrameNodeImplVisitor visitor) {
for (FrameNodeImpl* main_frame_node : page->main_frame_nodes()) {
if (!VisitFrameAndChildrenPreOrder(main_frame_node, visitor)) {
return false;
}
}
return true;
}
// static
bool GraphImplOperations::VisitFrameTreePostOrder(
const PageNodeImpl* page,
FrameNodeImplVisitor visitor) {
for (FrameNodeImpl* main_frame_node : page->main_frame_nodes()) {
if (!VisitFrameAndChildrenPostOrder(main_frame_node, visitor)) {
return false;
}
}
return true;
}
// static
bool GraphImplOperations::HasFrame(const PageNodeImpl* page,
FrameNodeImpl* frame) {
bool has_frame = false;
VisitFrameTreePreOrder(page, [&has_frame, frame](FrameNodeImpl* f) -> bool {
if (f == frame) {
has_frame = true;
return false;
}
return true;
});
return has_frame;
}
// static
bool GraphImplOperations::VisitAllWorkerClients(
const WorkerNodeImpl* worker,
FrameNodeImplVisitor frame_visitor,
WorkerNodeImplVisitor worker_visitor) {
std::set<const FrameNodeImpl*> visited_frames;
std::set<const WorkerNodeImpl*> visited_workers;
// Don't visit `worker` itself.
if (!VisitWorkerClientFrames(worker, frame_visitor, visited_frames)) {
return false;
}
for (WorkerNodeImpl* w : worker->client_workers()) {
if (!VisitWorkerAndClients(w, frame_visitor, worker_visitor, visited_frames,
visited_workers)) {
return false;
}
}
return true;
}
} // namespace performance_manager