diff options
Diffstat (limited to 'chromium/components/performance_manager/public')
14 files changed, 524 insertions, 14 deletions
diff --git a/chromium/components/performance_manager/public/decorators/page_load_tracker_decorator_helper.h b/chromium/components/performance_manager/public/decorators/page_load_tracker_decorator_helper.h index 5ebe065fb5e..e4fa05d4960 100644 --- a/chromium/components/performance_manager/public/decorators/page_load_tracker_decorator_helper.h +++ b/chromium/components/performance_manager/public/decorators/page_load_tracker_decorator_helper.h @@ -12,7 +12,7 @@ namespace performance_manager { // This class must be instantiated on the UI thread in order to maintain the // PageLoadTracker decorator of PageNodes. class PageLoadTrackerDecoratorHelper - : public PerformanceManagerMainThreadObserver { + : public PerformanceManagerMainThreadObserverDefaultImpl { public: PageLoadTrackerDecoratorHelper(); ~PageLoadTrackerDecoratorHelper() override; diff --git a/chromium/components/performance_manager/public/decorators/v8_per_frame_memory_decorator.h b/chromium/components/performance_manager/public/decorators/v8_per_frame_memory_decorator.h new file mode 100644 index 00000000000..2d3b2c59b40 --- /dev/null +++ b/chromium/components/performance_manager/public/decorators/v8_per_frame_memory_decorator.h @@ -0,0 +1,198 @@ +// Copyright 2020 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_PUBLIC_DECORATORS_V8_PER_FRAME_MEMORY_DECORATOR_H_ +#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_DECORATORS_V8_PER_FRAME_MEMORY_DECORATOR_H_ + +#include "base/sequence_checker.h" +#include "base/time/time.h" +#include "components/performance_manager/public/graph/graph.h" +#include "components/performance_manager/public/graph/graph_registered.h" +#include "components/performance_manager/public/graph/node_data_describer.h" +#include "components/performance_manager/public/graph/process_node.h" +#include "content/public/common/performance_manager/v8_per_frame_memory.mojom.h" + +namespace performance_manager { + +namespace internal { + +// A callback that will bind a V8PerFrameMemoryReporter interface to +// communicate with the given process. Exposed so that it can be overridden to +// implement the interface with a test fake. +using BindV8PerFrameMemoryReporterCallback = base::RepeatingCallback<void( + mojo::PendingReceiver<performance_manager::mojom::V8PerFrameMemoryReporter>, + RenderProcessHostProxy)>; + +// Sets a callback that will be used to bind the V8PerFrameMemoryReporter +// interface. The callback is owned by the caller and must live until this +// function is called again with nullptr. +void SetBindV8PerFrameMemoryReporterCallbackForTesting( + BindV8PerFrameMemoryReporterCallback* callback); + +} // namespace internal + +// A decorator that queries each renderer process for the amount of memory used +// by V8 in each frame. +// +// To start sampling create a MeasurementRequest object that specifies how +// often to request a memory measurement. Delete the object when you no longer +// need measurements. Measurement involves some overhead so choose the lowest +// sampling frequency your use case needs. The decorator will use the highest +// sampling frequency that any caller requests, and stop measurements entirely +// when no more MeasurementRequest objects exist. +// +// When measurements are available the decorator attaches them to FrameData and +// ProcessData objects that can be retrieved with FrameData::ForFrameNode and +// ProcessData::ForProcessNode. ProcessData objects can be cleaned up when +// MeasurementRequest objects are deleted so callers must save the measurements +// they are interested in before releasing their MeasurementRequest. +// +// MeasurementRequest, FrameData and ProcessData must all be accessed on the +// graph sequence. +class V8PerFrameMemoryDecorator + : public GraphOwned, + public GraphRegisteredImpl<V8PerFrameMemoryDecorator>, + public ProcessNode::ObserverDefaultImpl, + public NodeDataDescriberDefaultImpl { + public: + class MeasurementRequest; + class FrameData; + class ProcessData; + + V8PerFrameMemoryDecorator(); + ~V8PerFrameMemoryDecorator() override; + + V8PerFrameMemoryDecorator(const V8PerFrameMemoryDecorator&) = delete; + V8PerFrameMemoryDecorator& operator=(const V8PerFrameMemoryDecorator&) = + delete; + + // GraphOwned implementation. + void OnPassedToGraph(Graph* graph) override; + void OnTakenFromGraph(Graph* graph) override; + + // ProcessNodeObserver overrides. + void OnProcessNodeAdded(const ProcessNode* process_node) override; + + // NodeDataDescriber overrides. + base::Value DescribeFrameNodeData(const FrameNode* node) const override; + base::Value DescribeProcessNodeData(const ProcessNode* node) const override; + + // Returns the amount of time to wait between requests for each process. + // Returns a zero TimeDelta if no requests should be made. + base::TimeDelta GetMinTimeBetweenRequestsPerProcess() const; + + private: + friend class MeasurementRequest; + + void AddMeasurementRequest(MeasurementRequest* request); + void RemoveMeasurementRequest(MeasurementRequest* request); + void UpdateProcessMeasurementSchedules() const; + + Graph* graph_ = nullptr; + + // List of requests sorted by sample_frequency (lowest first). + std::vector<MeasurementRequest*> measurement_requests_; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +class V8PerFrameMemoryDecorator::MeasurementRequest { + public: + // Creates a MeasurementRequest but does not start the measurements. Call + // StartMeasurement to add it to the request list. + explicit MeasurementRequest(const base::TimeDelta& sample_frequency); + + // Creates a MeasurementRequest and calls StartMeasurement. This will request + // measurements for all ProcessNode's in |graph| with frequency + // |sample_frequency|. + MeasurementRequest(const base::TimeDelta& sample_frequency, Graph* graph); + ~MeasurementRequest(); + + MeasurementRequest(const MeasurementRequest&) = delete; + MeasurementRequest& operator=(const MeasurementRequest&) = delete; + + const base::TimeDelta& sample_frequency() const { return sample_frequency_; } + + // Requests measurements for all ProcessNode's in |graph| with this object's + // sample frequency. This must only be called once for each + // MeasurementRequest. + void StartMeasurement(Graph* graph); + + private: + friend class V8PerFrameMemoryDecorator; + void OnDecoratorUnregistered(); + + base::TimeDelta sample_frequency_; + V8PerFrameMemoryDecorator* decorator_ = nullptr; +}; + +class V8PerFrameMemoryDecorator::FrameData { + public: + FrameData() = default; + virtual ~FrameData() = default; + + FrameData(const FrameData&) = delete; + FrameData& operator=(const FrameData&) = delete; + + // Returns the number of bytes used by V8 for this frame at the last + // measurement. + uint64_t v8_bytes_used() const { return v8_bytes_used_; } + + void set_v8_bytes_used(uint64_t v8_bytes_used) { + v8_bytes_used_ = v8_bytes_used; + } + + // Returns FrameData for the given node, or nullptr if no measurement has + // been taken. The returned pointer must only be accessed on the graph + // sequence and may go invalid at any time after leaving the calling scope. + static const FrameData* ForFrameNode(const FrameNode* node); + + private: + uint64_t v8_bytes_used_ = 0; +}; + +class V8PerFrameMemoryDecorator::ProcessData { + public: + ProcessData() = default; + virtual ~ProcessData() = default; + + ProcessData(const ProcessData&) = delete; + ProcessData& operator=(const ProcessData&) = delete; + + // Returns the number of bytes used by V8 at the last measurement in this + // process that could not be attributed to a frame. + uint64_t unassociated_v8_bytes_used() const { + return unassociated_v8_bytes_used_; + } + + void set_unassociated_v8_bytes_used(uint64_t unassociated_v8_bytes_used) { + unassociated_v8_bytes_used_ = unassociated_v8_bytes_used; + } + + // Returns FrameData for the given node, or nullptr if no measurement has + // been taken. The returned pointer must only be accessed on the graph + // sequence and may go invalid at any time after leaving the calling scope. + static const ProcessData* ForProcessNode(const ProcessNode* node); + + private: + uint64_t unassociated_v8_bytes_used_ = 0; +}; + +// Wrapper that can instantiate a V8PerFrameMemoryDecorator::MeasurementRequest +// from any sequence. +class V8PerFrameMemoryRequest { + public: + explicit V8PerFrameMemoryRequest(const base::TimeDelta& sample_frequency); + ~V8PerFrameMemoryRequest(); + + V8PerFrameMemoryRequest(const V8PerFrameMemoryRequest&) = delete; + V8PerFrameMemoryRequest& operator=(const V8PerFrameMemoryRequest&) = delete; + + private: + std::unique_ptr<V8PerFrameMemoryDecorator::MeasurementRequest> request_; +}; + +} // namespace performance_manager + +#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_DECORATORS_V8_PER_FRAME_MEMORY_DECORATOR_H_ diff --git a/chromium/components/performance_manager/public/features.h b/chromium/components/performance_manager/public/features.h index 0c4e76f7333..2f22e6d5118 100644 --- a/chromium/components/performance_manager/public/features.h +++ b/chromium/components/performance_manager/public/features.h @@ -29,6 +29,11 @@ struct TabLoadingFrameNavigationThrottlesParams { // non-primary content frames. base::TimeDelta minimum_throttle_timeout; base::TimeDelta maximum_throttle_timeout; + + // The multiple of elapsed time from navigation start until + // FirstContentfulPaint (FCP) that is used in calculating the timeout to apply + // to the throttles. + double fcp_multiple; }; } // namespace features diff --git a/chromium/components/performance_manager/public/graph/frame_node.h b/chromium/components/performance_manager/public/graph/frame_node.h index bf74cc4fd8c..1adfefadedb 100644 --- a/chromium/components/performance_manager/public/graph/frame_node.h +++ b/chromium/components/performance_manager/public/graph/frame_node.h @@ -7,6 +7,7 @@ #include "base/containers/flat_set.h" #include "base/macros.h" +#include "base/util/type_safety/strong_alias.h" #include "components/performance_manager/public/frame_priority/frame_priority.h" #include "components/performance_manager/public/graph/node.h" #include "components/performance_manager/public/mojom/coordination_unit.mojom.h" @@ -26,6 +27,10 @@ class ProcessNode; class RenderFrameHostProxy; class WorkerNode; +// A strongly typed unguessable token for the frame tokens. +using FrameToken = + util::StrongAlias<class FrameTokenTag, base::UnguessableToken>; + // Frame nodes form a tree structure, each FrameNode at most has one parent that // is a FrameNode. Conceptually, a frame corresponds to a // content::RenderFrameHost in the browser, and a content::RenderFrameImpl / @@ -57,6 +62,7 @@ class FrameNode : public Node { using InterventionPolicy = mojom::InterventionPolicy; using LifecycleState = mojom::LifecycleState; using Observer = FrameNodeObserver; + using PageNodeVisitor = base::RepeatingCallback<bool(const PageNode*)>; using PriorityAndReason = frame_priority::PriorityAndReason; class ObserverDefaultImpl; @@ -84,9 +90,9 @@ class FrameNode : public Node { // be current at a time. This is a constant over the lifetime of the frame. virtual int GetFrameTreeNodeId() const = 0; - // Gets the devtools token associated with this frame. This is a constant over - // the lifetime of the frame. - virtual const base::UnguessableToken& GetDevToolsToken() const = 0; + // Gets the unique token associated with this frame. This is a constant over + // the lifetime of the frame and unique across all frames for all time. + virtual const FrameToken& GetFrameToken() const = 0; // Gets the ID of the browsing instance to which this frame belongs. This is a // constant over the lifetime of the frame. @@ -110,6 +116,17 @@ class FrameNode : public Node { // VisitChildFrameNodes when that makes sense. virtual const base::flat_set<const FrameNode*> GetChildFrameNodes() const = 0; + // Visits the page nodes that have been opened by this frame. The iteration + // is halted if the visitor returns false. Returns true if every call to the + // visitor returned true, false otherwise. + virtual bool VisitOpenedPageNodes(const PageNodeVisitor& visitor) const = 0; + + // Returns the set of opened pages associatted with this frame. Note that + // this incurs a full container copy all the opened nodes. Please use + // VisitOpenedPageNodes when that makes sense. This can change over the + // lifetime of the frame. + virtual const base::flat_set<const PageNode*> GetOpenedPageNodes() const = 0; + // Returns the current lifecycle state of this frame. See // FrameNodeObserver::OnFrameLifecycleStateChanged. virtual LifecycleState GetLifecycleState() const = 0; @@ -160,6 +177,9 @@ class FrameNode : public Node { // Returns true if at least one form of the frame has been interacted with. virtual bool HadFormInteraction() const = 0; + // Returns true if the frame is audible, false otherwise. + virtual bool IsAudible() const = 0; + // Returns a proxy to the RenderFrameHost associated with this node. The // proxy may only be dereferenced on the UI thread. virtual const RenderFrameHostProxy& GetRenderFrameHostProxy() const = 0; @@ -224,6 +244,9 @@ class FrameNodeObserver { // Called when the frame receives a form interaction. virtual void OnHadFormInteractionChanged(const FrameNode* frame_node) = 0; + // Invoked when the IsAudible property changes. + virtual void OnIsAudibleChanged(const FrameNode* frame_node) = 0; + // Events with no property changes. // Invoked when a non-persistent notification has been issued by the frame. @@ -270,6 +293,7 @@ class FrameNode::ObserverDefaultImpl : public FrameNodeObserver { const FrameNode* frame_node, const PriorityAndReason& previous_value) override {} void OnHadFormInteractionChanged(const FrameNode* frame_node) override {} + void OnIsAudibleChanged(const FrameNode* frame_node) override {} void OnNonPersistentNotificationCreated( const FrameNode* frame_node) override {} void OnFirstContentfulPaint( diff --git a/chromium/components/performance_manager/public/graph/graph.h b/chromium/components/performance_manager/public/graph/graph.h index 74e1ae56bb6..f00a3212388 100644 --- a/chromium/components/performance_manager/public/graph/graph.h +++ b/chromium/components/performance_manager/public/graph/graph.h @@ -92,8 +92,8 @@ class Graph { // registered. template <typename DerivedType> DerivedType* GetRegisteredObjectAs() { - // Be sure to access the TypeId provided GraphRegisteredImpl, in case this - // class has other TypeId implementations. + // Be sure to access the TypeId provided by GraphRegisteredImpl, in case + // this class has other TypeId implementations. GraphRegistered* object = GetRegisteredObject(GraphRegisteredImpl<DerivedType>::TypeId()); return static_cast<DerivedType*>(object); diff --git a/chromium/components/performance_manager/public/graph/node_attached_data.h b/chromium/components/performance_manager/public/graph/node_attached_data.h index 88e9561351a..51fab9fdd12 100644 --- a/chromium/components/performance_manager/public/graph/node_attached_data.h +++ b/chromium/components/performance_manager/public/graph/node_attached_data.h @@ -7,7 +7,7 @@ #include <memory> -#include "base/logging.h" +#include "base/check_op.h" #include "base/macros.h" namespace performance_manager { diff --git a/chromium/components/performance_manager/public/graph/page_node.h b/chromium/components/performance_manager/public/graph/page_node.h index d02c6ed6b8b..422c043ff72 100644 --- a/chromium/components/performance_manager/public/graph/page_node.h +++ b/chromium/components/performance_manager/public/graph/page_node.h @@ -5,6 +5,7 @@ #ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_PAGE_NODE_H_ #define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_PAGE_NODE_H_ +#include <ostream> #include <string> #include "base/containers/flat_set.h" @@ -33,12 +34,36 @@ class PageNode : public Node { using Observer = PageNodeObserver; class ObserverDefaultImpl; + // Reasons for which a frame can become the opener of a page. + enum class OpenedType { + // Returned if this node doesn't have an opener. + kInvalid, + // This page is a popup (the opener created it via window.open). + kPopup, + // This page is a guest view. This can be many things (<webview>, <appview>, + // etc) but is backed by the same inner/outer WebContents mechanism. + kGuestView, + // This page is a portal. + kPortal, + }; + + // Returns a string for a PageNode::OpenedType enumeration. + static const char* ToString(PageNode::OpenedType opened_type); + PageNode(); ~PageNode() override; // Returns the unique ID of the browser context that this page belongs to. virtual const std::string& GetBrowserContextID() const = 0; + // Returns the opener frame node, if there is one. This may change over the + // lifetime of this page. See "OnOpenerFrameNodeChanged". + virtual const FrameNode* GetOpenerFrameNode() const = 0; + + // Returns the type of relationship this node has with its opener, if it has + // an opener. + virtual OpenedType GetOpenedType() const = 0; + // Returns true if this page is currently visible, false otherwise. // See PageNodeObserver::OnIsVisibleChanged. virtual bool IsVisible() const = 0; @@ -132,6 +157,8 @@ class PageNode : public Node { // implement the entire interface. class PageNodeObserver { public: + using OpenedType = PageNode::OpenedType; + PageNodeObserver(); virtual ~PageNodeObserver(); @@ -145,6 +172,14 @@ class PageNodeObserver { // Notifications of property changes. + // Invoked when this page has been assigned an opener, had the opener change, + // or had the opener removed. This can happen if a page is opened via + // window.open, webviews, portals, etc, or when that relationship is + // subsequently severed or reparented. + virtual void OnOpenerFrameNodeChanged(const PageNode* page_node, + const FrameNode* previous_opener, + OpenedType previous_opened_type) = 0; + // Invoked when the IsVisible property changes. virtual void OnIsVisibleChanged(const PageNode* page_node) = 0; @@ -207,6 +242,9 @@ class PageNode::ObserverDefaultImpl : public PageNodeObserver { // PageNodeObserver implementation: void OnPageNodeAdded(const PageNode* page_node) override {} void OnBeforePageNodeRemoved(const PageNode* page_node) override {} + void OnOpenerFrameNodeChanged(const PageNode* page_node, + const FrameNode* previous_opener, + OpenedType previous_opened_type) override {} void OnIsVisibleChanged(const PageNode* page_node) override {} void OnIsAudibleChanged(const PageNode* page_node) override {} void OnIsLoadingChanged(const PageNode* page_node) override {} @@ -229,4 +267,8 @@ class PageNode::ObserverDefaultImpl : public PageNodeObserver { } // namespace performance_manager +// std::ostream support for PageNode::OpenedType. +std::ostream& operator<<(std::ostream& os, + performance_manager::PageNode::OpenedType opened_type); + #endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_PAGE_NODE_H_ diff --git a/chromium/components/performance_manager/public/graph/policies/tab_loading_frame_navigation_policy.h b/chromium/components/performance_manager/public/graph/policies/tab_loading_frame_navigation_policy.h index d49831a404c..5c37649835c 100644 --- a/chromium/components/performance_manager/public/graph/policies/tab_loading_frame_navigation_policy.h +++ b/chromium/components/performance_manager/public/graph/policies/tab_loading_frame_navigation_policy.h @@ -39,10 +39,11 @@ namespace policies { // - Main frames are never throttled. // - Child frames with the same eTLD+1 as the main frame are not throttled. // - All other frames are throttled. -// - Throttling continues until the main frame hits hits LargestContentfulPaint. +// - Throttling continues until the main frame hits LargestContentfulPaint. // Unfortunately, we can't know LCP in real time, so we use -// 2 x FirstContentfulPaint as an estimate, with an upper bound of the UMA -// measures 95th %ile of LCP. +// 3 x FirstContentfulPaint as an estimate, with an upper bound of +// the UMA measures 95th %ile of LCP (both the multiple and the upper bound +// are configurable via Finch). // // See design document: // @@ -73,11 +74,16 @@ class TabLoadingFrameNavigationPolicy // Exposed for testing. Only safe to call on the PM thread. size_t GetThrottledPageCountForTesting() const { return timeouts_.size(); } bool IsTimerRunningForTesting() const { return timeout_timer_.IsRunning(); } + base::TimeTicks GetPageTimeoutForTesting(const PageNode* page_node) const; - // Exposed for testing. Can be called on any sequence, as this is initialized - // at construction and stays constant afterwards. + // Exposed for testing. Can be called on any sequence, as these are + // initialized at construction and stays constant afterwards. base::TimeDelta GetMinTimeoutForTesting() const { return timeout_min_; } base::TimeDelta GetMaxTimeoutForTesting() const { return timeout_max_; } + double GetFCPMultipleForTesting() const { return fcp_multiple_; } + base::TimeDelta CalculateTimeoutFromFCPForTesting(base::TimeDelta fcp) const { + return CalculateTimeoutFromFCP(fcp); + } // Exposed for testing. Allows setting a MechanismDelegate. This should be // done immediately after construction and *before* passing to the PM graph. @@ -91,7 +97,16 @@ class TabLoadingFrameNavigationPolicy mechanism_ = mechanism; } + // Exposed for testing. Can only be called on PM sequence. + void OnFirstContentfulPaintForTesting( + const FrameNode* frame_node, + base::TimeDelta time_since_navigation_start) { + OnFirstContentfulPaint(frame_node, time_since_navigation_start); + } + private: + base::TimeDelta CalculateTimeoutFromFCP(base::TimeDelta fcp) const; + // PageNodeObserver: void OnBeforePageNodeRemoved(const PageNode* page_node) override; @@ -161,6 +176,10 @@ class TabLoadingFrameNavigationPolicy base::TimeDelta timeout_min_; base::TimeDelta timeout_max_; + // The multiple applied to FCP to calculate the throttle timeout. + // Configured via Finch. See features.cc. + double fcp_multiple_; + // A one shot timer that is used to timeout existing throttles. This will be // running whenever |timeouts_| is not empty. base::OneShotTimer timeout_timer_; diff --git a/chromium/components/performance_manager/public/mechanisms/tab_loading_frame_navigation_scheduler.h b/chromium/components/performance_manager/public/mechanisms/tab_loading_frame_navigation_scheduler.h index 520031b0d34..fb6e8671706 100644 --- a/chromium/components/performance_manager/public/mechanisms/tab_loading_frame_navigation_scheduler.h +++ b/chromium/components/performance_manager/public/mechanisms/tab_loading_frame_navigation_scheduler.h @@ -64,6 +64,7 @@ class TabLoadingFrameNavigationScheduler static bool IsMechanismRegisteredForTesting(); void StopThrottlingForTesting() { StopThrottlingImpl(); } size_t GetThrottleCountForTesting() const { return throttles_.size(); } + int64_t GetNavigationIdForTesting() const { return navigation_id_; } private: friend class content::WebContentsUserData<TabLoadingFrameNavigationScheduler>; diff --git a/chromium/components/performance_manager/public/performance_manager.h b/chromium/components/performance_manager/public/performance_manager.h index 4616099f63c..0ea87f8c671 100644 --- a/chromium/components/performance_manager/public/performance_manager.h +++ b/chromium/components/performance_manager/public/performance_manager.h @@ -9,7 +9,9 @@ #include "base/callback.h" #include "base/location.h" +#include "base/memory/ptr_util.h" #include "base/memory/weak_ptr.h" +#include "base/sequenced_task_runner.h" namespace content { class RenderFrameHost; @@ -24,6 +26,11 @@ class GraphOwned; class PageNode; class PerformanceManagerMainThreadMechanism; class PerformanceManagerMainThreadObserver; +class PerformanceManagerOwned; +class PerformanceManagerRegistered; + +template <typename DerivedType> +class PerformanceManagerRegisteredImpl; // The performance manager is a rendezvous point for communicating with the // performance manager graph on its dedicated sequence. @@ -31,6 +38,9 @@ class PerformanceManager { public: virtual ~PerformanceManager(); + PerformanceManager(const PerformanceManager&) = delete; + PerformanceManager& operator=(const PerformanceManager&) = delete; + // Returns true if the performance manager is initialized. Valid to call from // the main thread only. static bool IsAvailable(); @@ -84,11 +94,64 @@ class PerformanceManager { static void RemoveMechanism(PerformanceManagerMainThreadMechanism* mechanism); static bool HasMechanism(PerformanceManagerMainThreadMechanism* mechanism); + // For convenience, allows you to pass ownership of an object that lives on + // the main thread to the performance manager. Useful for attaching observers + // or mechanisms that will live with the PM until it dies. If you can name the + // object you can also take it back via "TakeFromPM". The objects will be + // torn down gracefully (and their "OnTakenFromPM" functions invoked) as the + // PM itself is torn down. + static void PassToPM(std::unique_ptr<PerformanceManagerOwned> pm_owned); + static std::unique_ptr<PerformanceManagerOwned> TakeFromPM( + PerformanceManagerOwned* pm_owned); + + // A TakeFromPM helper for taking back the ownership of a + // PerformanceManagerOwned object via its DerivedType. + template <typename DerivedType> + static std::unique_ptr<DerivedType> TakeFromPMAs(DerivedType* pm_owned) { + return base::WrapUnique( + static_cast<DerivedType*>(TakeFromPM(pm_owned).release())); + } + + // Registers an object with the PM. It is expected that no more than one + // object of a given type is registered at a given moment, and that all + // registered objects are unregistered before PM tear-down. This allows the + // PM to act as a rendez-vous point for objects that live on the main thread. + // Combined with PerformanceManagerOwned this offers an alternative to + // using singletons, and brings clear ownerships and lifetime semantics. + static void RegisterObject(PerformanceManagerRegistered* pm_object); + + // Unregisters the provided |object|, which must previously have been + // registered with "RegisterObject". It is expected that all registered + // objects are unregistered before graph tear-down. + static void UnregisterObject(PerformanceManagerRegistered* object); + + // Returns the registered object of the given type, nullptr if none has been + // registered. + template <typename DerivedType> + static DerivedType* GetRegisteredObjectAs() { + // Be sure to access the TypeId provided by PerformanceManagerRegisteredImpl + // in case this class has other TypeId implementations. + PerformanceManagerRegistered* object = GetRegisteredObject( + PerformanceManagerRegisteredImpl<DerivedType>::TypeId()); + return static_cast<DerivedType*>(object); + } + + // Returns the performance manager graph task runner. This is safe to call + // from any thread at any time between the creation of the thread pool and its + // destruction. + // + // NOTE: Tasks posted to this sequence from any thread but the UI thread, or + // on the UI thread after IsAvailable() returns false, cannot safely access + // the graph, graphowned objects or other performance manager related objects. + // In practice it's preferable to use CallOnGraph() whenever possible. + static scoped_refptr<base::SequencedTaskRunner> GetTaskRunner(); + protected: PerformanceManager(); - private: - DISALLOW_COPY_AND_ASSIGN(PerformanceManager); + // Retrieves the object with the given |type_id|, returning nullptr if none + // exists. Clients must use the GetRegisteredObjectAs wrapper instead. + static PerformanceManagerRegistered* GetRegisteredObject(uintptr_t type_id); }; } // namespace performance_manager diff --git a/chromium/components/performance_manager/public/performance_manager_main_thread_observer.h b/chromium/components/performance_manager/public/performance_manager_main_thread_observer.h index 6ec1c58a981..d0f85a7bd92 100644 --- a/chromium/components/performance_manager/public/performance_manager_main_thread_observer.h +++ b/chromium/components/performance_manager/public/performance_manager_main_thread_observer.h @@ -26,10 +26,28 @@ class PerformanceManagerMainThreadObserver : public base::CheckedObserver { virtual void OnPageNodeCreatedForWebContents( content::WebContents* web_contents) = 0; + // Invoked before the PM is torn down on the main thread. + virtual void OnBeforePerformanceManagerDestroyed() = 0; + protected: PerformanceManagerMainThreadObserver() = default; }; +// A default implementation of the observer, with all methods stubbed out. +class PerformanceManagerMainThreadObserverDefaultImpl + : public PerformanceManagerMainThreadObserver { + public: + ~PerformanceManagerMainThreadObserverDefaultImpl() override = default; + + // PerformanceManagerMainThreadObserver implementation: + void OnPageNodeCreatedForWebContents( + content::WebContents* web_contents) override {} + void OnBeforePerformanceManagerDestroyed() override {} + + protected: + PerformanceManagerMainThreadObserverDefaultImpl() = default; +}; + } // namespace performance_manager #endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_PERFORMANCE_MANAGER_MAIN_THREAD_OBSERVER_H_ diff --git a/chromium/components/performance_manager/public/performance_manager_owned.h b/chromium/components/performance_manager/public/performance_manager_owned.h new file mode 100644 index 00000000000..f33e8d9a56b --- /dev/null +++ b/chromium/components/performance_manager/public/performance_manager_owned.h @@ -0,0 +1,51 @@ +// Copyright 2020 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_PUBLIC_PERFORMANCE_MANAGER_OWNED_H_ +#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_PERFORMANCE_MANAGER_OWNED_H_ + +namespace performance_manager { + +// Helper class for passing ownership of objects to the PerformanceManager. +// The object is expected to live on the main thread. +class PerformanceManagerOwned { + public: + virtual ~PerformanceManagerOwned() = default; + + PerformanceManagerOwned(const PerformanceManagerOwned&) = delete; + PerformanceManagerOwned& operator=(const PerformanceManagerOwned&) = delete; + + // Called when the object is passed into the PerformanceManager. + virtual void OnPassedToPM() = 0; + + // Called when the object is removed from the PerformanceManager, either via + // an explicit call to TakeFromPM, or prior to the PerformanceManager being + // destroyed. + virtual void OnTakenFromPM() = 0; + + protected: + PerformanceManagerOwned() = default; +}; + +// A default implementation of PerformanceManagerOwned. +class PerformanceManagerOwnedDefaultImpl : public PerformanceManagerOwned { + public: + ~PerformanceManagerOwnedDefaultImpl() override = default; + + PerformanceManagerOwnedDefaultImpl( + const PerformanceManagerOwnedDefaultImpl&) = delete; + PerformanceManagerOwnedDefaultImpl& operator=( + const PerformanceManagerOwnedDefaultImpl*) = delete; + + // PerformanceManagerOwned implementation: + void OnPassedToPM() override {} + void OnTakenFromPM() override {} + + protected: + PerformanceManagerOwnedDefaultImpl() = default; +}; + +} // namespace performance_manager + +#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_PERFORMANCE_MANAGER_OWNED_H_ diff --git a/chromium/components/performance_manager/public/performance_manager_registered.h b/chromium/components/performance_manager/public/performance_manager_registered.h new file mode 100644 index 00000000000..df64ec21c25 --- /dev/null +++ b/chromium/components/performance_manager/public/performance_manager_registered.h @@ -0,0 +1,83 @@ +// Copyright 2020 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_PUBLIC_PERFORMANCE_MANAGER_REGISTERED_H_ +#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_PERFORMANCE_MANAGER_REGISTERED_H_ + +#include "components/performance_manager/public/performance_manager.h" + +namespace performance_manager { + +// This provides functionality that allows an instance of a PM-associated +// object to be looked up by type, allowing the PM to act as a rendezvous +// point for main thread objects. It enforces singleton semantics, so there may +// be no more than one instance of an object of a given type registered with the +// PM at the same time. All registration and unregistration must happen on the +// main thread. It is illegal to register more than one object of the same class +// at a time, and all registered objects must be unregistered prior to PM tear- +// down. + +template <typename SelfType> +class PerformanceManagerRegisteredImpl; + +// Interface that PerformanceManager registered objects must implement. Should +// only be implemented via PerformanceManagerRegisteredImpl. +class PerformanceManagerRegistered { + public: + PerformanceManagerRegistered(const PerformanceManagerRegistered&) = delete; + PerformanceManagerRegistered& operator=(const PerformanceManagerRegistered&) = + delete; + virtual ~PerformanceManagerRegistered() = default; + + // Returns the unique type of the object. Implemented by + // PerformanceManagerRegisteredImpl. + virtual uintptr_t GetTypeId() const = 0; + + protected: + template <typename SelfType> + friend class PerformanceManagerRegisteredImpl; + + PerformanceManagerRegistered() = default; +}; + +// Fully implements PerformanceManagerRegistered. Clients should derive from +// this class. +template <typename SelfType> +class PerformanceManagerRegisteredImpl : public PerformanceManagerRegistered { + public: + PerformanceManagerRegisteredImpl() = default; + ~PerformanceManagerRegisteredImpl() override = default; + + // The static TypeId associated with this class. + static uintptr_t TypeId() { + // The pointer to this object acts as a unique key that identifies the type + // at runtime. Note that the address of this should be taken only from a + // single library, as a different address will be returned from each library + // into which a given data type is linked. Note that if base/type_id ever + // becomes a thing, this should use that! + static constexpr int kTypeId = 0; + return reinterpret_cast<uintptr_t>(&kTypeId); + } + + // PerformanceManagerRegistered implementation: + uintptr_t GetTypeId() const override { return TypeId(); } + + // Helper function for looking up the registered object of this type from the + // PM. Syntactic sugar for "PerformanceManager::GetRegisteredObjectAs". + static SelfType* GetFromPM() { + return PerformanceManager::GetRegisteredObjectAs<SelfType>(); + } + + // Returns true if this object is the registered object in the PM, false + // otherwise. Useful for DCHECKing contract conditions. + bool IsRegisteredInPM() const { return GetFromPM() == this; } + + // Returns true if no object of this type is registered in the PM, false + // otherwise. Useful for DCHECKing contract conditions. + static bool NothingRegisteredInPM() { return GetFromPM() == nullptr; } +}; + +} // namespace performance_manager + +#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_PERFORMANCE_MANAGER_REGISTERED_H_
\ No newline at end of file diff --git a/chromium/components/performance_manager/public/web_contents_proxy.h b/chromium/components/performance_manager/public/web_contents_proxy.h index 45cf541a6fd..80bc2738a25 100644 --- a/chromium/components/performance_manager/public/web_contents_proxy.h +++ b/chromium/components/performance_manager/public/web_contents_proxy.h @@ -42,6 +42,12 @@ class WebContentsProxy { // on the UI thread. int64_t LastNavigationId() const; + // Similar to the above, but for the last non same-document navigation + // associated with this WebContents. This is always for a navigation that is + // older or equal to "LastNavigationId". This must only be called on the UI + // thread. + int64_t LastNewDocNavigationId() const; + protected: friend class PerformanceManagerTabHelper; |