blob: b85a5099eb2cac5311c1f411f1a8d9d99d5a45c8 [file]
// 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/process_node_impl.h"
#include "base/logging.h"
#include "chrome/browser/performance_manager/graph/frame_node_impl.h"
#include "chrome/browser/performance_manager/graph/graph_impl.h"
#include "chrome/browser/performance_manager/graph/page_node_impl.h"
namespace performance_manager {
ProcessNodeImpl::ProcessNodeImpl(GraphImpl* graph)
: TypedNodeBase(graph), binding_(this) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
ProcessNodeImpl::~ProcessNodeImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void ProcessNodeImpl::AddFrame(FrameNodeImpl* frame_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const bool inserted = frame_nodes_.insert(frame_node).second;
DCHECK(inserted);
}
void ProcessNodeImpl::RemoveFrame(FrameNodeImpl* frame_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(base::ContainsKey(frame_nodes_, frame_node));
frame_nodes_.erase(frame_node);
}
void ProcessNodeImpl::SetCPUUsage(double cpu_usage) {
cpu_usage_ = cpu_usage;
}
void ProcessNodeImpl::Bind(
resource_coordinator::mojom::ProcessCoordinationUnitRequest request) {
if (binding_.is_bound())
binding_.Close();
binding_.Bind(std::move(request));
}
void ProcessNodeImpl::SetExpectedTaskQueueingDuration(
base::TimeDelta duration) {
expected_task_queueing_duration_.SetAndNotify(this, duration);
}
void ProcessNodeImpl::SetMainThreadTaskLoadIsLow(
bool main_thread_task_load_is_low) {
main_thread_task_load_is_low_.SetAndMaybeNotify(this,
main_thread_task_load_is_low);
}
void ProcessNodeImpl::SetProcessExitStatus(int32_t exit_status) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This may occur as the first event seen in the case where the process
// fails to start or suffers a startup crash.
exit_status_ = exit_status;
// Close the process handle to kill the zombie.
process_.Close();
// No more message should be received from this process.
binding_.Close();
}
void ProcessNodeImpl::SetProcess(base::Process process,
base::Time launch_time) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(process.IsValid());
// Either this is the initial process associated with this process node,
// or it's a subsequent process. In the latter case, there must have been
// an exit status associated with the previous process.
DCHECK(!process_.IsValid() || exit_status_.has_value());
base::ProcessId pid = process.Pid();
SetProcessImpl(std::move(process), pid, launch_time);
}
const base::flat_set<FrameNodeImpl*>& ProcessNodeImpl::GetFrameNodes() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return frame_nodes_;
}
// There is currently not a direct relationship between processes and
// pages. However, frames are children of both processes and frames, so we
// find all of the pages that are reachable from the process's child
// frames.
base::flat_set<PageNodeImpl*> ProcessNodeImpl::GetAssociatedPageNodes() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::flat_set<PageNodeImpl*> page_nodes;
for (auto* frame_node : frame_nodes_)
page_nodes.insert(frame_node->page_node());
return page_nodes;
}
PageNodeImpl* ProcessNodeImpl::GetPageNodeIfExclusive() const {
PageNodeImpl* page_node = nullptr;
for (auto* frame_node : frame_nodes_) {
if (!page_node)
page_node = frame_node->page_node();
if (page_node != frame_node->page_node())
return nullptr;
}
return page_node;
}
void ProcessNodeImpl::SetProcessImpl(base::Process process,
base::ProcessId new_pid,
base::Time launch_time) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
graph()->BeforeProcessPidChange(this, new_pid);
process_ = std::move(process);
process_id_ = new_pid;
launch_time_ = launch_time;
// Clear the exit status for the previous process (if any).
exit_status_.reset();
// Also clear the measurement data (if any), as it references the previous
// process.
private_footprint_kb_ = 0;
cumulative_cpu_usage_ = base::TimeDelta();
}
void ProcessNodeImpl::LeaveGraph() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
NodeBase::LeaveGraph();
// Make as if we're transitioning to the null PID before we die to clear this
// instance from the PID map.
if (process_id_ != base::kNullProcessId)
graph()->BeforeProcessPidChange(this, base::kNullProcessId);
// All child frames should have been removed before the process is removed.
DCHECK(frame_nodes_.empty());
}
} // namespace performance_manager