1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_ISOLATION_CONTEXT_METRICS_H_ 6 #define CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_ISOLATION_CONTEXT_METRICS_H_ 7 8 #include <unordered_map> 9 10 #include "base/containers/small_map.h" 11 #include "base/macros.h" 12 #include "base/timer/timer.h" 13 #include "components/performance_manager/public/graph/frame_node.h" 14 #include "components/performance_manager/public/graph/graph.h" 15 #include "components/performance_manager/public/graph/process_node.h" 16 17 namespace performance_manager { 18 19 // A graph observer that tracks various metrics related to the isolation context 20 // of frames and pages: 21 // 22 // (1) How common it is for frames to be hosted in a same process that don't 23 // actually need to be hosted together (they are not in the same site 24 // instance and thus can't synchronously script each other). This is to 25 // inform value of work on Blink Isolates. 26 // (2) How common it is for pages to be in browsing instances with other pages, 27 // as opposed to in browsing instances on their own. This is for estimating 28 // the impact of extending freezing logic to entire browsing instances. 29 class IsolationContextMetrics : public FrameNode::ObserverDefaultImpl, 30 public GraphOwned, 31 public ProcessNode::ObserverDefaultImpl { 32 public: 33 IsolationContextMetrics(); 34 ~IsolationContextMetrics() override; 35 36 // Starts the timer for periodic reporting. 37 void StartTimer(); 38 39 protected: 40 // Helper struct that implements storage for ProcessData. 41 friend struct IsolationContextMetricsProcessDataImpl; 42 43 // Periodic reporting interval. This would ideally be triggered by UMA 44 // collection and not on its own timer, but UMA collection lives on the UI 45 // thread. This wants to be something on the same order of magnitude as UMA 46 // collection but not so fast as to cause pointless wakeups. 47 static constexpr base::TimeDelta kReportingInterval = 48 base::TimeDelta::FromMinutes(5); 49 50 // This histogram records the cumulative amount of time a process spends 51 // hosting only frames from distinct site instances, versus hosting more than 52 // one frame from the same site instance. See ProcessDataState for details. 53 static const char kProcessDataByTimeHistogramName[]; 54 // This histogram records the number of processes that ever only host frames 55 // from distinct site instances, versus those that ever host more than one 56 // frame from the same site instance. See ProcessDataState for details. 57 static const char kProcessDataByProcessHistogramName[]; 58 // This histogram records the number of frames in a renderer over time. 59 static const char kFramesPerRendererByTimeHistogram[]; 60 // This histogram records the number of site instances in a renderer over 61 // time. 62 static const char kSiteInstancesPerRendererByTimeHistogram[]; 63 64 // Tracks the number of distinct site instances being hosted per process. 65 struct ProcessData { 66 ProcessData(); 67 ~ProcessData(); 68 69 // Factories/accessors for node attached data. 70 static ProcessData* Get(const ProcessNode* process_node); 71 static ProcessData* GetOrCreate(const ProcessNode* process_node); 72 73 // A map between site instance ID and the number of frames with that site 74 // instance in the process. This is typically small for most processes, but 75 // can go to O(100s) for power users hence the use of small_map. 76 base::small_map<std::unordered_map<int32_t, int>> site_instance_frame_count; 77 // The number of frames in this process. 78 int frame_count = 0; 79 // The number of site instances with multiple frames in this process. 80 // Basically, this counts the number of entries in 81 // |site_instance_frame_count| that are > 1. 82 int multi_frame_site_instance_count = 0; 83 // Whether or not this process has *ever* hosted multiple frames. 84 bool has_hosted_multiple_frames = false; 85 // Whether or not this process has *ever* hosted multiple frames in the same 86 // site instance. This goes to true if |multi_frame_site_instance_count| is 87 // ever greater than 0. 88 bool has_hosted_multiple_frames_with_same_site_instance = false; 89 // The last time data related to this process was reported to the histogram. 90 // This happens on a timer or on state changes. This is initialized to the 91 // time of the struct creation. 92 base::TimeTicks last_reported; 93 }; 94 95 // A state that can be calculated from a ProcessData. 96 enum class ProcessDataState { 97 kUndefined = -1, // This value is never reported, but used in logic. 98 kAllFramesHaveDistinctSiteInstances = 0, 99 kSomeFramesHaveSameSiteInstance = 1, 100 kOnlyOneFrameExists = 2, 101 // Must be maintained as the max value. 102 kMaxValue = kOnlyOneFrameExists 103 }; 104 105 // FrameNodeObserver implementation: 106 void OnFrameNodeAdded(const FrameNode* frame_node) override; 107 void OnBeforeFrameNodeRemoved(const FrameNode* frame_node) override; 108 109 // GraphOwned implementation: 110 void OnPassedToGraph(Graph* graph) override; 111 void OnTakenFromGraph(Graph* graph) override; 112 113 // ProcessNodeObserver implementation: 114 void OnBeforeProcessNodeRemoved(const ProcessNode* process_node) override; 115 116 // (Un)registers the various node observer flavors of this object with the 117 // graph. These are invoked by OnPassedToGraph and OnTakenFromGraph, but 118 // hoisted to their own functions for testing. 119 void RegisterObservers(Graph* graph); 120 void UnregisterObservers(Graph* graph); 121 122 // Returns the state associated with a ProcessData. 123 static ProcessDataState GetProcessDataState(const ProcessData* process_data); 124 125 // Reports data associated with a ProcessData. 126 static void ReportProcessData(ProcessData* process_data, 127 ProcessDataState state, 128 base::TimeTicks now); 129 130 // Reports all process data. 131 void ReportAllProcessData(base::TimeTicks now); 132 133 // Adds or removes a frame from the relevant process data. The |delta| should 134 // be +/- 1. 135 void ChangeFrameCount(const FrameNode* frame_node, int delta); 136 137 // This is virtual in order to provide a testing seam. 138 virtual void OnReportingTimerFired(); 139 140 // The graph to which this object belongs. 141 Graph* graph_ = nullptr; 142 143 // Timer that is used to periodically flush metrics. This ensures that they 144 // are mostly up to date in the event of a catastrophic browser crash. We 145 // could do this on the same schedule as UMA itself by being a MetricsProvider 146 // but that is UI thread bound, and would require all sorts of hassles for us 147 // to build. 148 // TODO(chrisha): Migrate away if metrics team provides a convenient API. 149 // https://crbug.com/961468 150 base::RepeatingTimer reporting_timer_; 151 152 private: 153 DISALLOW_COPY_AND_ASSIGN(IsolationContextMetrics); 154 }; 155 156 } // namespace performance_manager 157 158 #endif // CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_ISOLATION_CONTEXT_METRICS_H_ 159