summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoroysteine@chromium.org <oysteine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-02 15:56:09 +0000
committeroysteine@chromium.org <oysteine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-02 15:56:09 +0000
commit56fd0a89174b70b665e6c0267a05e81beb86d510 (patch)
tree5fe813a40793f0a01257a46630451836cb584f5d
parent22c808bb76ea5873bab7b39b9e4e53f1e11d208b (diff)
downloadchromium_src-56fd0a89174b70b665e6c0267a05e81beb86d510.zip
chromium_src-56fd0a89174b70b665e6c0267a05e81beb86d510.tar.gz
chromium_src-56fd0a89174b70b665e6c0267a05e81beb86d510.tar.bz2
Modified the PerformanceMonitor to not use test/ code for enumerating Chrome processes.
Separated out basic performance metrics gathering in the PerformanceMonitor to run independently from the metrics/events database code. The former will now run even without the performance-monitor-gathering flag. Added an UMA event which triggers when the browser process never runs below X CPU utilization over a period of Y seconds. BUG=279660, 273320 Review URL: https://codereview.chromium.org/23825004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226466 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chrome_browser_main.cc5
-rw-r--r--chrome/browser/performance_monitor/constants.h7
-rw-r--r--chrome/browser/performance_monitor/event.h34
-rw-r--r--chrome/browser/performance_monitor/event_type.h44
-rw-r--r--chrome/browser/performance_monitor/performance_monitor.cc370
-rw-r--r--chrome/browser/performance_monitor/performance_monitor.h77
-rw-r--r--chrome/browser/performance_monitor/performance_monitor_browsertest.cc25
-rw-r--r--chrome/browser/performance_monitor/process_metrics_history.cc88
-rw-r--r--chrome/browser/performance_monitor/process_metrics_history.h72
-rw-r--r--chrome/browser/performance_monitor/startup_timer.cc11
-rw-r--r--chrome/chrome_browser.gypi10
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi5
-rw-r--r--tools/metrics/actions/chromeactions.txt2
14 files changed, 511 insertions, 241 deletions
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 9589a51..a2dfd7a 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -1575,10 +1575,7 @@ bool ChromeBrowserMainParts::MainMessageLoopRun(int* result_code) {
base::RunLoop run_loop;
#endif
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kPerformanceMonitorGathering)) {
- performance_monitor::PerformanceMonitor::GetInstance()->Start();
- }
+ performance_monitor::PerformanceMonitor::GetInstance()->Start();
run_loop.Run();
diff --git a/chrome/browser/performance_monitor/constants.h b/chrome/browser/performance_monitor/constants.h
index 168baf2..84dfb8e 100644
--- a/chrome/browser/performance_monitor/constants.h
+++ b/chrome/browser/performance_monitor/constants.h
@@ -21,6 +21,8 @@ extern const char kProcessChromeAggregate[];
extern const char kStateChromeVersion[];
extern const char kStateProfilePrefix[];
+// The interval the watched processes are sampled for performance metrics.
+const int kSampleIntervalInSeconds = 10;
// The default interval at which PerformanceMonitor performs its timed
// collections; this can be overridden by using the kPerformanceMonitorGathering
// switch with an associated (positive integer) value.
@@ -41,6 +43,11 @@ const int64 kBytesPerTerabyte = kBytesPerGigabyte * (1 << 10);
const int64 kMicrosecondsPerMonth = base::Time::kMicrosecondsPerDay * 30;
const int64 kMicrosecondsPerYear = base::Time::kMicrosecondsPerDay * 365;
+// Performance alert thresholds
+
+// 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 performance_monitor
#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_CONSTANTS_H_
diff --git a/chrome/browser/performance_monitor/event.h b/chrome/browser/performance_monitor/event.h
index b7666b4..4bde259 100644
--- a/chrome/browser/performance_monitor/event.h
+++ b/chrome/browser/performance_monitor/event.h
@@ -9,39 +9,9 @@
#include "base/time/time.h"
#include "base/values.h"
-namespace performance_monitor {
-
-// IMPORTANT: To add new events, please
-// - Place the new event above EVENT_NUMBER_OF_EVENTS.
-// - Add a member to the EventKeyChar enum in key_builder.cc.
-// - Add the appropriate messages in generated_resources.grd.
-// - Add the appropriate functions in
-// chrome/browser/ui/webui/performance_monitor/performance_monitor_l10n.h.
-enum EventType {
- EVENT_UNDEFINED,
-
- // Extension-Related events
- EVENT_EXTENSION_INSTALL,
- EVENT_EXTENSION_UNINSTALL,
- EVENT_EXTENSION_UPDATE,
- EVENT_EXTENSION_ENABLE,
- EVENT_EXTENSION_DISABLE,
-
- // Chrome's version has changed.
- EVENT_CHROME_UPDATE,
+#include "chrome/browser/performance_monitor/event_type.h"
- // Renderer-Failure related events; these correspond to the RENDERER_HANG
- // event, and the two termination statuses ABNORMAL_EXIT and PROCESS_KILLED,
- // respectively.
- EVENT_RENDERER_HANG,
- EVENT_RENDERER_CRASH,
- EVENT_RENDERER_KILLED,
-
- // Chrome did not shut down correctly.
- EVENT_UNCLEAN_EXIT,
-
- EVENT_NUMBER_OF_EVENTS
-};
+namespace performance_monitor {
const char* EventTypeToString(EventType event_type);
diff --git a/chrome/browser/performance_monitor/event_type.h b/chrome/browser/performance_monitor/event_type.h
new file mode 100644
index 0000000..fd19cac
--- /dev/null
+++ b/chrome/browser/performance_monitor/event_type.h
@@ -0,0 +1,44 @@
+// Copyright 2013 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_EVENT_TYPE_H_
+#define CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_TYPE_H_
+
+namespace performance_monitor {
+
+// IMPORTANT: To add new events, please
+// - Place the new event above EVENT_NUMBER_OF_EVENTS.
+// - Add a member to the EventKeyChar enum in key_builder.cc.
+// - Add the appropriate messages in generated_resources.grd.
+// - Add the appropriate functions in
+// chrome/browser/ui/webui/performance_monitor/performance_monitor_l10n.h.
+enum EventType {
+ EVENT_UNDEFINED,
+
+ // Extension-Related events
+ EVENT_EXTENSION_INSTALL,
+ EVENT_EXTENSION_UNINSTALL,
+ EVENT_EXTENSION_UPDATE,
+ EVENT_EXTENSION_ENABLE,
+ EVENT_EXTENSION_DISABLE,
+
+ // Chrome's version has changed.
+ EVENT_CHROME_UPDATE,
+
+ // Renderer-Failure related events; these correspond to the RENDERER_HANG
+ // event, and the two termination statuses ABNORMAL_EXIT and PROCESS_KILLED,
+ // respectively.
+ EVENT_RENDERER_HANG,
+ EVENT_RENDERER_CRASH,
+ EVENT_RENDERER_KILLED,
+
+ // Chrome did not shut down correctly.
+ EVENT_UNCLEAN_EXIT,
+
+ EVENT_NUMBER_OF_EVENTS
+};
+
+} // namespace performance_monitor
+
+#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_TYPE_H_
diff --git a/chrome/browser/performance_monitor/performance_monitor.cc b/chrome/browser/performance_monitor/performance_monitor.cc
index b800e7f..55e5df1 100644
--- a/chrome/browser/performance_monitor/performance_monitor.cc
+++ b/chrome/browser/performance_monitor/performance_monitor.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/memory/singleton.h"
#include "base/process/process_iterator.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -29,9 +30,10 @@
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/test/base/chrome_process_util.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_thread.h"
+#include "content/public/browser/child_process_data.h"
#include "content/public/browser/load_notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
@@ -53,8 +55,6 @@ const uint32 kAccessFlags = base::kProcessAccessDuplicateHandle |
base::kProcessAccessTerminate |
base::kProcessAccessWaitForTermination;
-bool g_started_initialization = false;
-
std::string TimeToString(base::Time time) {
int64 time_int64 = time.ToInternalValue();
return base::Int64ToString(time_int64);
@@ -99,7 +99,15 @@ PerformanceMonitor::PerformanceDataForIOThread::PerformanceDataForIOThread()
: network_bytes_read(0) {
}
-PerformanceMonitor::PerformanceMonitor() : metrics_map_(new MetricsMap) {}
+PerformanceMonitor::PerformanceMonitor()
+ : gather_interval_in_seconds_(kDefaultGatherIntervalInSeconds),
+ database_logging_enabled_(false),
+ timer_(FROM_HERE,
+ base::TimeDelta::FromSeconds(kSampleIntervalInSeconds),
+ this,
+ &PerformanceMonitor::DoTimedCollections),
+ disable_timer_autostart_for_testing_(false) {
+}
PerformanceMonitor::~PerformanceMonitor() {
BrowserThread::PostBlockingPoolSequencedTask(
@@ -126,11 +134,39 @@ PerformanceMonitor* PerformanceMonitor::GetInstance() {
void PerformanceMonitor::Start() {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- // Avoid responding to multiple calls to Start().
- if (g_started_initialization)
+ static bool has_initialized = false;
+ if (has_initialized) {
+ NOTREACHED();
return;
+ }
+ has_initialized = true;
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kPerformanceMonitorGathering)) {
+ database_logging_enabled_ = true;
+
+ std::string switch_value = CommandLine::ForCurrentProcess()->
+ GetSwitchValueASCII(switches::kPerformanceMonitorGathering);
+
+ if (!switch_value.empty()) {
+ int specified_interval = 0;
+ if (!base::StringToInt(switch_value, &specified_interval) ||
+ specified_interval <= 0) {
+ LOG(ERROR) << "Invalid value for switch: '"
+ << switches::kPerformanceMonitorGathering
+ << "'; please use an integer greater than 0.";
+ } else {
+ gather_interval_in_seconds_ = std::max(specified_interval,
+ kSampleIntervalInSeconds);
+ }
+ }
+ }
+
+ DCHECK(gather_interval_in_seconds_ >= kSampleIntervalInSeconds);
+
+ next_collection_time_ = base::Time::Now() +
+ base::TimeDelta::FromSeconds(gather_interval_in_seconds_);
- g_started_initialization = true;
util::PostTaskToDatabaseThreadAndReply(
FROM_HERE,
base::Bind(&PerformanceMonitor::InitOnBackgroundThread,
@@ -141,59 +177,42 @@ void PerformanceMonitor::Start() {
void PerformanceMonitor::InitOnBackgroundThread() {
CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
- database_ = Database::Create(database_path_);
- if (!database_) {
- LOG(ERROR) << "Could not initialize database; aborting initialization.";
- return;
- }
- // Initialize the io thread's performance data to the value in the database;
- // if there isn't a recording in the database, the value stays at 0.
- Metric metric;
- if (database_->GetRecentStatsForActivityAndMetric(METRIC_NETWORK_BYTES_READ,
- &metric)) {
- performance_data_for_io_thread_.network_bytes_read = metric.value;
+ if (database_logging_enabled_) {
+ database_ = Database::Create(database_path_);
+ if (!database_) {
+ LOG(ERROR) << "Could not initialize database; aborting initialization.";
+ database_logging_enabled_ = false;
+ return;
+ }
+
+ // Initialize the io thread's performance data to the value in the database;
+ // if there isn't a recording in the database, the value stays at 0.
+ Metric metric;
+ if (database_->GetRecentStatsForActivityAndMetric(METRIC_NETWORK_BYTES_READ,
+ &metric)) {
+ performance_data_for_io_thread_.network_bytes_read = metric.value;
+ }
}
}
void PerformanceMonitor::FinishInit() {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- // Short-circuit the initialization process if the database wasn't properly
- // created. This will prevent PerformanceMonitor from performing any actions,
- // including observing events.
- if (!database_)
- return;
-
- RegisterForNotifications();
- CheckForUncleanExits();
- BrowserThread::PostBlockingPoolSequencedTask(
- Database::kDatabaseSequenceToken,
- FROM_HERE,
- base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread,
- base::Unretained(this)));
- int gather_interval_in_seconds = kDefaultGatherIntervalInSeconds;
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kPerformanceMonitorGathering) &&
- !CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kPerformanceMonitorGathering).empty()) {
- int specified_interval = 0;
- if (!base::StringToInt(
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kPerformanceMonitorGathering),
- &specified_interval) || specified_interval <= 0) {
- LOG(ERROR) << "Invalid value for switch: '"
- << switches::kPerformanceMonitorGathering
- << "'; please use an integer greater than 0.";
- } else {
- gather_interval_in_seconds = specified_interval;
- }
+ // Events and notifications are only useful if we're logging to the database.
+ if (database_logging_enabled_) {
+ RegisterForNotifications();
+ CheckForUncleanExits();
+ BrowserThread::PostBlockingPoolSequencedTask(
+ Database::kDatabaseSequenceToken,
+ FROM_HERE,
+ base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread,
+ base::Unretained(this)));
}
- timer_.Start(FROM_HERE,
- base::TimeDelta::FromSeconds(gather_interval_in_seconds),
- this,
- &PerformanceMonitor::DoTimedCollections);
+ // Start our periodic gathering of metrics.
+ if (!disable_timer_autostart_for_testing_)
+ timer_.Reset();
// Post a task to the background thread to a function which does nothing.
// This will force any tasks the database is performing to finish prior to
@@ -210,6 +229,8 @@ void PerformanceMonitor::FinishInit() {
}
void PerformanceMonitor::RegisterForNotifications() {
+ DCHECK(database_logging_enabled_);
+
// Extensions
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
content::NotificationService::AllSources());
@@ -241,6 +262,8 @@ void PerformanceMonitor::RegisterForNotifications() {
// loaded prior to PerformanceMonitor's initialization. Later profiles will be
// checked through the PROFILE_ADDED notification.
void PerformanceMonitor::CheckForUncleanExits() {
+ DCHECK(database_logging_enabled_);
+
std::vector<Profile*> profiles =
g_browser_process->profile_manager()->GetLoadedProfiles();
@@ -258,7 +281,8 @@ void PerformanceMonitor::CheckForUncleanExits() {
}
void PerformanceMonitor::AddUncleanExitEventOnBackgroundThread(
- const std::string& profile_name) {
+ const std::string& profile_name) {
+ DCHECK(database_logging_enabled_);
std::string database_key = kStateProfilePrefix + profile_name;
std::string last_active_string = database_->GetStateValue(database_key);
@@ -279,6 +303,7 @@ void PerformanceMonitor::AddUncleanExitEventOnBackgroundThread(
void PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread() {
CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(database_logging_enabled_);
chrome::VersionInfo version;
DCHECK(version.is_valid());
@@ -305,6 +330,8 @@ void PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread() {
}
void PerformanceMonitor::AddEvent(scoped_ptr<Event> event) {
+ DCHECK(database_logging_enabled_);
+
BrowserThread::PostBlockingPoolSequencedTask(
Database::kDatabaseSequenceToken,
FROM_HERE,
@@ -319,6 +346,8 @@ void PerformanceMonitor::AddEventOnBackgroundThread(scoped_ptr<Event> event) {
void PerformanceMonitor::AddMetricOnBackgroundThread(const Metric& metric) {
DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(database_logging_enabled_);
+
database_->AddMetric(metric);
}
@@ -331,88 +360,62 @@ void PerformanceMonitor::NotifyInitialized() {
initialized_ = true;
}
-void PerformanceMonitor::GatherStatisticsOnBackgroundThread() {
- CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Because the CPU usage is gathered as an average since the last time the
- // function was called, while the memory usage is gathered as an instantaneous
- // usage, the CPU usage is gathered before the metrics map is wiped.
- GatherCPUUsageOnBackgroundThread();
- UpdateMetricsMapOnBackgroundThread();
- GatherMemoryUsageOnBackgroundThread();
-}
-
-void PerformanceMonitor::GatherCPUUsageOnBackgroundThread() {
- if (metrics_map_->size()) {
- double cpu_usage = 0;
- for (MetricsMap::const_iterator iter = metrics_map_->begin();
- iter != metrics_map_->end(); ++iter) {
- cpu_usage += iter->second->GetCPUUsage();
- }
+void PerformanceMonitor::DoTimedCollections() {
+#if !defined(OS_ANDROID)
+ // The profile list is only useful for the logged events.
+ if (database_logging_enabled_)
+ UpdateLiveProfiles();
+#endif
- database_->AddMetric(Metric(METRIC_CPU_USAGE,
- base::Time::Now(),
- cpu_usage));
- }
+ GatherMetricsMapOnUIThread();
}
-void PerformanceMonitor::GatherMemoryUsageOnBackgroundThread() {
- size_t private_memory_sum = 0;
- size_t shared_memory_sum = 0;
- for (MetricsMap::const_iterator iter = metrics_map_->begin();
- iter != metrics_map_->end(); ++iter) {
- size_t private_memory = 0;
- size_t shared_memory = 0;
- if (iter->second->GetMemoryBytes(&private_memory, &shared_memory)) {
- private_memory_sum += private_memory;
- shared_memory_sum += shared_memory;
- } else {
- LOG(WARNING) << "GetMemoryBytes returned NULL (platform-specific error)";
- }
+void PerformanceMonitor::GatherMetricsMapOnUIThread() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ static int current_update_sequence = 0;
+ // Even in the "somewhat" unlikely event this wraps around,
+ // it doesn't matter. We just check it for inequality.
+ current_update_sequence++;
+
+ // Find all render child processes; has to be done on the UI thread.
+ for (content::RenderProcessHost::iterator rph_iter =
+ content::RenderProcessHost::AllHostsIterator();
+ !rph_iter.IsAtEnd(); rph_iter.Advance()) {
+ base::ProcessHandle handle = rph_iter.GetCurrentValue()->GetHandle();
+ MarkProcessAsAlive(handle, content::PROCESS_TYPE_RENDERER,
+ current_update_sequence);
}
- database_->AddMetric(Metric(METRIC_PRIVATE_MEMORY_USAGE,
- base::Time::Now(),
- static_cast<double>(private_memory_sum)));
- database_->AddMetric(Metric(METRIC_SHARED_MEMORY_USAGE,
- base::Time::Now(),
- static_cast<double>(shared_memory_sum)));
-}
-
-void PerformanceMonitor::UpdateMetricsMapOnBackgroundThread() {
- MetricsMap* new_map = new MetricsMap;
-
- base::ProcessId browser_pid = base::GetCurrentProcId();
- ChromeProcessList chrome_processes(GetRunningChromeProcesses(browser_pid));
- for (ChromeProcessList::const_iterator pid_iter = chrome_processes.begin();
- pid_iter != chrome_processes.end(); ++pid_iter) {
- base::ProcessHandle handle;
- if (base::OpenProcessHandleWithAccess(*pid_iter, kAccessFlags, &handle)) {
- // If we were already watching this process, transfer it to the new map.
- if (ContainsKey(*metrics_map_, handle)) {
- (*new_map)[handle] = (*metrics_map_)[handle];
- continue;
- }
-
- // Otherwise, gather information and prime the CPU usage to be gathered.
-#if defined (OS_MACOSX)
- linked_ptr<base::ProcessMetrics> process_metrics(
- base::ProcessMetrics::CreateProcessMetrics(
- handle, content::BrowserChildProcessHost::GetPortProvider()));
-#else
- linked_ptr<base::ProcessMetrics> process_metrics(
- base::ProcessMetrics::CreateProcessMetrics(handle));
-#endif
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&PerformanceMonitor::GatherMetricsMapOnIOThread,
+ base::Unretained(this),
+ current_update_sequence));
+}
- process_metrics->GetCPUUsage();
+void PerformanceMonitor::MarkProcessAsAlive(const base::ProcessHandle& handle,
+ int process_type,
+ int current_update_sequence) {
- (*new_map)[handle] = process_metrics;
- }
+ if (handle == 0) {
+ // Process may not be valid yet.
+ return;
}
- metrics_map_.reset(new_map);
+ MetricsMap::iterator process_metrics_iter = metrics_map_.find(handle);
+ if (process_metrics_iter == metrics_map_.end()) {
+ // If we're not already watching the process, let's initialize it.
+ metrics_map_[handle]
+ .Initialize(handle, process_type, current_update_sequence);
+ } else {
+ // If we are watching the process, touch it to keep it alive.
+ ProcessMetricsHistory& process_metrics = process_metrics_iter->second;
+ process_metrics.set_last_update_sequence(current_update_sequence);
+ }
}
+#if !defined(OS_ANDROID)
void PerformanceMonitor::UpdateLiveProfiles() {
std::string time = TimeToString(base::Time::Now());
scoped_ptr<std::set<std::string> > active_profiles(
@@ -434,48 +437,119 @@ void PerformanceMonitor::UpdateLiveProfilesHelper(
scoped_ptr<std::set<std::string> > active_profiles,
std::string time) {
CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(database_logging_enabled_);
for (std::set<std::string>::const_iterator iter = active_profiles->begin();
iter != active_profiles->end(); ++iter) {
database_->AddStateValue(kStateProfilePrefix + *iter, time);
}
}
+#endif
-void PerformanceMonitor::DoTimedCollections() {
- UpdateLiveProfiles();
-
- BrowserThread::PostBlockingPoolSequencedTask(
- Database::kDatabaseSequenceToken,
- FROM_HERE,
- base::Bind(&PerformanceMonitor::GatherStatisticsOnBackgroundThread,
- base::Unretained(this)));
+void PerformanceMonitor::GatherMetricsMapOnIOThread(
+ int current_update_sequence) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&PerformanceMonitor::CallInsertIOData,
- base::Unretained(this)));
-}
+ // Find all child processes (does not include renderers), which has to be
+ // done on the IO thread.
+ for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
+ const content::ChildProcessData& child_process_data = iter.GetData();
+ base::ProcessHandle handle = child_process_data.handle;
+ MarkProcessAsAlive(handle, child_process_data.process_type,
+ current_update_sequence);
+ }
-void PerformanceMonitor::CallInsertIOData() {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Add the current (browser) process.
+ MarkProcessAsAlive(base::GetCurrentProcessHandle(),
+ content::PROCESS_TYPE_BROWSER, current_update_sequence);
BrowserThread::PostBlockingPoolSequencedTask(
Database::kDatabaseSequenceToken,
FROM_HERE,
- base::Bind(&PerformanceMonitor::InsertIOData,
- base::Unretained(this),
+ base::Bind(&PerformanceMonitor::StoreMetricsOnBackgroundThread,
+ base::Unretained(this), current_update_sequence,
performance_data_for_io_thread_));
}
-void PerformanceMonitor::InsertIOData(
+void PerformanceMonitor::StoreMetricsOnBackgroundThread(
+ int current_update_sequence,
const PerformanceDataForIOThread& performance_data_for_io_thread) {
CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
- database_->AddMetric(
- Metric(METRIC_NETWORK_BYTES_READ,
- base::Time::Now(),
- static_cast<double>(
- performance_data_for_io_thread.network_bytes_read)));
+
+ base::Time time_now = base::Time::Now();
+
+ // The timing can be off by kSampleIntervalInSeconds during any one particular
+ // run, but will be correct over time.
+ bool end_of_cycle = time_now >= next_collection_time_;
+ if (end_of_cycle) {
+ next_collection_time_ +=
+ base::TimeDelta::FromSeconds(gather_interval_in_seconds_);
+ }
+
+ double cpu_usage = 0.0;
+ size_t private_memory_sum = 0;
+ size_t shared_memory_sum = 0;
+
+ // Update metrics for all watched processes; remove dead entries from the map.
+ MetricsMap::iterator iter = metrics_map_.begin();
+ while (iter != metrics_map_.end()) {
+ ProcessMetricsHistory& process_metrics = iter->second;
+ if (process_metrics.last_update_sequence() != current_update_sequence) {
+ // Not touched this iteration; let's get rid of it.
+ metrics_map_.erase(iter++);
+ } else {
+ process_metrics.SampleMetrics();
+
+ if (end_of_cycle) {
+ // Gather averages of previously sampled metrics.
+ cpu_usage += process_metrics.GetAverageCPUUsage();
+
+ size_t private_memory = 0;
+ size_t shared_memory = 0;
+ process_metrics.GetAverageMemoryBytes(&private_memory, &shared_memory);
+ private_memory_sum += private_memory;
+ shared_memory_sum += shared_memory;
+
+ process_metrics.EndOfCycle();
+ }
+
+ ++iter;
+ }
+ }
+
+ // Store previously-sampled metrics.
+ if (end_of_cycle && database_logging_enabled_) {
+ if (!metrics_map_.empty()) {
+ database_->AddMetric(Metric(METRIC_CPU_USAGE, time_now, cpu_usage));
+ database_->AddMetric(Metric(METRIC_PRIVATE_MEMORY_USAGE,
+ time_now,
+ static_cast<double>(private_memory_sum)));
+ database_->AddMetric(Metric(METRIC_SHARED_MEMORY_USAGE,
+ time_now,
+ static_cast<double>(shared_memory_sum)));
+ }
+
+ database_->AddMetric(
+ Metric(METRIC_NETWORK_BYTES_READ,
+ time_now,
+ static_cast<double>(
+ performance_data_for_io_thread.network_bytes_read)));
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&PerformanceMonitor::ResetMetricsTimerOnUIThread,
+ base::Unretained(this)));
+}
+
+void PerformanceMonitor::ResetMetricsTimerOnUIThread() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Start up the timer again; we avoid the use of a repeating timer
+ // to not have concurrent metrics gathering running.
+ if (!disable_timer_autostart_for_testing_)
+ timer_.Reset();
}
void PerformanceMonitor::BytesReadOnIOThread(const net::URLRequest& request,
@@ -489,6 +563,8 @@ void PerformanceMonitor::BytesReadOnIOThread(const net::URLRequest& request,
void PerformanceMonitor::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
+ DCHECK(database_logging_enabled_);
+
switch (type) {
case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
AddExtensionEvent(
diff --git a/chrome/browser/performance_monitor/performance_monitor.h b/chrome/browser/performance_monitor/performance_monitor.h
index a054f58..ff14abb 100644
--- a/chrome/browser/performance_monitor/performance_monitor.h
+++ b/chrome/browser/performance_monitor/performance_monitor.h
@@ -6,23 +6,23 @@
#define CHROME_BROWSER_PERFORMANCE_MONITOR_PERFORMANCE_MONITOR_H_
#include <map>
+#include <set>
#include <string>
-#include "base/callback.h"
#include "base/files/file_path.h"
-#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
-#include "base/memory/singleton.h"
-#include "base/process/process_metrics.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
#include "base/timer/timer.h"
-#include "chrome/browser/performance_monitor/database.h"
-#include "chrome/browser/performance_monitor/event.h"
-#include "content/public/browser/notification_details.h"
+#include "chrome/browser/performance_monitor/event_type.h"
+#include "chrome/browser/performance_monitor/process_metrics_history.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_process_host.h"
+template <typename Type>
+struct DefaultSingletonTraits;
+
namespace extensions {
class Extension;
}
@@ -33,6 +33,8 @@ class URLRequest;
namespace performance_monitor {
class Database;
+class Event;
+struct Metric;
// PerformanceMonitor is a tool which will allow the user to view information
// about Chrome's performance over a period of time. It will gather statistics
@@ -56,8 +58,7 @@ class PerformanceMonitor : public content::NotificationObserver {
uint64 network_bytes_read;
};
- typedef std::map<base::ProcessHandle,
- linked_ptr<base::ProcessMetrics> > MetricsMap;
+ typedef std::map<base::ProcessHandle, ProcessMetricsHistory> MetricsMap;
// Set the path which the PerformanceMonitor should use for the database files
// constructed. This must be done prior to the initialization of the
@@ -66,6 +67,8 @@ class PerformanceMonitor : public content::NotificationObserver {
// time of the call).
bool SetDatabasePath(const base::FilePath& path);
+ bool database_logging_enabled() const { return database_logging_enabled_; }
+
// Returns the current PerformanceMonitor instance if one exists; otherwise
// constructs a new PerformanceMonitor.
static PerformanceMonitor* GetInstance();
@@ -141,22 +144,32 @@ class PerformanceMonitor : public content::NotificationObserver {
// Update the database record of the last time the active profiles were
// running; this is used in determining when an unclean exit occurred.
+#if !defined(OS_ANDROID)
void UpdateLiveProfiles();
void UpdateLiveProfilesHelper(
scoped_ptr<std::set<std::string> > active_profiles, std::string time);
+#endif
- // Gathers CPU usage and memory usage of all Chrome processes in order to.
- void GatherStatisticsOnBackgroundThread();
+ // Stores CPU/memory usage metrics to the database.
+ void StoreMetricsOnBackgroundThread(
+ int current_update_sequence,
+ const PerformanceDataForIOThread& performance_data_for_io_thread);
- // Gathers the CPU usage of every Chrome process that has been running since
- // the last call to GatherStatistics().
- void GatherCPUUsageOnBackgroundThread();
+ // 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 base::ProcessHandle& handle,
+ int process_type,
+ int current_update_sequence);
- // Gathers the memory usage of every process in the current list of processes.
- void GatherMemoryUsageOnBackgroundThread();
+ // Updates the ProcessMetrics map with the current list of processes and
+ // gathers metrics from each entry.
+ void GatherMetricsMapOnUIThread();
+ void GatherMetricsMapOnIOThread(int current_update_sequence);
- // Updates the ProcessMetrics map with the current list of processes.
- void UpdateMetricsMapOnBackgroundThread();
+ // Called at the end of the metrics gathering process, to start
+ // our timer for the next run.
+ void ResetMetricsTimerOnUIThread();
// Generate an appropriate ExtensionEvent for an extension-related occurrance
// and insert it in the database.
@@ -169,15 +182,6 @@ class PerformanceMonitor : public content::NotificationObserver {
content::RenderProcessHost* host,
const content::RenderProcessHost::RendererClosedDetails& details);
- // Called on the IO thread, this will call InsertIOData on the background
- // thread with a copy of the PerformanceDataForIOThread object to prevent
- // any possible race conditions.
- void CallInsertIOData();
-
- // Insert the collected IO data into the database.
- void InsertIOData(
- const PerformanceDataForIOThread& performance_data_for_io_thread);
-
// The store for all performance data that must be gathered from the IO
// thread.
PerformanceDataForIOThread performance_data_for_io_thread_;
@@ -189,10 +193,20 @@ class PerformanceMonitor : public content::NotificationObserver {
scoped_ptr<Database> database_;
// A map of currently running ProcessHandles to ProcessMetrics.
- scoped_ptr<MetricsMap> metrics_map_;
+ MetricsMap metrics_map_;
+
+ // The next time we should collect averages from the performance metrics
+ // and act on them.
+ base::Time next_collection_time_;
+
+ // How long to wait between collections.
+ int gather_interval_in_seconds_;
+
+ // Enable persistent logging of performance metrics to a database.
+ bool database_logging_enabled_;
// The timer to signal PerformanceMonitor to perform its timed collections.
- base::RepeatingTimer<PerformanceMonitor> timer_;
+ base::DelayTimer<PerformanceMonitor> timer_;
content::NotificationRegistrar registrar_;
@@ -202,6 +216,9 @@ class PerformanceMonitor : public content::NotificationObserver {
// flag.
static bool initialized_;
+ // Disable auto-starting the collection timer; used for tests.
+ bool disable_timer_autostart_for_testing_;
+
DISALLOW_COPY_AND_ASSIGN(PerformanceMonitor);
};
diff --git a/chrome/browser/performance_monitor/performance_monitor_browsertest.cc b/chrome/browser/performance_monitor/performance_monitor_browsertest.cc
index a343e04..0535418 100644
--- a/chrome/browser/performance_monitor/performance_monitor_browsertest.cc
+++ b/chrome/browser/performance_monitor/performance_monitor_browsertest.cc
@@ -161,25 +161,24 @@ class PerformanceMonitorBrowserTest : public ExtensionBrowserTest {
chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED,
content::NotificationService::AllSources());
+ // We stop the timer in charge of doing timed collections so that we can
+ // enforce when, and how many times, we do these collections.
+ performance_monitor_->disable_timer_autostart_for_testing_ = true;
+ // Force metrics to be stored, regardless of switches used.
+ performance_monitor_->database_logging_enabled_ = true;
performance_monitor_->Start();
windowed_observer.Wait();
-
- // We stop the timer in charge of doing timed collections so that we can
- // enforce when, and how many times, we do these collections.
- performance_monitor_->timer_.Stop();
}
// A handle for gathering statistics from the database, which must be done on
// the background thread. Since we are testing, we can mock synchronicity with
// FlushForTesting().
void GatherStatistics() {
- content::BrowserThread::PostBlockingPoolSequencedTask(
- Database::kDatabaseSequenceToken,
- FROM_HERE,
- base::Bind(&PerformanceMonitor::GatherStatisticsOnBackgroundThread,
- base::Unretained(performance_monitor())));
+ performance_monitor_->next_collection_time_ = base::Time::Now();
+ performance_monitor_->GatherMetricsMapOnUIThread();
+ RunAllPendingInMessageLoop(content::BrowserThread::IO);
content::BrowserThread::GetBlockingPool()->FlushForTesting();
}
@@ -772,11 +771,7 @@ IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, NetworkBytesRead) {
browser(),
test_server()->GetURL(std::string("files/").append("title1.html")));
- performance_monitor()->DoTimedCollections();
-
- // Since network bytes are read and set on the IO thread, we must flush this
- // additional thread to be sure that all messages are run.
- RunAllPendingInMessageLoop(content::BrowserThread::IO);
+ GatherStatistics();
Database::MetricVector metrics = GetStats(METRIC_NETWORK_BYTES_READ);
ASSERT_EQ(1u, metrics.size());
@@ -789,7 +784,7 @@ IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, NetworkBytesRead) {
browser(),
test_server()->GetURL(std::string("files/").append("title2.html")));
- performance_monitor()->DoTimedCollections();
+ GatherStatistics();
metrics = GetStats(METRIC_NETWORK_BYTES_READ);
ASSERT_EQ(2u, metrics.size());
diff --git a/chrome/browser/performance_monitor/process_metrics_history.cc b/chrome/browser/performance_monitor/process_metrics_history.cc
new file mode 100644
index 0000000..84ffcac
--- /dev/null
+++ b/chrome/browser/performance_monitor/process_metrics_history.cc
@@ -0,0 +1,88 @@
+// Copyright 2013 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 <limits>
+
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+
+#include "chrome/browser/performance_monitor/constants.h"
+#include "chrome/browser/performance_monitor/process_metrics_history.h"
+#if defined(OS_MACOSX)
+#include "content/public/browser/browser_child_process_host.h"
+#endif
+#include "content/public/browser/user_metrics.h"
+#include "content/public/common/process_type.h"
+
+namespace performance_monitor {
+
+ProcessMetricsHistory::ProcessMetricsHistory()
+ : process_handle_(0),
+ process_type_(content::PROCESS_TYPE_UNKNOWN),
+ last_update_sequence_(0) {
+ ResetCounters();
+}
+
+ProcessMetricsHistory::~ProcessMetricsHistory() {}
+
+void ProcessMetricsHistory::ResetCounters() {
+ min_cpu_usage_ = std::numeric_limits<double>::max();
+ accumulated_cpu_usage_ = 0.0;
+ accumulated_private_bytes_ = 0;
+ accumulated_shared_bytes_ = 0;
+ sample_count_ = 0;
+}
+
+void ProcessMetricsHistory::Initialize(base::ProcessHandle process_handle,
+ int process_type,
+ int initial_update_sequence) {
+ DCHECK(process_handle_ == 0);
+ process_handle_ = process_handle;
+ process_type_ = process_type;
+ last_update_sequence_ = initial_update_sequence;
+
+#if defined(OS_MACOSX)
+ process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(
+ process_handle_, content::BrowserChildProcessHost::GetPortProvider()));
+#else
+ process_metrics_.reset(
+ base::ProcessMetrics::CreateProcessMetrics(process_handle_));
+#endif
+}
+
+void ProcessMetricsHistory::SampleMetrics() {
+ double cpu_usage = process_metrics_->GetCPUUsage();
+ min_cpu_usage_ = std::min(min_cpu_usage_, cpu_usage);
+ accumulated_cpu_usage_ += cpu_usage;
+
+ size_t private_bytes = 0;
+ size_t shared_bytes = 0;
+ if (!process_metrics_->GetMemoryBytes(&private_bytes, &shared_bytes))
+ LOG(WARNING) << "GetMemoryBytes returned NULL (platform-specific error)";
+
+ accumulated_private_bytes_ += private_bytes;
+ accumulated_shared_bytes_ += shared_bytes;
+
+ sample_count_++;
+}
+
+void ProcessMetricsHistory::EndOfCycle() {
+ RunPerformanceTriggers();
+ ResetCounters();
+}
+
+void ProcessMetricsHistory::RunPerformanceTriggers() {
+ // As an initial step, we only care about browser processes.
+ if (process_type_ != content::PROCESS_TYPE_BROWSER)
+ return;
+
+ // If CPU usage has consistently been above our threshold,
+ // we *may* have an issue.
+ if (min_cpu_usage_ > kHighCPUUtilizationThreshold) {
+ content::RecordAction(
+ content::UserMetricsAction("PerformanceMonitor.HighCPU.Browser"));
+ }
+}
+
+} // namespace performance_monitor
diff --git a/chrome/browser/performance_monitor/process_metrics_history.h b/chrome/browser/performance_monitor/process_metrics_history.h
new file mode 100644
index 0000000..8837e1f
--- /dev/null
+++ b/chrome/browser/performance_monitor/process_metrics_history.h
@@ -0,0 +1,72 @@
+// Copyright 2013 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_HISTORY_H_
+#define CHROME_BROWSER_PERFORMANCE_MONITOR_PROCESS_METRICS_HISTORY_H_
+
+#include "base/memory/linked_ptr.h"
+#include "base/process/process_handle.h"
+
+namespace base {
+class ProcessMetrics;
+}
+
+namespace performance_monitor {
+
+class ProcessMetricsHistory {
+ public:
+ ProcessMetricsHistory();
+ ~ProcessMetricsHistory();
+
+ // Configure this to monitor a specific process.
+ void Initialize(base::ProcessHandle process_handle,
+ int process_type,
+ int initial_update_sequence);
+
+ // End of a measurement cycle; check for performance issues and reset
+ // accumulated statistics.
+ void EndOfCycle();
+
+ // Gather metrics for the process and accumulate with past data.
+ void SampleMetrics();
+
+ // Used to mark when this object was last updated, so we can cull
+ // dead ones.
+ void set_last_update_sequence(int new_update_sequence) {
+ last_update_sequence_ = new_update_sequence;
+ }
+
+ int last_update_sequence() const { return last_update_sequence_; }
+
+ // Average CPU over all the past sampling points since last reset.
+ double GetAverageCPUUsage() const {
+ return accumulated_cpu_usage_ / sample_count_;
+ }
+
+ // Average mem usage over all the past sampling points since last reset.
+ void GetAverageMemoryBytes(size_t* private_bytes,
+ size_t* shared_bytes) const {
+ *private_bytes = accumulated_private_bytes_ / sample_count_;
+ *shared_bytes = accumulated_shared_bytes_ / sample_count_;
+ }
+
+ private:
+ void ResetCounters();
+ void RunPerformanceTriggers();
+
+ base::ProcessHandle process_handle_;
+ int process_type_;
+ linked_ptr<base::ProcessMetrics> process_metrics_;
+ int last_update_sequence_;
+
+ double accumulated_cpu_usage_;
+ double min_cpu_usage_;
+ size_t accumulated_private_bytes_;
+ size_t accumulated_shared_bytes_;
+ int sample_count_;
+};
+
+} // namespace performance_monitor
+
+#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_PROCESS_METRICS_HISTORY_H_
diff --git a/chrome/browser/performance_monitor/startup_timer.cc b/chrome/browser/performance_monitor/startup_timer.cc
index d6aee73..175ab6d 100644
--- a/chrome/browser/performance_monitor/startup_timer.cc
+++ b/chrome/browser/performance_monitor/startup_timer.cc
@@ -90,10 +90,13 @@ void StartupTimer::Observe(int type,
const content::NotificationDetails& details) {
CHECK(type == chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED);
performance_monitor_initialized_ = true;
- if (elapsed_startup_time_ != base::TimeDelta())
- InsertElapsedStartupTime();
- if (elapsed_session_restore_times_.size())
- InsertElapsedSessionRestoreTime();
+
+ if (PerformanceMonitor::GetInstance()->database_logging_enabled()) {
+ if (elapsed_startup_time_ != base::TimeDelta())
+ InsertElapsedStartupTime();
+ if (elapsed_session_restore_times_.size())
+ InsertElapsedSessionRestoreTime();
+ }
}
// static
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 6ffea01..a0198d8 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1390,6 +1390,8 @@
'browser/performance_monitor/performance_monitor.h',
'browser/performance_monitor/performance_monitor_util.cc',
'browser/performance_monitor/performance_monitor_util.h',
+ 'browser/performance_monitor/process_metrics_history.cc',
+ 'browser/performance_monitor/process_metrics_history.h',
'browser/performance_monitor/startup_timer.cc',
'browser/performance_monitor/startup_timer.h',
'browser/platform_util.h',
@@ -2566,14 +2568,6 @@
'browser/webdata/web_intents_table.cc',
'browser/webdata/web_intents_table.h',
- # These files are needed by performance_monitor.cc and this dependency
- # should be removed (crbug.com/279660)
- 'test/base/test_switches.cc',
- 'test/base/test_switches.h',
- 'test/base/chrome_process_util.cc',
- 'test/base/chrome_process_util.h',
- 'test/base/chrome_process_util_mac.cc',
-
# These files are generated by GRIT.
'<(grit_out_dir)/grit/component_extension_resources_map.cc',
'<(grit_out_dir)/grit/devtools_discovery_page_resources_map.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 519dafa..e4bf877 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1490,12 +1490,12 @@
'test/base/chrome_test_launcher.cc',
'test/base/web_ui_browsertest.cc',
'test/base/web_ui_browsertest.h',
- 'test/data/chromeos/oobe_webui_browsertest.js',
'test/base/in_process_browser_test_browsertest.cc',
'test/base/tracing_browsertest.cc',
'test/base/test_chrome_web_ui_controller_factory.cc',
'test/base/test_chrome_web_ui_controller_factory.h',
'test/base/test_chrome_web_ui_controller_factory_browsertest.cc',
+ 'test/data/chromeos/oobe_webui_browsertest.js',
'test/data/webui/accessibility_audit_browsertest.js',
'test/data/webui/assertions.js',
'test/data/webui/async_gen.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 70af84d..fb7068d 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -218,6 +218,9 @@
'test/automation/tab_proxy.h',
'test/automation/window_proxy.cc',
'test/automation/window_proxy.h',
+ 'test/base/chrome_process_util.cc',
+ 'test/base/chrome_process_util.h',
+ 'test/base/chrome_process_util_mac.cc',
'test/base/chrome_render_view_host_test_harness.cc',
'test/base/chrome_render_view_host_test_harness.h',
'test/base/chrome_test_suite.cc',
@@ -244,6 +247,8 @@
'test/base/test_launcher_utils.h',
'test/base/test_location_bar.cc',
'test/base/test_location_bar.h',
+ 'test/base/test_switches.cc',
+ 'test/base/test_switches.h',
'test/base/test_tab_strip_model_observer.cc',
'test/base/test_tab_strip_model_observer.h',
'test/base/testing_browser_process.cc',
diff --git a/tools/metrics/actions/chromeactions.txt b/tools/metrics/actions/chromeactions.txt
index cee69a1..c3793e7 100644
--- a/tools/metrics/actions/chromeactions.txt
+++ b/tools/metrics/actions/chromeactions.txt
@@ -1440,6 +1440,7 @@
0xa7613e3a71f2d755 PasswordManager_RemoveSavedPassword
0x36bb6559696dc912 Paste
0x5d0e6942f354a06c PasteAndMatchStyle
+0xb0c1b1bb1cef8c89 PerformanceMonitor.HighCPU.Browser
0x01c52e891f36d4fe PlatformVerificationAccepted
0x1929087478be7017 PlatformVerificationRejected
0xca471265efb33961 PluginContextMenu_RotateClockwise
@@ -1537,6 +1538,7 @@
0x2d9491c68a4ec635 SelectTab5
0x8fa9d8e88271c82d SelectTab6
0xdaa611aa645914e5 SelectTab7
+0x7eb3241cff786567 SettingsResetBubble.Show
0xbc7eb334ae9f29d0 ShowAccessibilitySettings
0x1da022468e27685c ShowAppLauncherPage
0x0d1d6961dd313b79 ShowAppMenu