Commit 6c6de388 authored by Patrick Monette's avatar Patrick Monette Committed by Commit Bot

Reland "[PM] Add SharedWorkerWatcher"

This is a reland of 7c390807

The fix for the issue that caused the revert is here:
https://chromium-review.googlesource.com/c/chromium/src/+/1835164

Original change's description:
> [PM] Add SharedWorkerWatcher
>
> This class observes running shared worker instances, keeps track of
> the connection to their client frames and manages the lifetime of
> worker nodes in the Performance Manager graph.
>
> Bug: 993029
> Change-Id: I2e0c7cd9f194a06405293c22fd543a14ff3c6cbc
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1757283
> Commit-Queue: Patrick Monette <pmonette@chromium.org>
> Reviewed-by: Matt Falkenhagen <falken@chromium.org>
> Reviewed-by: Sigurður Ásgeirsson <siggi@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#701445}

Bug: 993029
Change-Id: Ib77ea36b9cc71ec83ccbe28173fc6053e4a497f8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1829796
Commit-Queue: Patrick Monette <pmonette@chromium.org>
Reviewed-by: default avatarSigurður Ásgeirsson <siggi@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#704055}
parent de1f81b5
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/feature_list.h" #include "base/feature_list.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/performance_manager/browser_child_process_watcher.h" #include "chrome/browser/performance_manager/browser_child_process_watcher.h"
#include "chrome/browser/performance_manager/decorators/frozen_frame_aggregator.h" #include "chrome/browser/performance_manager/decorators/frozen_frame_aggregator.h"
#include "chrome/browser/performance_manager/decorators/page_aggregator.h" #include "chrome/browser/performance_manager/decorators/page_aggregator.h"
...@@ -18,10 +20,14 @@ ...@@ -18,10 +20,14 @@
#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h" #include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h"
#include "chrome/browser/performance_manager/observers/isolation_context_metrics.h" #include "chrome/browser/performance_manager/observers/isolation_context_metrics.h"
#include "chrome/browser/performance_manager/observers/metrics_collector.h" #include "chrome/browser/performance_manager/observers/metrics_collector.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/performance_manager/graph/graph_impl.h" #include "components/performance_manager/graph/graph_impl.h"
#include "components/performance_manager/performance_manager_impl.h" #include "components/performance_manager/performance_manager_impl.h"
#include "components/performance_manager/performance_manager_tab_helper.h" #include "components/performance_manager/performance_manager_tab_helper.h"
#include "components/performance_manager/render_process_user_data.h" #include "components/performance_manager/render_process_user_data.h"
#include "components/performance_manager/shared_worker_watcher.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#if defined(OS_LINUX) #if defined(OS_LINUX)
...@@ -37,6 +43,37 @@ ChromeBrowserMainExtraPartsPerformanceManager:: ...@@ -37,6 +43,37 @@ ChromeBrowserMainExtraPartsPerformanceManager::
ChromeBrowserMainExtraPartsPerformanceManager:: ChromeBrowserMainExtraPartsPerformanceManager::
~ChromeBrowserMainExtraPartsPerformanceManager() = default; ~ChromeBrowserMainExtraPartsPerformanceManager() = default;
// static
void ChromeBrowserMainExtraPartsPerformanceManager::
CreateDefaultPoliciesAndDecorators(performance_manager::GraphImpl* graph) {
graph->PassToGraph(std::make_unique<performance_manager::PageAggregator>());
graph->PassToGraph(
std::make_unique<performance_manager::FrozenFrameAggregator>());
graph->PassToGraph(
std::make_unique<performance_manager::PageAlmostIdleDecorator>());
graph->PassToGraph(
std::make_unique<performance_manager::IsolationContextMetrics>());
graph->PassToGraph(std::make_unique<performance_manager::MetricsCollector>());
graph->PassToGraph(
std::make_unique<performance_manager::ProcessMetricsDecorator>());
if (performance_manager::policies::WorkingSetTrimmerPolicy::
PlatformSupportsWorkingSetTrim()) {
graph->PassToGraph(performance_manager::policies::WorkingSetTrimmerPolicy::
CreatePolicyForPlatform());
}
#if defined(OS_LINUX)
#if BUILDFLAG(USE_TCMALLOC)
if (base::FeatureList::IsEnabled(
performance_manager::features::kDynamicTcmallocTuning)) {
graph->PassToGraph(std::make_unique<
performance_manager::policies::DynamicTcmallocPolicy>());
}
#endif // BUILDFLAG(USE_TCMALLOC)
#endif // defined(OS_LINUX)
}
void ChromeBrowserMainExtraPartsPerformanceManager::PostCreateThreads() { void ChromeBrowserMainExtraPartsPerformanceManager::PostCreateThreads() {
performance_manager_ = performance_manager::PerformanceManagerImpl::Create( performance_manager_ = performance_manager::PerformanceManagerImpl::Create(
base::BindOnce(&ChromeBrowserMainExtraPartsPerformanceManager:: base::BindOnce(&ChromeBrowserMainExtraPartsPerformanceManager::
...@@ -44,6 +81,15 @@ void ChromeBrowserMainExtraPartsPerformanceManager::PostCreateThreads() { ...@@ -44,6 +81,15 @@ void ChromeBrowserMainExtraPartsPerformanceManager::PostCreateThreads() {
browser_child_process_watcher_ = browser_child_process_watcher_ =
std::make_unique<performance_manager::BrowserChildProcessWatcher>(); std::make_unique<performance_manager::BrowserChildProcessWatcher>();
browser_child_process_watcher_->Initialize(); browser_child_process_watcher_->Initialize();
// There are no existing loaded profiles.
DCHECK(g_browser_process->profile_manager()->GetLoadedProfiles().empty());
// Register for profile events to observe them as they come and go.
notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
content::NotificationService::AllSources());
notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
content::NotificationService::AllSources());
} }
void ChromeBrowserMainExtraPartsPerformanceManager::PostMainMessageLoopRun() { void ChromeBrowserMainExtraPartsPerformanceManager::PostMainMessageLoopRun() {
...@@ -52,6 +98,11 @@ void ChromeBrowserMainExtraPartsPerformanceManager::PostMainMessageLoopRun() { ...@@ -52,6 +98,11 @@ void ChromeBrowserMainExtraPartsPerformanceManager::PostMainMessageLoopRun() {
browser_child_process_watcher_->TearDown(); browser_child_process_watcher_->TearDown();
browser_child_process_watcher_.reset(); browser_child_process_watcher_.reset();
// Clear up the worker nodes.
for (auto& shared_worker_watcher : shared_worker_watchers_)
shared_worker_watcher.second->TearDown();
shared_worker_watchers_.clear();
// There may still be WebContents with attached tab helpers at this point in // There may still be WebContents with attached tab helpers at this point in
// time, and there's no convenient later call-out to destroy the performance // time, and there's no convenient later call-out to destroy the performance
// manager. To release the page and frame nodes, detach the tab helpers // manager. To release the page and frame nodes, detach the tab helpers
...@@ -64,35 +115,52 @@ void ChromeBrowserMainExtraPartsPerformanceManager::PostMainMessageLoopRun() { ...@@ -64,35 +115,52 @@ void ChromeBrowserMainExtraPartsPerformanceManager::PostMainMessageLoopRun() {
performance_manager::PerformanceManagerImpl::Destroy( performance_manager::PerformanceManagerImpl::Destroy(
std::move(performance_manager_)); std::move(performance_manager_));
}
// static // Unregister to profile notifications so as to not create more worker
void ChromeBrowserMainExtraPartsPerformanceManager:: // watchers after this point.
CreateDefaultPoliciesAndDecorators(performance_manager::GraphImpl* graph) { notification_registrar_.RemoveAll();
graph->PassToGraph(std::make_unique<performance_manager::PageAggregator>()); }
graph->PassToGraph(
std::make_unique<performance_manager::FrozenFrameAggregator>());
graph->PassToGraph(
std::make_unique<performance_manager::PageAlmostIdleDecorator>());
graph->PassToGraph(
std::make_unique<performance_manager::IsolationContextMetrics>());
graph->PassToGraph(std::make_unique<performance_manager::MetricsCollector>());
graph->PassToGraph(
std::make_unique<performance_manager::ProcessMetricsDecorator>());
if (performance_manager::policies::WorkingSetTrimmerPolicy:: void ChromeBrowserMainExtraPartsPerformanceManager::Observe(
PlatformSupportsWorkingSetTrim()) { int type,
graph->PassToGraph(performance_manager::policies::WorkingSetTrimmerPolicy:: const content::NotificationSource& source,
CreatePolicyForPlatform()); const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PROFILE_CREATED: {
Profile* profile = content::Source<Profile>(source).ptr();
CreateSharedWorkerWatcher(profile);
break;
}
case chrome::NOTIFICATION_PROFILE_DESTROYED: {
Profile* profile = content::Source<Profile>(source).ptr();
DeleteSharedWorkerWatcher(profile);
break;
}
default:
NOTREACHED();
break;
} }
}
#if defined(OS_LINUX) void ChromeBrowserMainExtraPartsPerformanceManager::CreateSharedWorkerWatcher(
#if BUILDFLAG(USE_TCMALLOC) Profile* profile) {
if (base::FeatureList::IsEnabled( auto shared_worker_watcher =
performance_manager::features::kDynamicTcmallocTuning)) { std::make_unique<performance_manager::SharedWorkerWatcher>(
graph->PassToGraph(std::make_unique< profile->UniqueId(),
performance_manager::policies::DynamicTcmallocPolicy>()); content::BrowserContext::GetDefaultStoragePartition(profile)
} ->GetSharedWorkerService(),
#endif // BUILDFLAG(USE_TCMALLOC) &process_node_source_, &frame_node_source_);
#endif // defined(OS_LINUX)
bool inserted = shared_worker_watchers_
.insert({profile, std::move(shared_worker_watcher)})
.second;
DCHECK(inserted);
}
void ChromeBrowserMainExtraPartsPerformanceManager::DeleteSharedWorkerWatcher(
Profile* profile) {
auto it = shared_worker_watchers_.find(profile);
DCHECK(it != shared_worker_watchers_.end());
it->second->TearDown();
shared_worker_watchers_.erase(it);
} }
...@@ -8,17 +8,28 @@ ...@@ -8,17 +8,28 @@
#include <memory> #include <memory>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/chrome_browser_main_extra_parts.h" #include "chrome/browser/chrome_browser_main_extra_parts.h"
#include "components/performance_manager/process_node_source.h"
#include "components/performance_manager/tab_helper_frame_node_source.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
class Profile;
namespace performance_manager { namespace performance_manager {
class BrowserChildProcessWatcher; class BrowserChildProcessWatcher;
class GraphImpl; class GraphImpl;
class PerformanceManagerImpl; class PerformanceManagerImpl;
class SharedWorkerWatcher;
} // namespace performance_manager } // namespace performance_manager
// Handles the initialization of the performance manager and a few dependent
// classes that create/manage graph nodes.
class ChromeBrowserMainExtraPartsPerformanceManager class ChromeBrowserMainExtraPartsPerformanceManager
: public ChromeBrowserMainExtraParts { : public ChromeBrowserMainExtraParts,
public content::NotificationObserver {
public: public:
ChromeBrowserMainExtraPartsPerformanceManager(); ChromeBrowserMainExtraPartsPerformanceManager();
~ChromeBrowserMainExtraPartsPerformanceManager() override; ~ChromeBrowserMainExtraPartsPerformanceManager() override;
...@@ -31,12 +42,33 @@ class ChromeBrowserMainExtraPartsPerformanceManager ...@@ -31,12 +42,33 @@ class ChromeBrowserMainExtraPartsPerformanceManager
void PostCreateThreads() override; void PostCreateThreads() override;
void PostMainMessageLoopRun() override; void PostMainMessageLoopRun() override;
// content::NotificationObserver:
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
// Handlers for profile creation and destruction notifications.
void CreateSharedWorkerWatcher(Profile* profile);
void DeleteSharedWorkerWatcher(Profile* profile);
std::unique_ptr<performance_manager::PerformanceManagerImpl> std::unique_ptr<performance_manager::PerformanceManagerImpl>
performance_manager_; performance_manager_;
std::unique_ptr<performance_manager::BrowserChildProcessWatcher> std::unique_ptr<performance_manager::BrowserChildProcessWatcher>
browser_child_process_watcher_; browser_child_process_watcher_;
content::NotificationRegistrar notification_registrar_;
// Needed by the worker watchers to access existing process nodes and frame
// nodes.
performance_manager::ProcessNodeSource process_node_source_;
performance_manager::TabHelperFrameNodeSource frame_node_source_;
// Observes the lifetime of shared workers.
base::flat_map<Profile*,
std::unique_ptr<performance_manager::SharedWorkerWatcher>>
shared_worker_watchers_;
DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsPerformanceManager); DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsPerformanceManager);
}; };
......
...@@ -43,6 +43,8 @@ static_library("performance_manager") { ...@@ -43,6 +43,8 @@ static_library("performance_manager") {
"performance_manager_lock_observer.h", "performance_manager_lock_observer.h",
"performance_manager_tab_helper.cc", "performance_manager_tab_helper.cc",
"performance_manager_tab_helper.h", "performance_manager_tab_helper.h",
"process_node_source.cc",
"process_node_source.h",
"public/frame_priority/frame_priority.h", "public/frame_priority/frame_priority.h",
"public/frame_priority/max_vote_aggregator.h", "public/frame_priority/max_vote_aggregator.h",
"public/frame_priority/override_vote_aggregator.h", "public/frame_priority/override_vote_aggregator.h",
...@@ -61,6 +63,10 @@ static_library("performance_manager") { ...@@ -61,6 +63,10 @@ static_library("performance_manager") {
"render_process_host_proxy.cc", "render_process_host_proxy.cc",
"render_process_user_data.cc", "render_process_user_data.cc",
"render_process_user_data.h", "render_process_user_data.h",
"shared_worker_watcher.cc",
"shared_worker_watcher.h",
"tab_helper_frame_node_source.cc",
"tab_helper_frame_node_source.h",
"web_contents_proxy.cc", "web_contents_proxy.cc",
"web_contents_proxy_impl.cc", "web_contents_proxy_impl.cc",
"web_contents_proxy_impl.h", "web_contents_proxy_impl.h",
...@@ -99,6 +105,7 @@ source_set("unit_tests") { ...@@ -99,6 +105,7 @@ source_set("unit_tests") {
"performance_manager_tab_helper_unittest.cc", "performance_manager_tab_helper_unittest.cc",
"performance_manager_test_harness.cc", "performance_manager_test_harness.cc",
"performance_manager_test_harness.h", "performance_manager_test_harness.h",
"shared_worker_watcher_unittest.cc",
"web_contents_proxy_unittest.cc", "web_contents_proxy_unittest.cc",
] ]
......
// Copyright 2019 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.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_FRAME_NODE_SOURCE_H_
#define COMPONENTS_PERFORMANCE_MANAGER_FRAME_NODE_SOURCE_H_
#include "base/callback.h"
#include "base/observer_list_types.h"
namespace performance_manager {
class FrameNodeImpl;
// Represents a source of existing frame nodes that lives on the main thread.
// In practice, this is used by the worker watchers as an abstraction over the
// PerformanceManagerTabHelper to make testing easier.
class FrameNodeSource {
public:
virtual ~FrameNodeSource() = default;
using OnbeforeFrameNodeRemovedCallback =
base::OnceCallback<void(FrameNodeImpl*)>;
// Returns the frame node associated with |render_process_id| and |frame_id|.
// Returns null if no such node exists.
virtual FrameNodeImpl* GetFrameNode(int render_process_id, int frame_id) = 0;
// Subscribes to receive removal notification for a frame node.
virtual void SubscribeToFrameNode(
int render_process_id,
int frame_id,
OnbeforeFrameNodeRemovedCallback
on_before_frame_node_removed_callback) = 0;
// Unsubscribes to a frame node
virtual void UnsubscribeFromFrameNode(int render_process_id,
int frame_id) = 0;
};
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_FRAME_NODE_SOURCE_H_
...@@ -248,6 +248,11 @@ void PerformanceManagerImpl::BatchDeleteNodesImpl( ...@@ -248,6 +248,11 @@ void PerformanceManagerImpl::BatchDeleteNodesImpl(
} }
case FrameNodeImpl::Type(): case FrameNodeImpl::Type():
break; break;
case WorkerNodeImpl::Type(): {
auto* worker_node = WorkerNodeImpl::FromNodeBase(it->get());
graph_.RemoveNode(worker_node);
break;
}
case SystemNodeImpl::Type(): case SystemNodeImpl::Type():
case NodeTypeEnum::kInvalidType: case NodeTypeEnum::kInvalidType:
default: { default: {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "components/performance_manager/performance_manager_tab_helper.h" #include "components/performance_manager/performance_manager_tab_helper.h"
#include <type_traits> #include <type_traits>
#include <utility>
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
...@@ -86,8 +87,16 @@ void PerformanceManagerTabHelper::TearDown() { ...@@ -86,8 +87,16 @@ void PerformanceManagerTabHelper::TearDown() {
// incineration. // incineration.
std::vector<std::unique_ptr<NodeBase>> nodes; std::vector<std::unique_ptr<NodeBase>> nodes;
nodes.push_back(std::move(page_node_)); nodes.push_back(std::move(page_node_));
for (auto& kv : frames_) for (auto& kv : frames_) {
nodes.push_back(std::move(kv.second)); std::unique_ptr<FrameNodeImpl> frame_node = std::move(kv.second);
// Notify observers.
for (Observer& observer : observers_)
observer.OnBeforeFrameNodeRemoved(this, frame_node.get());
// Ensure the node will be deleted on the graph sequence.
nodes.push_back(std::move(frame_node));
}
frames_.clear(); frames_.clear();
...@@ -169,7 +178,14 @@ void PerformanceManagerTabHelper::RenderFrameDeleted( ...@@ -169,7 +178,14 @@ void PerformanceManagerTabHelper::RenderFrameDeleted(
} }
DCHECK(it != frames_.end()); DCHECK(it != frames_.end());
performance_manager_->DeleteNode(std::move(it->second)); std::unique_ptr<FrameNodeImpl> frame_node = std::move(it->second);
// Notify observers.
for (Observer& observer : observers_)
observer.OnBeforeFrameNodeRemoved(this, frame_node.get());
// Then delete the node.
performance_manager_->DeleteNode(std::move(frame_node));
frames_.erase(it); frames_.erase(it);
} }
...@@ -228,7 +244,7 @@ void PerformanceManagerTabHelper::RenderFrameHostChanged( ...@@ -228,7 +244,7 @@ void PerformanceManagerTabHelper::RenderFrameHostChanged(
new_frame->SetIsCurrent(true); new_frame->SetIsCurrent(true);
} }
}, },
base::Unretained(old_frame), base::Unretained(new_frame))); old_frame, new_frame));
} }
void PerformanceManagerTabHelper::DidStartLoading() { void PerformanceManagerTabHelper::DidStartLoading() {
...@@ -352,6 +368,26 @@ int64_t PerformanceManagerTabHelper::LastNavigationId() const { ...@@ -352,6 +368,26 @@ int64_t PerformanceManagerTabHelper::LastNavigationId() const {
return last_navigation_id_; return last_navigation_id_;
} }
FrameNodeImpl* PerformanceManagerTabHelper::GetFrameNode(
content::RenderFrameHost* render_frame_host) {
auto it = frames_.find(render_frame_host);
if (it == frames_.end()) {
// Avoid dereferencing an invalid iterator because it produces hard to debug
// crashes.
NOTREACHED();
return nullptr;
}
return it->second.get();
}
void PerformanceManagerTabHelper::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void PerformanceManagerTabHelper::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
template <typename Functor, typename NodeType, typename... Args> template <typename Functor, typename NodeType, typename... Args>
void PerformanceManagerTabHelper::PostToGraph(const base::Location& from_here, void PerformanceManagerTabHelper::PostToGraph(const base::Location& from_here,
Functor&& functor, Functor&& functor,
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "components/performance_manager/web_contents_proxy_impl.h" #include "components/performance_manager/web_contents_proxy_impl.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_user_data.h"
...@@ -66,6 +67,21 @@ class PerformanceManagerTabHelper ...@@ -66,6 +67,21 @@ class PerformanceManagerTabHelper
void SetUkmSourceIdForTesting(ukm::SourceId id) { ukm_source_id_ = id; } void SetUkmSourceIdForTesting(ukm::SourceId id) { ukm_source_id_ = id; }
// Retrieves the frame node associated with |render_frame_host|.
FrameNodeImpl* GetFrameNode(content::RenderFrameHost* render_frame_host);
class Observer : public base::CheckedObserver {
public:
// Invoked when a frame node is about to be removed from the graph.
virtual void OnBeforeFrameNodeRemoved(
PerformanceManagerTabHelper* performance_manager,
FrameNodeImpl* frame_node) = 0;
};
// Adds/removes an observer.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
private: private:
friend class content::WebContentsUserData<PerformanceManagerTabHelper>; friend class content::WebContentsUserData<PerformanceManagerTabHelper>;
friend class WebContentsProxyImpl; friend class WebContentsProxyImpl;
...@@ -102,6 +118,8 @@ class PerformanceManagerTabHelper ...@@ -102,6 +118,8 @@ class PerformanceManagerTabHelper
// Maps from RenderFrameHost to the associated PM node. // Maps from RenderFrameHost to the associated PM node.
std::map<content::RenderFrameHost*, std::unique_ptr<FrameNodeImpl>> frames_; std::map<content::RenderFrameHost*, std::unique_ptr<FrameNodeImpl>> frames_;
base::ObserverList<Observer, true, false> observers_;
// All instances are linked together in a doubly linked list to allow orderly // All instances are linked together in a doubly linked list to allow orderly
// destruction at browser shutdown time. // destruction at browser shutdown time.
static PerformanceManagerTabHelper* first_; static PerformanceManagerTabHelper* first_;
......
// Copyright 2019 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/process_node_source.h"
#include "components/performance_manager/render_process_user_data.h"
#include "content/public/browser/render_process_host.h"
namespace performance_manager {
ProcessNodeImpl* ProcessNodeSource::GetProcessNode(int render_process_id) {
auto* render_process_host =
content::RenderProcessHost::FromID(render_process_id);
DCHECK(render_process_host);
auto* render_process_user_data =
RenderProcessUserData::GetForRenderProcessHost(render_process_host);
DCHECK(render_process_user_data);
return render_process_user_data->process_node();
}
} // namespace performance_manager
// Copyright 2019 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.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_PROCESS_NODE_SOURCE_H_
#define COMPONENTS_PERFORMANCE_MANAGER_PROCESS_NODE_SOURCE_H_
namespace performance_manager {
class ProcessNodeImpl;
// Represents a source of existing process nodes that lives on the main thread.
// In practice, this is used by the worker watchers as an abstraction over the
// peformance_manager::RenderProcessUserData to make testing easier.
class ProcessNodeSource {
public:
virtual ~ProcessNodeSource() = default;
// Retrieves the process node associated with the |render_process_id|.
virtual ProcessNodeImpl* GetProcessNode(int render_process_id);
};
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_PROCESS_NODE_SOURCE_H_
// Copyright 2019 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/shared_worker_watcher.h"
#include <utility>
#include <vector>
#include "components/performance_manager/frame_node_source.h"
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/worker_node_impl.h"
#include "components/performance_manager/performance_manager_impl.h"
#include "components/performance_manager/process_node_source.h"
#include "content/public/browser/shared_worker_instance.h"
namespace performance_manager {
namespace {
// Helper function to add |worker_node| as a child to |frame_node| on the PM
// sequence.
void AddWorkerToFrameNode(FrameNodeImpl* frame_node,
WorkerNodeImpl* worker_node,
GraphImpl* graph) {
worker_node->AddClientFrame(frame_node);
}
// Helper function to remove |worker_node| from |frame_node| on the PM sequence.
void RemoveWorkerFromFrameNode(FrameNodeImpl* frame_node,
WorkerNodeImpl* worker_node,
GraphImpl* graph) {
worker_node->RemoveClientFrame(frame_node);
}
// Helper function to remove all |worker_nodes| from |frame_node| on the PM
// sequence.
void RemoveWorkersFromFrameNode(
FrameNodeImpl* frame_node,
const base::flat_set<WorkerNodeImpl*>& worker_nodes,
GraphImpl* graph) {
for (auto* worker_node : worker_nodes)
worker_node->RemoveClientFrame(frame_node);
}
} // namespace
SharedWorkerWatcher::SharedWorkerWatcher(
const std::string& browser_context_id,
content::SharedWorkerService* shared_worker_service,
ProcessNodeSource* process_node_source,
FrameNodeSource* frame_node_source)
: browser_context_id_(browser_context_id),
shared_worker_service_observer_(this),
process_node_source_(process_node_source),
frame_node_source_(frame_node_source) {
DCHECK(shared_worker_service);
DCHECK(process_node_source_);
DCHECK(frame_node_source_);
shared_worker_service_observer_.Add(shared_worker_service);
}
SharedWorkerWatcher::~SharedWorkerWatcher() {
DCHECK(frame_node_child_workers_.empty());
DCHECK(worker_nodes_.empty());
DCHECK(!shared_worker_service_observer_.IsObservingSources());
}
void SharedWorkerWatcher::TearDown() {
// First clear client-child relations between frames and workers.
for (auto& kv : frame_node_child_workers_) {
const FrameInfo& frame_info = kv.first;
base::flat_set<WorkerNodeImpl*>& child_workers = kv.second;
frame_node_source_->UnsubscribeFromFrameNode(frame_info.render_process_id,
frame_info.frame_id);
// Disconnect all child workers from |frame_node|.
FrameNodeImpl* frame_node = frame_node_source_->GetFrameNode(
frame_info.render_process_id, frame_info.frame_id);
DCHECK(frame_node);
DCHECK(!child_workers.empty());
PerformanceManagerImpl::CallOnGraphImpl(
FROM_HERE,
base::BindOnce(&RemoveWorkersFromFrameNode, frame_node, child_workers));
}
frame_node_child_workers_.clear();
// Then clean all the worker nodes.
std::vector<std::unique_ptr<NodeBase>> nodes;
nodes.reserve(worker_nodes_.size());
for (auto& node : worker_nodes_)
nodes.push_back(std::move(node.second));
worker_nodes_.clear();
PerformanceManagerImpl::GetInstance()->BatchDeleteNodes(std::move(nodes));
shared_worker_service_observer_.RemoveAll();
}
void SharedWorkerWatcher::OnWorkerStarted(
const content::SharedWorkerInstance& instance,
int worker_process_id,
const base::UnguessableToken& dev_tools_token) {
auto worker_node = PerformanceManagerImpl::GetInstance()->CreateWorkerNode(
browser_context_id_, WorkerNode::WorkerType::kShared,
process_node_source_->GetProcessNode(worker_process_id), instance.url(),
dev_tools_token);
bool inserted =
worker_nodes_.emplace(instance, std::move(worker_node)).second;
DCHECK(inserted);
}
void SharedWorkerWatcher::OnBeforeWorkerTerminated(
const content::SharedWorkerInstance& instance) {
auto it = worker_nodes_.find(instance);
DCHECK(it != worker_nodes_.end());
auto worker_node = std::move(it->second);
#if DCHECK_IS_ON()
DCHECK(!base::Contains(clients_to_remove_, worker_node.get()));
#endif // DCHECK_IS_ON()
PerformanceManagerImpl::GetInstance()->DeleteNode(std::move(worker_node));
worker_nodes_.erase(it);
}
void SharedWorkerWatcher::OnClientAdded(
const content::SharedWorkerInstance& instance,
int client_process_id,
int frame_id) {
FrameNodeImpl* frame_node =
frame_node_source_->GetFrameNode(client_process_id, frame_id);
DCHECK(frame_node);
// Connect the nodes in the PM graph.
WorkerNodeImpl* worker_node = GetWorkerNode(instance);
PerformanceManagerImpl::CallOnGraphImpl(
FROM_HERE,
base::BindOnce(&AddWorkerToFrameNode, frame_node, worker_node));
// Keep track of the shared workers that this frame is a client to.
if (AddChildWorker(client_process_id, frame_id, worker_node)) {
frame_node_source_->SubscribeToFrameNode(
client_process_id, frame_id,
base::BindOnce(&SharedWorkerWatcher::OnBeforeFrameNodeRemoved,
base::Unretained(this), client_process_id, frame_id));
}
}
void SharedWorkerWatcher::OnClientRemoved(
const content::SharedWorkerInstance& instance,
int client_process_id,
int frame_id) {
WorkerNodeImpl* worker_node = GetWorkerNode(instance);
FrameNodeImpl* frame_node =
frame_node_source_->GetFrameNode(client_process_id, frame_id);
// It's possible that the frame was destroyed before receiving the
// OnClientRemoved() for all of its child shared worker. Nothing to do in
// that case because OnBeforeFrameNodeRemoved() took care of removing this
// client from its child worker nodes.
if (!frame_node) {
#if DCHECK_IS_ON()
// These debug only checks ensure that this code path is only taken if
// OnBeforeFrameNodeRemoved() was already called for that frame.
auto it = clients_to_remove_.find(worker_node);
DCHECK(it != clients_to_remove_.end());
int& count = it->second;
DCHECK_GT(count, 0);
--count;
if (count == 0)
clients_to_remove_.erase(it);
#endif // DCHECK_IS_ON()
return;
}
// Disconnect the node.
PerformanceManagerImpl::CallOnGraphImpl(
FROM_HERE,
base::BindOnce(&RemoveWorkerFromFrameNode, frame_node, worker_node));
// Remove |worker_node| from the set of workers that this frame is a client
// of.
if (RemoveChildWorker(client_process_id, frame_id, worker_node))
frame_node_source_->UnsubscribeFromFrameNode(client_process_id, frame_id);
}
void SharedWorkerWatcher::OnBeforeFrameNodeRemoved(int render_process_id,
int frame_id,
FrameNodeImpl* frame_node) {
auto it =
frame_node_child_workers_.find(FrameInfo{render_process_id, frame_id});
DCHECK(it != frame_node_child_workers_.end());
// Clean up all child workers of this frame node.
base::flat_set<WorkerNodeImpl*> child_workers = std::move(it->second);
frame_node_child_workers_.erase(it);
// Disconnect all child workers from |frame_node|.
DCHECK(!child_workers.empty());
PerformanceManagerImpl::CallOnGraphImpl(
FROM_HERE,
base::BindOnce(&RemoveWorkersFromFrameNode, frame_node, child_workers));
#if DCHECK_IS_ON()
for (WorkerNodeImpl* worker_node : child_workers) {
// Now expect that this frame will be removed as a client for each worker
// in |child_workers|.
// Note: the [] operator is intentionally used to default initialize the
// count to zero if needed.
clients_to_remove_[worker_node]++;
}
#endif // DCHECK_IS_ON()
}
bool SharedWorkerWatcher::AddChildWorker(int render_process_id,
int frame_id,
WorkerNodeImpl* child_worker_node) {
auto insertion_result =
frame_node_child_workers_.insert({{render_process_id, frame_id}, {}});
auto& child_workers = insertion_result.first->second;
bool inserted = child_workers.insert(child_worker_node).second;
DCHECK(inserted);
return insertion_result.second;
}
bool SharedWorkerWatcher::RemoveChildWorker(int render_process_id,
int frame_id,
WorkerNodeImpl* child_worker_node) {
auto it =
frame_node_child_workers_.find(FrameInfo{render_process_id, frame_id});
DCHECK(it != frame_node_child_workers_.end());
auto& child_workers = it->second;
size_t removed = child_workers.erase(child_worker_node);
DCHECK_EQ(removed, 1u);
if (child_workers.empty()) {
frame_node_child_workers_.erase(it);
return true;
}
return false;
}
WorkerNodeImpl* SharedWorkerWatcher::GetWorkerNode(
const content::SharedWorkerInstance& instance) {
auto it = worker_nodes_.find(instance);
if (it == worker_nodes_.end()) {
NOTREACHED();
return nullptr;
}
return it->second.get();
}
bool operator<(const SharedWorkerWatcher::FrameInfo& lhs,
const SharedWorkerWatcher::FrameInfo& rhs) {
return std::tie(lhs.render_process_id, lhs.frame_id) <
std::tie(rhs.render_process_id, rhs.frame_id);
}
} // namespace performance_manager
// Copyright 2019 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.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_SHARED_WORKER_WATCHER_H_
#define COMPONENTS_PERFORMANCE_MANAGER_SHARED_WORKER_WATCHER_H_
#include <memory>
#include <string>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/scoped_observer.h"
#include "content/public/browser/shared_worker_service.h"
namespace content {
class SharedWorkerInstance;
}
namespace performance_manager {
class FrameNodeImpl;
class FrameNodeSource;
class ProcessNodeSource;
class WorkerNodeImpl;
// This class keeps track of running shared workers for a single browser context
// and handles the ownership of the worker nodes.
class SharedWorkerWatcher : public content::SharedWorkerService::Observer {
public:
SharedWorkerWatcher(const std::string& browser_context_id,
content::SharedWorkerService* shared_worker_service,
ProcessNodeSource* process_node_source,
FrameNodeSource* frame_node_source);
~SharedWorkerWatcher() override;
// Cleans up this instance and ensures shared worker nodes are correctly
// destroyed on the PM graph.
void TearDown();
// content::SharedWorkerService::Observer:
void OnWorkerStarted(const content::SharedWorkerInstance& instance,
int worker_process_id,
const base::UnguessableToken& dev_tools_token) override;
void OnBeforeWorkerTerminated(
const content::SharedWorkerInstance& instance) override;
void OnClientAdded(const content::SharedWorkerInstance& instance,
int client_process_id,
int frame_id) override;
void OnClientRemoved(const content::SharedWorkerInstance& instance,
int client_process_id,
int frame_id) override;
private:
friend class SharedWorkerWatcherTest;
void OnBeforeFrameNodeRemoved(int render_process_id,
int frame_id,
FrameNodeImpl* frame_node);
bool AddChildWorker(int render_process_id,
int frame_id,
WorkerNodeImpl* child_worker_node);
bool RemoveChildWorker(int render_process_id,
int frame_id,
WorkerNodeImpl* child_worker_node);
// Helper function to retrieve an existing worker node.
WorkerNodeImpl* GetWorkerNode(const content::SharedWorkerInstance& instance);
// The ID of the BrowserContext who owns the shared worker service.
const std::string browser_context_id_;
// Observes the SharedWorkerService for this browser context.
ScopedObserver<content::SharedWorkerService,
content::SharedWorkerService::Observer>
shared_worker_service_observer_;
// Used to retrieve an existing process node from its render process ID.
ProcessNodeSource* const process_node_source_;
// Used to retrieve an existing frame node from its render process ID and
// frame ID. Also allows to subscribe to a frame's deletion notification.
FrameNodeSource* const frame_node_source_;
// Maps each SharedWorkerInstance to its worker node.
base::flat_map<content::SharedWorkerInstance, std::unique_ptr<WorkerNodeImpl>>
worker_nodes_;
// Maps each frame to the shared workers that this frame is a client of. This
// is used when a frame is torn down before the OnBeforeWorkerTerminated() is
// received, to ensure the deletion of the worker nodes in the right order
// (workers before frames).
struct FrameInfo {
int render_process_id;
int frame_id;
};
// Comparison operator to allow using FrameInfo as a key.
friend bool operator<(const FrameInfo& lhs, const FrameInfo& rhs);
base::flat_map<FrameInfo, base::flat_set<WorkerNodeImpl*>>
frame_node_child_workers_;
#if DCHECK_IS_ON()
// Keeps track of how many OnClientRemoved() calls are expected for an
// existing worker. This happens when OnBeforeFrameNodeRemoved() is invoked
// before OnClientRemoved().
base::flat_map<WorkerNodeImpl*, int> clients_to_remove_;
#endif // DCHECK_IS_ON()
DISALLOW_COPY_AND_ASSIGN(SharedWorkerWatcher);
};
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_SHARED_WORKER_WATCHER_H_
// Copyright 2019 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/tab_helper_frame_node_source.h"
#include <utility>
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
namespace performance_manager {
TabHelperFrameNodeSource::TabHelperFrameNodeSource()
: performance_manager_tab_helper_observers_(this) {}
TabHelperFrameNodeSource::~TabHelperFrameNodeSource() {
DCHECK(observed_frame_nodes_.empty());
DCHECK(!performance_manager_tab_helper_observers_.IsObservingSources());
}
FrameNodeImpl* TabHelperFrameNodeSource::GetFrameNode(int render_process_id,
int frame_id) {
// Retrieve the client's RenderFrameHost and its associated
// PerformanceManagerTabHelper.
auto* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, frame_id);
if (!render_frame_host)
return nullptr;
PerformanceManagerTabHelper* performance_manager_tab_helper =
PerformanceManagerTabHelper::FromWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host));
DCHECK(performance_manager_tab_helper);
return performance_manager_tab_helper->GetFrameNode(render_frame_host);
}
void TabHelperFrameNodeSource::SubscribeToFrameNode(
int render_process_id,
int frame_id,
OnbeforeFrameNodeRemovedCallback on_before_frame_node_removed_callback) {
auto* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, frame_id);
DCHECK(render_frame_host);
PerformanceManagerTabHelper* performance_manager_tab_helper =
PerformanceManagerTabHelper::FromWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host));
DCHECK(performance_manager_tab_helper);
FrameNodeImpl* frame_node =
performance_manager_tab_helper->GetFrameNode(render_frame_host);
// Add the frame to the set of observed frames that belongs to
// |performance_manager_tab_helper|.
if (AddObservedFrameNode(performance_manager_tab_helper, frame_node)) {
// Start observing the tab helper only if this is the first observed frame
// that is associated with it.
performance_manager_tab_helper_observers_.Add(
performance_manager_tab_helper);
}
// Then remember the frame's callback.
bool inserted =
frame_node_callbacks_
.insert(std::make_pair(
frame_node, std::move(on_before_frame_node_removed_callback)))
.second;
DCHECK(inserted);
}
void TabHelperFrameNodeSource::UnsubscribeFromFrameNode(int render_process_id,
int frame_id) {
auto* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, frame_id);
DCHECK(render_frame_host);
PerformanceManagerTabHelper* performance_manager_tab_helper =
PerformanceManagerTabHelper::FromWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host));
DCHECK(performance_manager_tab_helper);
FrameNodeImpl* frame_node =
performance_manager_tab_helper->GetFrameNode(render_frame_host);
// Remove the frame's callback without invoking it.
size_t removed = frame_node_callbacks_.erase(frame_node);
DCHECK_EQ(removed, 1u);
// And also remove the frame from the set of observed frames that belongs to
// |performance_manager_tab_helper|.
if (RemoveObservedFrameNode(performance_manager_tab_helper, frame_node)) {
// Stop observing that tab helper if there no longer are any observed
// frames that are associated with it.
performance_manager_tab_helper_observers_.Remove(
performance_manager_tab_helper);
}
}
void TabHelperFrameNodeSource::OnBeforeFrameNodeRemoved(
PerformanceManagerTabHelper* performance_manager_tab_helper,
FrameNodeImpl* frame_node) {
// The tab helper owns many other frames than the ones this instance cares
// about. Ignore irrelevant notifications.
auto it = frame_node_callbacks_.find(frame_node);
if (it == frame_node_callbacks_.end())
return;
// Invoke the frame's callback and remove it.
std::move(it->second).Run(frame_node);
frame_node_callbacks_.erase(it);
// And also remove the frame from the set of observed frames that belong to
// |performance_manager_tab_helper|.
if (RemoveObservedFrameNode(performance_manager_tab_helper, frame_node)) {
// Stop observing that tab helper if there no longer are any observed
// frames that are associated with it.
performance_manager_tab_helper_observers_.Remove(
performance_manager_tab_helper);
}
}
bool TabHelperFrameNodeSource::AddObservedFrameNode(
PerformanceManagerTabHelper* performance_manager_tab_helper,
FrameNodeImpl* frame_node) {
auto insertion_result =
observed_frame_nodes_.insert({performance_manager_tab_helper, {}});
base::flat_set<FrameNodeImpl*>& frame_nodes = insertion_result.first->second;
bool inserted = frame_nodes.insert(frame_node).second;
DCHECK(inserted);
return insertion_result.second;
}
bool TabHelperFrameNodeSource::RemoveObservedFrameNode(
PerformanceManagerTabHelper* performance_manager_tab_helper,
FrameNodeImpl* frame_node) {
auto it = observed_frame_nodes_.find(performance_manager_tab_helper);
DCHECK(it != observed_frame_nodes_.end());
base::flat_set<FrameNodeImpl*>& frame_nodes = it->second;
size_t removed = frame_nodes.erase(frame_node);
DCHECK_EQ(removed, 1u);
if (frame_nodes.empty()) {
observed_frame_nodes_.erase(it);
return true;
}
return false;
}
} // namespace performance_manager
// Copyright 2019 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.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_TAB_HELPER_FRAME_NODE_SOURCE_H_
#define COMPONENTS_PERFORMANCE_MANAGER_TAB_HELPER_FRAME_NODE_SOURCE_H_
#include "components/performance_manager/frame_node_source.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/scoped_observer.h"
#include "components/performance_manager/performance_manager_tab_helper.h"
namespace performance_manager {
// An implementation of FrameNodeSource that uses PerformanceManagerTabHelper to
// get frame node information.
class TabHelperFrameNodeSource : public FrameNodeSource,
public PerformanceManagerTabHelper::Observer {
public:
TabHelperFrameNodeSource();
~TabHelperFrameNodeSource() override;
// FrameNodeSource:
FrameNodeImpl* GetFrameNode(int render_process_id, int frame_id) override;
void SubscribeToFrameNode(int render_process_id,
int frame_id,
OnbeforeFrameNodeRemovedCallback
on_before_frame_node_removed_callback) override;
void UnsubscribeFromFrameNode(int render_process_id, int frame_id) override;
// PerformanceManagerTabHelper::Observer:
void OnBeforeFrameNodeRemoved(
PerformanceManagerTabHelper* performance_manager_tab_helper,
FrameNodeImpl* frame_node) override;
private:
// Adds |frame_node| to the set of observed frame nodes associated with
// |performance_manager_tab_helper|. Returns true if |frame_node| was the
// first frame added to that set.
bool AddObservedFrameNode(
PerformanceManagerTabHelper* performance_manager_tab_helper,
FrameNodeImpl* frame_node);
// Removes |frame_node| to the set of observed frame nodes associated with
// |performance_manager_tab_helper|. Returns true if |frame_node| was the
// last frame removed from that set.
bool RemoveObservedFrameNode(
PerformanceManagerTabHelper* performance_manager_tab_helper,
FrameNodeImpl* frame_node);
// Maps each observed frame node to their callback.
base::flat_map<FrameNodeImpl*, OnbeforeFrameNodeRemovedCallback>
frame_node_callbacks_;
// Maps each tab helper to the set of observed frame nodes that belongs to
// that tab helper.
base::flat_map<PerformanceManagerTabHelper*, base::flat_set<FrameNodeImpl*>>
observed_frame_nodes_;
// Observes frame node deletions.
ScopedObserver<PerformanceManagerTabHelper,
PerformanceManagerTabHelper::Observer>
performance_manager_tab_helper_observers_;
DISALLOW_COPY_AND_ASSIGN(TabHelperFrameNodeSource);
};
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_TAB_HELPER_FRAME_NODE_SOURCE_H_
...@@ -12,9 +12,13 @@ ...@@ -12,9 +12,13 @@
class GURL; class GURL;
namespace base {
class UnguessableToken;
}
namespace url { namespace url {
class Origin; class Origin;
} // namespace url }
namespace content { namespace content {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment