Commit e2602980 authored by Patrick Monette's avatar Patrick Monette Committed by Chromium LUCI CQ

Add ProcessMonitorObserver

This interface will allow other components to receive the process
metrics gathered by ProcessMonitor.

Bug: 1166820
Change-Id: Ie65de109bb2e596dcd3a9ba343b8f34138041ee8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2631245
Commit-Queue: Patrick Monette <pmonette@chromium.org>
Reviewed-by: default avatarSébastien Marchand <sebmarchand@chromium.org>
Cr-Commit-Position: refs/heads/master@{#845402}
parent 29aa67b6
......@@ -1119,6 +1119,8 @@ static_library("browser") {
"performance_monitor/chrome_browser_main_extra_parts_performance_monitor.h",
"performance_monitor/process_metrics_history.cc",
"performance_monitor/process_metrics_history.h",
"performance_monitor/process_metrics_recorder.cc",
"performance_monitor/process_metrics_recorder.h",
"performance_monitor/process_monitor.cc",
"performance_monitor/process_monitor.h",
"performance_monitor/system_monitor.cc",
......
......@@ -4,6 +4,7 @@
#include "chrome/browser/performance_monitor/chrome_browser_main_extra_parts_performance_monitor.h"
#include "chrome/browser/performance_monitor/process_metrics_recorder.h"
#include "chrome/browser/performance_monitor/process_monitor.h"
#include "chrome/browser/performance_monitor/system_monitor.h"
......@@ -15,6 +16,10 @@ ChromeBrowserMainExtraPartsPerformanceMonitor::
void ChromeBrowserMainExtraPartsPerformanceMonitor::PreMainMessageLoopStart() {
process_monitor_ = performance_monitor::ProcessMonitor::Create();
process_metrics_recorder_ =
std::make_unique<performance_monitor::ProcessMetricsRecorder>();
process_monitor_->AddObserver(process_metrics_recorder_.get());
}
void ChromeBrowserMainExtraPartsPerformanceMonitor::PostMainMessageLoopStart() {
......
......@@ -10,6 +10,7 @@
#include "chrome/browser/chrome_browser_main_extra_parts.h"
namespace performance_monitor {
class ProcessMetricsRecorder;
class ProcessMonitor;
class SystemMonitor;
} // namespace performance_monitor
......@@ -30,11 +31,17 @@ class ChromeBrowserMainExtraPartsPerformanceMonitor
void PostMainMessageLoopStart() override;
private:
// The process monitor instance. Collects metrics about every child processes.
std::unique_ptr<performance_monitor::ProcessMonitor> process_monitor_;
// The system monitor instance, used by some subsystems to collect the system
// metrics they need.
std::unique_ptr<performance_monitor::SystemMonitor> system_monitor_;
// Observes the |process_monitor_| and record histograms from the metrics
// received.
std::unique_ptr<performance_monitor::ProcessMetricsRecorder>
process_metrics_recorder_;
};
#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_CHROME_BROWSER_MAIN_EXTRA_PARTS_PERFORMANCE_MONITOR_H_
......@@ -7,9 +7,7 @@
#include <limits>
#include "base/check_op.h"
#include "base/metrics/histogram_macros.h"
#include "base/process/process_metrics.h"
#include "content/public/common/process_type.h"
#if defined(OS_MAC)
#include "content/public/browser/browser_child_process_host.h"
......@@ -17,17 +15,12 @@
namespace performance_monitor {
// If a process is consistently above this CPU utilization percentage over time,
// we consider it as high and may take action.
const float kHighCPUUtilizationThreshold = 90.0f;
ProcessMetricsHistory::ProcessMetricsHistory() = default;
ProcessMetricsHistory::~ProcessMetricsHistory() = default;
void ProcessMetricsHistory::Initialize(
const ProcessMetricsMetadata& process_data,
int initial_update_sequence) {
void ProcessMetricsHistory::Initialize(const ProcessMetadata& process_data,
int initial_update_sequence) {
DCHECK_EQ(base::kNullProcessHandle, process_data_.handle);
process_data_ = process_data;
last_update_sequence_ = initial_update_sequence;
......@@ -42,156 +35,24 @@ void ProcessMetricsHistory::Initialize(
#endif
}
void ProcessMetricsHistory::SampleMetrics() {
cpu_usage_ = process_metrics_->GetPlatformIndependentCPUUsage();
#if defined(OS_WIN)
disk_usage_ = process_metrics_->GetDiskUsageBytesPerSecond();
#endif
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_AIX)
idle_wakeups_ = process_metrics_->GetIdleWakeupsPerSecond();
#endif
#if defined(OS_MAC)
package_idle_wakeups_ = process_metrics_->GetPackageIdleWakeupsPerSecond();
energy_impact_ = process_metrics_->GetEnergyImpact();
#endif
UpdateHistograms();
}
void ProcessMetricsHistory::UpdateHistograms() {
// We scale up to the equivalent of 64 CPU cores fully loaded. More than this
// doesn't really matter, as we're already in a terrible place.
const int kHistogramMin = 1;
const int kHistogramMax = 6400;
const int kHistogramBucketCount = 50;
ProcessMonitor::Metrics ProcessMetricsHistory::SampleMetrics() {
ProcessMonitor::Metrics metrics;
metrics.cpu_usage = process_metrics_->GetPlatformIndependentCPUUsage();
#if defined(OS_WIN)
const int kDiskUsageHistogramMin = 1;
const int kDiskUsageHistogramMax = 200 * 1024 * 1024; // 200 M/sec.
const int kDiskUsageHistogramBucketCount = 50;
#endif
// The histogram macros don't support variables as histogram names,
// hence the macro duplication for each process type.
switch (process_data_.process_type) {
case content::PROCESS_TYPE_BROWSER:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.BrowserProcess", cpu_usage_,
kHistogramMin, kHistogramMax, kHistogramBucketCount);
// If CPU usage has consistently been above our threshold,
// we *may* have an issue.
if (cpu_usage_ > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.BrowserProcess",
true);
}
#if defined(OS_WIN)
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageDisk.BrowserProcess", disk_usage_,
kDiskUsageHistogramMin, kDiskUsageHistogramMax,
kDiskUsageHistogramBucketCount);
metrics.disk_usage = process_metrics_->GetDiskUsageBytesPerSecond();
#endif
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_AIX)
UMA_HISTOGRAM_COUNTS_10000(
"PerformanceMonitor.IdleWakeups.BrowserProcess", idle_wakeups_);
metrics.idle_wakeups = process_metrics_->GetIdleWakeupsPerSecond();
#endif
#if defined(OS_MAC)
UMA_HISTOGRAM_COUNTS_1000(
"PerformanceMonitor.PackageExitIdleWakeups.BrowserProcess",
package_idle_wakeups_);
UMA_HISTOGRAM_COUNTS_100000(
"PerformanceMonitor.EnergyImpact.BrowserProcess", energy_impact_);
metrics.package_idle_wakeups =
process_metrics_->GetPackageIdleWakeupsPerSecond();
metrics.energy_impact = process_metrics_->GetEnergyImpact();
#endif
break;
case content::PROCESS_TYPE_RENDERER:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.RendererProcess", cpu_usage_,
kHistogramMin, kHistogramMax, kHistogramBucketCount);
if (cpu_usage_ > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.RendererProcess",
true);
}
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_AIX)
UMA_HISTOGRAM_COUNTS_10000(
"PerformanceMonitor.IdleWakeups.RendererProcess", idle_wakeups_);
#endif
#if defined(OS_MAC)
UMA_HISTOGRAM_COUNTS_1000(
"PerformanceMonitor.PackageExitIdleWakeups.RendererProcess",
package_idle_wakeups_);
UMA_HISTOGRAM_COUNTS_100000(
"PerformanceMonitor.EnergyImpact.RendererProcess", energy_impact_);
#endif
break;
case content::PROCESS_TYPE_GPU:
UMA_HISTOGRAM_CUSTOM_COUNTS("PerformanceMonitor.AverageCPU.GPUProcess",
cpu_usage_, kHistogramMin, kHistogramMax,
kHistogramBucketCount);
if (cpu_usage_ > kHighCPUUtilizationThreshold)
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.GPUProcess", true);
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_AIX)
UMA_HISTOGRAM_COUNTS_10000("PerformanceMonitor.IdleWakeups.GPUProcess",
idle_wakeups_);
#endif
#if defined(OS_MAC)
UMA_HISTOGRAM_COUNTS_1000(
"PerformanceMonitor.PackageExitIdleWakeups.GPUProcess",
package_idle_wakeups_);
UMA_HISTOGRAM_COUNTS_100000("PerformanceMonitor.EnergyImpact.GPUProcess",
energy_impact_);
#endif
break;
case content::PROCESS_TYPE_PPAPI_PLUGIN:
UMA_HISTOGRAM_CUSTOM_COUNTS("PerformanceMonitor.AverageCPU.PPAPIProcess",
cpu_usage_, kHistogramMin, kHistogramMax,
kHistogramBucketCount);
if (cpu_usage_ > kHighCPUUtilizationThreshold)
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.PPAPIProcess", true);
break;
default:
break;
}
switch (process_data_.process_subtype) {
case kProcessSubtypeUnknown:
break;
case kProcessSubtypePPAPIFlash:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.PPAPIFlashProcess", cpu_usage_,
kHistogramMin, kHistogramMax, kHistogramBucketCount);
if (cpu_usage_ > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.PPAPIFlashProcess",
true);
}
break;
case kProcessSubtypeExtensionPersistent:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.RendererExtensionPersistentProcess",
cpu_usage_, kHistogramMin, kHistogramMax, kHistogramBucketCount);
if (cpu_usage_ > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN(
"PerformanceMonitor.HighCPU.RendererExtensionPersistentProcess",
true);
}
break;
case kProcessSubtypeExtensionEvent:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.RendererExtensionEventProcess",
cpu_usage_, kHistogramMin, kHistogramMax, kHistogramBucketCount);
if (cpu_usage_ > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN(
"PerformanceMonitor.HighCPU.RendererExtensionEventProcess", true);
}
break;
}
return metrics;
}
} // namespace performance_monitor
......@@ -7,47 +7,29 @@
#include <memory>
#include "base/macros.h"
#include "base/process/process_handle.h"
#include "build/build_config.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/common/process_type.h"
#include "chrome/browser/performance_monitor/process_monitor.h"
namespace base {
class ProcessMetrics;
}
namespace performance_monitor {
enum ProcessSubtypes {
kProcessSubtypeUnknown,
kProcessSubtypePPAPIFlash,
kProcessSubtypeExtensionPersistent,
kProcessSubtypeExtensionEvent
};
struct ProcessMetricsMetadata {
base::ProcessHandle handle;
int process_type;
ProcessSubtypes process_subtype;
ProcessMetricsMetadata()
: handle(base::kNullProcessHandle),
process_type(content::PROCESS_TYPE_UNKNOWN),
process_subtype(kProcessSubtypeUnknown) {}
};
class ProcessMetricsHistory {
public:
ProcessMetricsHistory();
ProcessMetricsHistory(const ProcessMetricsHistory& other) = delete;
ProcessMetricsHistory& operator=(const ProcessMetricsHistory& other) = delete;
~ProcessMetricsHistory();
// Configure this to monitor a specific process.
void Initialize(const ProcessMetricsMetadata& process_data,
void Initialize(const ProcessMetadata& process_data,
int initial_update_sequence);
// Gather metrics for the process and accumulate with past data.
void SampleMetrics();
ProcessMonitor::Metrics SampleMetrics();
// Used to mark when this object was last updated, so we can cull
// dead ones.
......@@ -55,32 +37,14 @@ class ProcessMetricsHistory {
last_update_sequence_ = new_update_sequence;
}
const ProcessMetadata& metadata() const { return process_data_; }
int last_update_sequence() const { return last_update_sequence_; }
private:
void UpdateHistograms();
// May not be fully populated. e.g. no |id| and no |name| for browser and
// renderer processes.
ProcessMetricsMetadata process_data_;
ProcessMetadata process_data_;
std::unique_ptr<base::ProcessMetrics> process_metrics_;
int last_update_sequence_ = 0;
double cpu_usage_ = 0.0;
#if defined(OS_WIN)
uint64_t disk_usage_ = 0;
#endif
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_AIX)
int idle_wakeups_ = 0;
#endif
#if defined(OS_MAC)
int package_idle_wakeups_ = 0;
double energy_impact_ = 0.0;
#endif
DISALLOW_ASSIGN(ProcessMetricsHistory);
};
} // namespace performance_monitor
......
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/performance_monitor/process_metrics_recorder.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
namespace performance_monitor {
namespace {
// If a process is consistently above this CPU utilization percentage over time,
// we consider it as high and may take action.
const float kHighCPUUtilizationThreshold = 90.0f;
} // namespace
ProcessMetricsRecorder::ProcessMetricsRecorder() = default;
ProcessMetricsRecorder::~ProcessMetricsRecorder() = default;
void ProcessMetricsRecorder::OnMetricsSampled(
const ProcessMetadata& process_metadata,
const ProcessMonitor::Metrics& metrics) {
// We scale up to the equivalent of 64 CPU cores fully loaded. More than this
// doesn't really matter, as we're already in a terrible place.
const int kHistogramMin = 1;
const int kHistogramMax = 6400;
const int kHistogramBucketCount = 50;
#if defined(OS_WIN)
const int kDiskUsageHistogramMin = 1;
const int kDiskUsageHistogramMax = 200 * 1024 * 1024; // 200 M/sec.
const int kDiskUsageHistogramBucketCount = 50;
#endif
// The histogram macros don't support variables as histogram names,
// hence the macro duplication for each process type.
switch (process_metadata.process_type) {
case content::PROCESS_TYPE_BROWSER:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.BrowserProcess", metrics.cpu_usage,
kHistogramMin, kHistogramMax, kHistogramBucketCount);
// If CPU usage has consistently been above our threshold,
// we *may* have an issue.
if (metrics.cpu_usage > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.BrowserProcess",
true);
}
#if defined(OS_WIN)
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageDisk.BrowserProcess", metrics.disk_usage,
kDiskUsageHistogramMin, kDiskUsageHistogramMax,
kDiskUsageHistogramBucketCount);
#endif
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_AIX)
UMA_HISTOGRAM_COUNTS_10000(
"PerformanceMonitor.IdleWakeups.BrowserProcess",
metrics.idle_wakeups);
#endif
#if defined(OS_MAC)
UMA_HISTOGRAM_COUNTS_1000(
"PerformanceMonitor.PackageExitIdleWakeups.BrowserProcess",
metrics.package_idle_wakeups);
UMA_HISTOGRAM_COUNTS_100000(
"PerformanceMonitor.EnergyImpact.BrowserProcess",
metrics.energy_impact);
#endif
break;
case content::PROCESS_TYPE_RENDERER:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.RendererProcess", metrics.cpu_usage,
kHistogramMin, kHistogramMax, kHistogramBucketCount);
if (metrics.cpu_usage > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.RendererProcess",
true);
}
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_AIX)
UMA_HISTOGRAM_COUNTS_10000(
"PerformanceMonitor.IdleWakeups.RendererProcess",
metrics.idle_wakeups);
#endif
#if defined(OS_MAC)
UMA_HISTOGRAM_COUNTS_1000(
"PerformanceMonitor.PackageExitIdleWakeups.RendererProcess",
metrics.package_idle_wakeups);
UMA_HISTOGRAM_COUNTS_100000(
"PerformanceMonitor.EnergyImpact.RendererProcess",
metrics.energy_impact);
#endif
break;
case content::PROCESS_TYPE_GPU:
UMA_HISTOGRAM_CUSTOM_COUNTS("PerformanceMonitor.AverageCPU.GPUProcess",
metrics.cpu_usage, kHistogramMin,
kHistogramMax, kHistogramBucketCount);
if (metrics.cpu_usage > kHighCPUUtilizationThreshold)
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.GPUProcess", true);
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_AIX)
UMA_HISTOGRAM_COUNTS_10000("PerformanceMonitor.IdleWakeups.GPUProcess",
metrics.idle_wakeups);
#endif
#if defined(OS_MAC)
UMA_HISTOGRAM_COUNTS_1000(
"PerformanceMonitor.PackageExitIdleWakeups.GPUProcess",
metrics.package_idle_wakeups);
UMA_HISTOGRAM_COUNTS_100000("PerformanceMonitor.EnergyImpact.GPUProcess",
metrics.energy_impact);
#endif
break;
case content::PROCESS_TYPE_PPAPI_PLUGIN:
UMA_HISTOGRAM_CUSTOM_COUNTS("PerformanceMonitor.AverageCPU.PPAPIProcess",
metrics.cpu_usage, kHistogramMin,
kHistogramMax, kHistogramBucketCount);
if (metrics.cpu_usage > kHighCPUUtilizationThreshold)
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.PPAPIProcess", true);
break;
default:
break;
}
switch (process_metadata.process_subtype) {
case kProcessSubtypeUnknown:
break;
case kProcessSubtypePPAPIFlash:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.PPAPIFlashProcess", metrics.cpu_usage,
kHistogramMin, kHistogramMax, kHistogramBucketCount);
if (metrics.cpu_usage > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.PPAPIFlashProcess",
true);
}
break;
case kProcessSubtypeExtensionPersistent:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.RendererExtensionPersistentProcess",
metrics.cpu_usage, kHistogramMin, kHistogramMax,
kHistogramBucketCount);
if (metrics.cpu_usage > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN(
"PerformanceMonitor.HighCPU.RendererExtensionPersistentProcess",
true);
}
break;
case kProcessSubtypeExtensionEvent:
UMA_HISTOGRAM_CUSTOM_COUNTS(
"PerformanceMonitor.AverageCPU.RendererExtensionEventProcess",
metrics.cpu_usage, kHistogramMin, kHistogramMax,
kHistogramBucketCount);
if (metrics.cpu_usage > kHighCPUUtilizationThreshold) {
UMA_HISTOGRAM_BOOLEAN(
"PerformanceMonitor.HighCPU.RendererExtensionEventProcess", true);
}
break;
}
}
} // namespace performance_monitor
// Copyright 2021 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_MONITOR_PROCESS_METRICS_RECORDER_H_
#define CHROME_BROWSER_PERFORMANCE_MONITOR_PROCESS_METRICS_RECORDER_H_
#include "chrome/browser/performance_monitor/process_monitor.h"
namespace performance_monitor {
// This class receives the metrics gathered by the ProcessMonitor and records
// some performance-related histograms about the different process types.
class ProcessMetricsRecorder final : public ProcessMonitor::Observer {
public:
ProcessMetricsRecorder();
~ProcessMetricsRecorder() override;
ProcessMetricsRecorder(const ProcessMetricsRecorder&) = delete;
ProcessMetricsRecorder& operator=(const ProcessMetricsRecorder&) = delete;
// ProcessMonitorObserver:
void OnMetricsSampled(const ProcessMetadata& process_metadata,
const ProcessMonitor::Metrics& metrics) override;
};
} // namespace performance_monitor
#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_PROCESS_METRICS_RECORDER_H_
......@@ -11,6 +11,7 @@
#include "base/process/process_iterator.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chrome/browser/performance_monitor/process_metrics_history.h"
#include "content/public/browser/browser_child_process_host.h"
#include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/browser_task_traits.h"
......@@ -41,7 +42,7 @@ constexpr base::TimeDelta kGatherInterval = base::TimeDelta::FromSeconds(120);
ProcessMonitor* g_process_monitor = nullptr;
void GatherMetricsForRenderProcess(content::RenderProcessHost* host,
ProcessMetricsMetadata* data) {
ProcessMetadata* data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
#if BUILDFLAG(ENABLE_EXTENSIONS)
content::BrowserContext* browser_context = host->GetBrowserContext();
......@@ -96,14 +97,21 @@ void ProcessMonitor::StartGatherCycle() {
&ProcessMonitor::GatherMetricsMapOnUIThread);
}
void ProcessMonitor::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void ProcessMonitor::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
ProcessMonitor::ProcessMonitor() {
DCHECK(!g_process_monitor);
g_process_monitor = this;
}
void ProcessMonitor::MarkProcessAsAlive(
const ProcessMetricsMetadata& process_data,
int current_update_sequence) {
void ProcessMonitor::MarkProcessAsAlive(const ProcessMetadata& process_data,
int current_update_sequence) {
const base::ProcessHandle& handle = process_data.handle;
if (handle == base::kNullProcessHandle) {
// Process may not be valid yet.
......@@ -135,7 +143,7 @@ void ProcessMonitor::GatherMetricsMapOnUIThread() {
content::RenderProcessHost::AllHostsIterator();
!rph_iter.IsAtEnd(); rph_iter.Advance()) {
content::RenderProcessHost* host = rph_iter.GetCurrentValue();
ProcessMetricsMetadata data;
ProcessMetadata data;
data.process_type = content::PROCESS_TYPE_RENDERER;
data.handle = host->GetProcess().Handle();
......@@ -155,7 +163,7 @@ void ProcessMonitor::GatherMetricsMapOnIOThread(int current_update_sequence) {
// Find all child processes (does not include renderers), which has to be
// done on the IO thread.
for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
ProcessMetricsMetadata child_process_data;
ProcessMetadata child_process_data;
child_process_data.handle = iter.GetData().GetProcess().Handle();
child_process_data.process_type = iter.GetData().process_type;
......@@ -167,7 +175,7 @@ void ProcessMonitor::GatherMetricsMapOnIOThread(int current_update_sequence) {
}
// Add the current (browser) process.
ProcessMetricsMetadata browser_process_data;
ProcessMetadata browser_process_data;
browser_process_data.process_type = content::PROCESS_TYPE_BROWSER;
browser_process_data.handle = base::GetCurrentProcessHandle();
MarkProcessAsAlive(browser_process_data, current_update_sequence);
......@@ -180,7 +188,9 @@ void ProcessMonitor::GatherMetricsMapOnIOThread(int current_update_sequence) {
// Not touched this iteration; let's get rid of it.
metrics_map_.erase(iter++);
} else {
process_metrics->SampleMetrics();
Metrics metrics = process_metrics->SampleMetrics();
for (auto& observer : observer_list_)
observer.OnMetricsSampled(process_metrics->metadata(), metrics);
++iter;
}
}
......
......@@ -8,21 +8,73 @@
#include <map>
#include <memory>
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/process/process_handle.h"
#include "base/timer/timer.h"
#include "chrome/browser/performance_monitor/process_metrics_history.h"
#include "build/build_config.h"
#include "content/public/common/process_type.h"
namespace performance_monitor {
class ProcessMetricsHistory;
enum ProcessSubtypes {
kProcessSubtypeUnknown,
kProcessSubtypePPAPIFlash,
kProcessSubtypeExtensionPersistent,
kProcessSubtypeExtensionEvent
};
struct ProcessMetadata {
base::ProcessHandle handle = base::kNullProcessHandle;
int process_type = content::PROCESS_TYPE_UNKNOWN;
ProcessSubtypes process_subtype = kProcessSubtypeUnknown;
};
// ProcessMonitor is a tool which periodically monitors performance metrics
// of all the Chrome processes for histogram logging and possibly taking action
// upon noticing serious performance degradation.
class ProcessMonitor {
public:
struct Metrics {
// The percentage of time spent executing, across all threads of the
// process, in the interval since the last time the metric was sampled. This
// can exceed 100% in multi-thread processes running on multi-core systems.
double cpu_usage = 0.0;
#if defined(OS_WIN)
// The number of bytes transferred to/from disk per second, across all
// threads of the process, in the interval since the last time the metric
// was sampled.
uint64_t disk_usage = 0;
#endif
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_AIX)
// Returns the number of average idle cpu wakeups per second since the last
// time the metric was sampled.
int idle_wakeups = 0;
#endif
#if defined(OS_MAC)
// The number of average "package idle exits" per second since the last
// time the metric was sampled. See base/process/process_metrics.h for a
// more detailed explanation.
int package_idle_wakeups = 0;
// "Energy Impact" is a synthetic power estimation metric displayed by macOS
// in Activity Monitor and the battery menu.
double energy_impact = 0.0;
#endif
};
class Observer : public base::CheckedObserver {
public:
virtual void OnMetricsSampled(const ProcessMetadata& process_metadata,
const Metrics& metrics) = 0;
};
// Creates and returns the application-wide ProcessMonitor. Can only be called
// if no ProcessMonitor instances exists in the current process. The caller
// owns the created instance. The current process' instance can be retrieved
......@@ -38,9 +90,11 @@ class ProcessMonitor {
// Start the cycle of metrics gathering.
void StartGatherCycle();
private:
friend struct base::LazyInstanceTraitsBase<ProcessMonitor>;
// Adds/removes an observer.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
private:
using MetricsMap =
std::map<base::ProcessHandle, std::unique_ptr<ProcessMetricsHistory>>;
......@@ -49,7 +103,7 @@ class ProcessMonitor {
// Mark the given process as alive in the current update iteration.
// This means adding an entry to the map of watched processes if it's not
// already present.
void MarkProcessAsAlive(const ProcessMetricsMetadata& process_data,
void MarkProcessAsAlive(const ProcessMetadata& process_data,
int current_update_sequence);
// Updates the ProcessMetrics map with the current list of processes and
......@@ -63,6 +117,8 @@ class ProcessMonitor {
// The timer to signal ProcessMonitor to perform its timed collections.
base::RepeatingTimer repeating_timer_;
base::ObserverList<Observer> observer_list_;
DISALLOW_COPY_AND_ASSIGN(ProcessMonitor);
};
......
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