blob: 26a0436c580b99d5c0cdacd1e9f09bede2391c82 [file] [log] [blame]
// 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 CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_ISOLATION_CONTEXT_METRICS_H_
#define CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_ISOLATION_CONTEXT_METRICS_H_
#include <unordered_map>
#include "base/containers/small_map.h"
#include "base/macros.h"
#include "base/timer/timer.h"
#include "components/performance_manager/public/graph/frame_node.h"
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/process_node.h"
#include "content/public/browser/site_instance.h"
namespace performance_manager {
// A graph observer that tracks various metrics related to the isolation context
// of frames and pages:
//
// (1) How common it is for frames to be hosted in a same process that don't
// actually need to be hosted together (they are not in the same site
// instance and thus can't synchronously script each other). This is to
// inform value of work on Blink Isolates.
// (2) How common it is for pages to be in browsing instances with other pages,
// as opposed to in browsing instances on their own. This is for estimating
// the impact of extending freezing logic to entire browsing instances.
class IsolationContextMetrics : public FrameNode::ObserverDefaultImpl,
public GraphOwned,
public ProcessNode::ObserverDefaultImpl {
public:
IsolationContextMetrics();
IsolationContextMetrics(const IsolationContextMetrics&) = delete;
IsolationContextMetrics& operator=(const IsolationContextMetrics&) = delete;
~IsolationContextMetrics() override;
// Starts the timer for periodic reporting.
void StartTimer();
protected:
// Helper struct that implements storage for ProcessData.
friend struct IsolationContextMetricsProcessDataImpl;
// Periodic reporting interval. This would ideally be triggered by UMA
// collection and not on its own timer, but UMA collection lives on the UI
// thread. This wants to be something on the same order of magnitude as UMA
// collection but not so fast as to cause pointless wakeups.
static constexpr base::TimeDelta kReportingInterval = base::Minutes(5);
// This histogram records the cumulative amount of time a process spends
// hosting only frames from distinct site instances, versus hosting more than
// one frame from the same site instance. See ProcessDataState for details.
static const char kProcessDataByTimeHistogramName[];
// This histogram records the number of processes that ever only host frames
// from distinct site instances, versus those that ever host more than one
// frame from the same site instance. See ProcessDataState for details.
static const char kProcessDataByProcessHistogramName[];
// This histogram records the number of frames in a renderer over time.
static const char kFramesPerRendererByTimeHistogram[];
// This histogram records the number of site instances in a renderer over
// time.
static const char kSiteInstancesPerRendererByTimeHistogram[];
// Tracks the number of distinct site instances being hosted per process.
struct ProcessData {
ProcessData();
~ProcessData();
// Factories/accessors for node attached data.
static ProcessData* Get(const ProcessNode* process_node);
static ProcessData* GetOrCreate(const ProcessNode* process_node);
// A map between site instance ID and the number of frames with that site
// instance in the process. This is typically small for most processes, but
// can go to O(100s) for power users hence the use of small_map.
base::small_map<
std::unordered_map<content::SiteInstanceId,
int,
typename content::SiteInstanceId::Hasher>>
site_instance_frame_count;
// The number of frames in this process.
int frame_count = 0;
// The number of site instances with multiple frames in this process.
// Basically, this counts the number of entries in
// |site_instance_frame_count| that are > 1.
int multi_frame_site_instance_count = 0;
// Whether or not this process has *ever* hosted multiple frames.
bool has_hosted_multiple_frames = false;
// Whether or not this process has *ever* hosted multiple frames in the same
// site instance. This goes to true if |multi_frame_site_instance_count| is
// ever greater than 0.
bool has_hosted_multiple_frames_with_same_site_instance = false;
// The last time data related to this process was reported to the histogram.
// This happens on a timer or on state changes. This is initialized to the
// time of the struct creation.
base::TimeTicks last_reported;
};
// A state that can be calculated from a ProcessData.
enum class ProcessDataState {
kUndefined = -1, // This value is never reported, but used in logic.
kAllFramesHaveDistinctSiteInstances = 0,
kSomeFramesHaveSameSiteInstance = 1,
kOnlyOneFrameExists = 2,
// Must be maintained as the max value.
kMaxValue = kOnlyOneFrameExists
};
// FrameNodeObserver implementation:
void OnFrameNodeAdded(const FrameNode* frame_node) override;
void OnBeforeFrameNodeRemoved(const FrameNode* frame_node) override;
// GraphOwned implementation:
void OnPassedToGraph(Graph* graph) override;
void OnTakenFromGraph(Graph* graph) override;
// ProcessNodeObserver implementation:
void OnBeforeProcessNodeRemoved(const ProcessNode* process_node) override;
// (Un)registers the various node observer flavors of this object with the
// graph. These are invoked by OnPassedToGraph and OnTakenFromGraph, but
// hoisted to their own functions for testing.
void RegisterObservers(Graph* graph);
void UnregisterObservers(Graph* graph);
// Returns the state associated with a ProcessData.
static ProcessDataState GetProcessDataState(const ProcessData* process_data);
// Reports data associated with a ProcessData.
static void ReportProcessData(ProcessData* process_data,
ProcessDataState state,
base::TimeTicks now);
// Reports all process data.
void ReportAllProcessData(base::TimeTicks now);
// Adds or removes a frame from the relevant process data. The |delta| should
// be +/- 1.
void ChangeFrameCount(const FrameNode* frame_node, int delta);
// This is virtual in order to provide a testing seam.
virtual void OnReportingTimerFired();
// The graph to which this object belongs.
Graph* graph_ = nullptr;
// Timer that is used to periodically flush metrics. This ensures that they
// are mostly up to date in the event of a catastrophic browser crash. We
// could do this on the same schedule as UMA itself by being a MetricsProvider
// but that is UI thread bound, and would require all sorts of hassles for us
// to build.
// TODO(chrisha): Migrate away if metrics team provides a convenient API.
// https://crbug.com/961468
base::RepeatingTimer reporting_timer_;
};
} // namespace performance_manager
#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_ISOLATION_CONTEXT_METRICS_H_