Commit 3cf1d2aa authored by dhnishi's avatar dhnishi Committed by Commit bot

Add ProcessPowerCollector to audit CPU and power information.

This is part of the battery auditing feature, which will be surfaced in the Website Settings options page in the next patch.

BUG=372598

Review URL: https://codereview.chromium.org/472383002

Cr-Commit-Position: refs/heads/master@{#291999}
parent bc9cd5f5
...@@ -347,6 +347,10 @@ class AppWindow : public content::NotificationObserver, ...@@ -347,6 +347,10 @@ class AppWindow : public content::NotificationObserver,
// Whether the app window wants to be alpha enabled. // Whether the app window wants to be alpha enabled.
bool requested_alpha_enabled() const { return requested_alpha_enabled_; } bool requested_alpha_enabled() const { return requested_alpha_enabled_; }
void SetAppWindowContentsForTesting(scoped_ptr<AppWindowContents> contents) {
app_window_contents_ = contents.Pass();
}
protected: protected:
virtual ~AppWindow(); virtual ~AppWindow();
......
...@@ -48,6 +48,7 @@ include_rules = [ ...@@ -48,6 +48,7 @@ include_rules = [
"+components/os_crypt", "+components/os_crypt",
"+components/password_manager", "+components/password_manager",
"+components/policy", "+components/policy",
"+components/power",
"+components/precache", "+components/precache",
"+components/pref_registry", "+components/pref_registry",
"+components/query_parser", "+components/query_parser",
......
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#include "chrome/browser/performance_monitor/performance_monitor.h" #include "chrome/browser/performance_monitor/performance_monitor.h"
#include "chrome/browser/performance_monitor/startup_timer.h" #include "chrome/browser/performance_monitor/startup_timer.h"
#include "chrome/browser/plugins/plugin_prefs.h" #include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/browser/power/process_power_collector.h"
#include "chrome/browser/pref_service_flags_storage.h" #include "chrome/browser/pref_service_flags_storage.h"
#include "chrome/browser/prefs/chrome_pref_service_factory.h" #include "chrome/browser/prefs/chrome_pref_service_factory.h"
#include "chrome/browser/prefs/command_line_pref_store.h" #include "chrome/browser/prefs/command_line_pref_store.h"
...@@ -1551,6 +1552,11 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() { ...@@ -1551,6 +1552,11 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
performance_monitor::PerformanceMonitor::GetInstance()->Initialize(); performance_monitor::PerformanceMonitor::GetInstance()->Initialize();
#if !defined(OS_ANDROID)
process_power_collector_.reset(new ProcessPowerCollector);
process_power_collector_->Initialize();
#endif
PostBrowserStart(); PostBrowserStart();
if (parameters().ui_task) { if (parameters().ui_task) {
...@@ -1625,6 +1631,10 @@ void ChromeBrowserMainParts::PostMainMessageLoopRun() { ...@@ -1625,6 +1631,10 @@ void ChromeBrowserMainParts::PostMainMessageLoopRun() {
// Disarm the startup hang detector time bomb if it is still Arm'ed. // Disarm the startup hang detector time bomb if it is still Arm'ed.
startup_watcher_->Disarm(); startup_watcher_->Disarm();
// Remove observers attached to D-Bus clients before DbusThreadManager is
// shut down.
process_power_collector_.reset();
for (size_t i = 0; i < chrome_extra_parts_.size(); ++i) for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
chrome_extra_parts_[i]->PostMainMessageLoopRun(); chrome_extra_parts_[i]->PostMainMessageLoopRun();
......
...@@ -23,6 +23,7 @@ class ChromeBrowserMainExtraParts; ...@@ -23,6 +23,7 @@ class ChromeBrowserMainExtraParts;
class FieldTrialSynchronizer; class FieldTrialSynchronizer;
class MetricsService; class MetricsService;
class PrefService; class PrefService;
class ProcessPowerCollector;
class Profile; class Profile;
class StartupBrowserCreator; class StartupBrowserCreator;
class StartupTimeBomb; class StartupTimeBomb;
...@@ -150,6 +151,11 @@ class ChromeBrowserMainParts : public content::BrowserMainParts { ...@@ -150,6 +151,11 @@ class ChromeBrowserMainParts : public content::BrowserMainParts {
ChromeBrowserFieldTrials browser_field_trials_; ChromeBrowserFieldTrials browser_field_trials_;
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// A monitor for attributing power consumption to origins.
scoped_ptr<ProcessPowerCollector> process_power_collector_;
#endif
// Vector of additional ChromeBrowserMainExtraParts. // Vector of additional ChromeBrowserMainExtraParts.
// Parts are deleted in the inverse order they are added. // Parts are deleted in the inverse order they are added.
std::vector<ChromeBrowserMainExtraParts*> chrome_extra_parts_; std::vector<ChromeBrowserMainExtraParts*> chrome_extra_parts_;
......
derat@chromium.org
dhnishi@chromium.org
sivachandra@chromium.org
// Copyright 2014 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/power/process_power_collector.h"
#include "apps/app_window.h"
#include "apps/app_window_registry.h"
#include "base/process/process_handle.h"
#include "base/process/process_metrics.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
#include "components/power/origin_power_map.h"
#include "components/power/origin_power_map_factory.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "url/gurl.h"
#if defined(OS_CHROMEOS)
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
#endif
namespace {
const int kSecondsPerSample = 30;
}
ProcessPowerCollector::PerProcessData::PerProcessData(
scoped_ptr<base::ProcessMetrics> metrics,
const GURL& origin,
Profile* profile)
: metrics_(metrics.Pass()),
profile_(profile),
last_origin_(origin),
last_cpu_percent_(0),
seen_this_cycle_(true) {
}
ProcessPowerCollector::PerProcessData::PerProcessData()
: profile_(NULL),
last_cpu_percent_(0.0),
seen_this_cycle_(false) {
}
ProcessPowerCollector::PerProcessData::~PerProcessData() {
}
ProcessPowerCollector::ProcessPowerCollector()
: scale_factor_(1.0) {
#if defined(OS_CHROMEOS)
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
this);
#endif
}
ProcessPowerCollector::~ProcessPowerCollector() {
#if defined(OS_CHROMEOS)
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(
this);
#endif
}
#if defined(OS_CHROMEOS)
void ProcessPowerCollector::PowerChanged(
const power_manager::PowerSupplyProperties& prop) {
if (prop.battery_state() ==
power_manager::PowerSupplyProperties::DISCHARGING) {
if (!timer_.IsRunning())
StartTimer();
scale_factor_ = prop.battery_discharge_rate();
} else {
timer_.Stop();
}
}
#endif
void ProcessPowerCollector::Initialize() {
StartTimer();
}
double ProcessPowerCollector::UpdatePowerConsumptionForTesting() {
return UpdatePowerConsumption();
}
void ProcessPowerCollector::StartTimer() {
DCHECK(!timer_.IsRunning());
timer_.Start(FROM_HERE,
base::TimeDelta::FromSeconds(kSecondsPerSample),
this,
&ProcessPowerCollector::HandleUpdateTimeout);
}
double ProcessPowerCollector::UpdatePowerConsumption() {
double total_cpu_percent = SynchronizeProcesses();
for (ProcessMetricsMap::iterator it = metrics_map_.begin();
it != metrics_map_.end();
++it) {
// Invalidate the process for the next cycle.
it->second->set_seen_this_cycle(false);
}
RecordCpuUsageByOrigin(total_cpu_percent);
return total_cpu_percent;
}
void ProcessPowerCollector::HandleUpdateTimeout() {
UpdatePowerConsumption();
}
double ProcessPowerCollector::SynchronizeProcesses() {
// Update all tabs.
for (TabContentsIterator it; !it.done(); it.Next()) {
content::RenderProcessHost* render_process = it->GetRenderProcessHost();
// Skip incognito web contents.
if (render_process->GetBrowserContext()->IsOffTheRecord())
continue;
UpdateProcessInMap(render_process, it->GetLastCommittedURL().GetOrigin());
}
// Iterate over all profiles to find all app windows to attribute all apps.
ProfileManager* pm = g_browser_process->profile_manager();
std::vector<Profile*> open_profiles = pm->GetLoadedProfiles();
for (std::vector<Profile*>::const_iterator it = open_profiles.begin();
it != open_profiles.end();
++it) {
const apps::AppWindowRegistry::AppWindowList& app_windows =
apps::AppWindowRegistry::Get(*it)->app_windows();
for (apps::AppWindowRegistry::AppWindowList::const_iterator itr =
app_windows.begin();
itr != app_windows.end();
++itr) {
content::WebContents* web_contents = (*itr)->web_contents();
UpdateProcessInMap(web_contents->GetRenderProcessHost(),
web_contents->GetLastCommittedURL().GetOrigin());
}
}
// Remove invalid processes and sum up the cpu cycle.
double total_cpu_percent = 0.0;
ProcessMetricsMap::iterator it = metrics_map_.begin();
while (it != metrics_map_.end()) {
if (!it->second->seen_this_cycle()) {
metrics_map_.erase(it++);
continue;
}
total_cpu_percent += it->second->last_cpu_percent();
++it;
}
return total_cpu_percent;
}
void ProcessPowerCollector::RecordCpuUsageByOrigin(double total_cpu_percent) {
DCHECK_GE(total_cpu_percent, 0);
if (total_cpu_percent == 0)
return;
for (ProcessMetricsMap::iterator it = metrics_map_.begin();
it != metrics_map_.end();
++it) {
double last_process_power_usage = it->second->last_cpu_percent();
last_process_power_usage *= scale_factor_ / total_cpu_percent;
GURL origin = it->second->last_origin();
power::OriginPowerMap* origin_power_map =
power::OriginPowerMapFactory::GetForBrowserContext(
it->second->profile());
DCHECK(origin_power_map);
origin_power_map->AddPowerForOrigin(origin, last_process_power_usage);
}
}
void ProcessPowerCollector::UpdateProcessInMap(
const content::RenderProcessHost* rph,
const GURL& origin) {
base::ProcessHandle handle = rph->GetHandle();
if (metrics_map_.find(handle) == metrics_map_.end()) {
metrics_map_[handle] = linked_ptr<PerProcessData>(new PerProcessData(
#if defined(OS_MACOSX)
scoped_ptr<base::ProcessMetrics>(
base::ProcessMetrics::CreateProcessMetrics(handle, NULL)),
#else
scoped_ptr<base::ProcessMetrics>(
base::ProcessMetrics::CreateProcessMetrics(handle)),
#endif
origin,
Profile::FromBrowserContext(rph->GetBrowserContext())));
}
linked_ptr<PerProcessData>& process_data = metrics_map_[handle];
process_data->set_last_cpu_percent(std::max(0.0,
cpu_usage_callback_.is_null() ? process_data->metrics()->GetCPUUsage()
: cpu_usage_callback_.Run(handle)));
process_data->set_seen_this_cycle(true);
}
// Copyright 2014 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_POWER_PROCESS_POWER_COLLECTOR_H_
#define CHROME_BROWSER_POWER_PROCESS_POWER_COLLECTOR_H_
#include <map>
#include "base/memory/linked_ptr.h"
#include "base/process/process_handle.h"
#include "base/process/process_metrics.h"
#include "base/timer/timer.h"
#include "components/power/origin_power_map_factory.h"
#include "url/gurl.h"
#if defined(OS_CHROMEOS)
#include "chromeos/dbus/power_manager_client.h"
#endif
class Profile;
namespace content {
class RenderProcessHost;
}
#if defined(OS_CHROMEOS)
namespace power_manager {
class PowerSupplyProperties;
}
#endif
// Manages regular updates of the profile power consumption.
class ProcessPowerCollector
#if defined(OS_CHROMEOS)
: public chromeos::PowerManagerClient::Observer
#endif
{
public:
class PerProcessData {
public:
PerProcessData(scoped_ptr<base::ProcessMetrics> metrics,
const GURL& origin,
Profile* profile);
PerProcessData();
~PerProcessData();
base::ProcessMetrics* metrics() const { return metrics_.get(); }
Profile* profile() const { return profile_; }
GURL last_origin() const { return last_origin_; }
int last_cpu_percent() const { return last_cpu_percent_; }
bool seen_this_cycle() const { return seen_this_cycle_; }
void set_last_cpu_percent(double new_cpu) { last_cpu_percent_ = new_cpu; }
void set_seen_this_cycle(bool seen) { seen_this_cycle_ = seen; }
private:
// |metrics_| holds the ProcessMetrics information for the given process.
scoped_ptr<base::ProcessMetrics> metrics_;
// |profile| is the profile that is visiting the |last_origin_|.
// It is not owned by PerProcessData.
Profile* profile_;
// |last_origin_| is the last origin visited by the process.
GURL last_origin_;
// |last_cpu_percent_| is the proportion of the CPU used since the last
// query.
double last_cpu_percent_;
// |seen_this_cycle| represents if the process still exists in this cycle.
// If it doesn't, we erase the PerProcessData.
bool seen_this_cycle_;
DISALLOW_COPY_AND_ASSIGN(PerProcessData);
};
// A map from all process handles to a metric.
typedef std::map<base::ProcessHandle, linked_ptr<PerProcessData> >
ProcessMetricsMap;
// A callback used to define mock CPU usage for testing.
typedef base::Callback<double(base::ProcessHandle)> CpuUsageCallback;
// On Chrome OS, can only be initialized after the DBusThreadManager has been
// initialized.
ProcessPowerCollector();
// On Chrome OS, can only be destroyed before DBusThreadManager is.
virtual ~ProcessPowerCollector();
void set_cpu_usage_callback_for_testing(const CpuUsageCallback& callback) {
cpu_usage_callback_ = callback;
}
ProcessMetricsMap* metrics_map_for_testing() { return &metrics_map_; }
#if defined(OS_CHROMEOS)
// PowerManagerClient::Observer implementation:
virtual void PowerChanged(
const power_manager::PowerSupplyProperties& prop) OVERRIDE;
#endif
// Begin periodically updating the power consumption numbers by profile.
void Initialize();
// Calls UpdatePowerConsumption() and returns the total CPU percent.
double UpdatePowerConsumptionForTesting();
private:
// Starts the timer for updating the power consumption.
void StartTimer();
// Calls SynchronizerProcesses() and RecordCpuUsageByOrigin() to update the
// |metrics_map_| and attribute power consumption. Invoked by |timer_| and as
// a helper method for UpdatePowerConsumptionForTesting().
double UpdatePowerConsumption();
// Calls UpdatePowerConsumption(). Invoked by |timer_|.
void HandleUpdateTimeout();
// Synchronizes the currently active processes to the |metrics_map_| and
// returns the total amount of cpu usage in the cycle.
double SynchronizeProcesses();
// Attributes the power usage to the profiles and origins using the
// information from SynchronizeProcesses() given a total amount
// of CPU used in this cycle, |total_cpu_percent|.
void RecordCpuUsageByOrigin(double total_cpu_percent);
// Adds the information from a given RenderProcessHost to the |metrics_map_|
// for a given origin. Called by SynchronizeProcesses().
void UpdateProcessInMap(const content::RenderProcessHost* render_process,
const GURL& origin);
ProcessMetricsMap metrics_map_;
base::RepeatingTimer<ProcessPowerCollector> timer_;
// Callback to use to get CPU usage if set.
CpuUsageCallback cpu_usage_callback_;
// The factor to scale the CPU usage by.
double scale_factor_;
DISALLOW_COPY_AND_ASSIGN(ProcessPowerCollector);
};
#endif // CHROME_BROWSER_POWER_PROCESS_POWER_COLLECTOR_H_
This diff is collapsed.
...@@ -870,6 +870,8 @@ ...@@ -870,6 +870,8 @@
'browser/platform_util_chromeos.cc', 'browser/platform_util_chromeos.cc',
'browser/platform_util_mac.mm', 'browser/platform_util_mac.mm',
'browser/platform_util_win.cc', 'browser/platform_util_win.cc',
'browser/power/process_power_collector.cc',
'browser/power/process_power_collector.h',
'browser/precache/most_visited_urls_provider.cc', 'browser/precache/most_visited_urls_provider.cc',
'browser/precache/most_visited_urls_provider.h', 'browser/precache/most_visited_urls_provider.h',
'browser/predictors/autocomplete_action_predictor.cc', 'browser/predictors/autocomplete_action_predictor.cc',
...@@ -2919,6 +2921,7 @@ ...@@ -2919,6 +2921,7 @@
'../components/components.gyp:keyed_service_content', '../components/components.gyp:keyed_service_content',
'../components/components.gyp:navigation_interception', '../components/components.gyp:navigation_interception',
'../components/components.gyp:password_manager_content_browser', '../components/components.gyp:password_manager_content_browser',
'../components/components.gyp:power',
'../components/components.gyp:precache_content', '../components/components.gyp:precache_content',
'../components/components.gyp:sessions', '../components/components.gyp:sessions',
'../components/components.gyp:storage_monitor', '../components/components.gyp:storage_monitor',
......
...@@ -1137,6 +1137,7 @@ ...@@ -1137,6 +1137,7 @@
'browser/policy/policy_path_parser_unittest.cc', 'browser/policy/policy_path_parser_unittest.cc',
'browser/policy/profile_policy_connector_unittest.cc', 'browser/policy/profile_policy_connector_unittest.cc',
'browser/policy/url_blacklist_manager_unittest.cc', 'browser/policy/url_blacklist_manager_unittest.cc',
'browser/power/process_power_collector_unittest.cc',
'browser/predictors/autocomplete_action_predictor_table_unittest.cc', 'browser/predictors/autocomplete_action_predictor_table_unittest.cc',
'browser/predictors/autocomplete_action_predictor_unittest.cc', 'browser/predictors/autocomplete_action_predictor_unittest.cc',
'browser/prefs/chrome_pref_service_unittest.cc', 'browser/prefs/chrome_pref_service_unittest.cc',
...@@ -2565,6 +2566,7 @@ ...@@ -2565,6 +2566,7 @@
'browser/process_singleton_posix_unittest.cc', 'browser/process_singleton_posix_unittest.cc',
'browser/profiles/off_the_record_profile_impl_unittest.cc', 'browser/profiles/off_the_record_profile_impl_unittest.cc',
'browser/profiles/profile_list_desktop_unittest.cc', 'browser/profiles/profile_list_desktop_unittest.cc',
'browser/power/process_power_collector_unittest.cc',
'browser/renderer_context_menu/render_view_context_menu_unittest.cc', 'browser/renderer_context_menu/render_view_context_menu_unittest.cc',
'browser/search/instant_service_unittest.cc', 'browser/search/instant_service_unittest.cc',
'browser/search/search_unittest.cc', 'browser/search/search_unittest.cc',
......
...@@ -122,6 +122,8 @@ void MockRenderProcessHost::DumpHandles() { ...@@ -122,6 +122,8 @@ void MockRenderProcessHost::DumpHandles() {
base::ProcessHandle MockRenderProcessHost::GetHandle() const { base::ProcessHandle MockRenderProcessHost::GetHandle() const {
// Return the current-process handle for the IPC::GetFileHandleForProcess // Return the current-process handle for the IPC::GetFileHandleForProcess
// function. // function.
if (process_handle)
return *process_handle;
return base::Process::Current().handle(); return base::Process::Current().handle();
} }
......
...@@ -103,6 +103,10 @@ class MockRenderProcessHost : public RenderProcessHost { ...@@ -103,6 +103,10 @@ class MockRenderProcessHost : public RenderProcessHost {
is_isolated_guest_ = is_isolated_guest; is_isolated_guest_ = is_isolated_guest;
} }
void SetProcessHandle(scoped_ptr<base::ProcessHandle> new_handle) {
process_handle = new_handle.Pass();
}
private: private:
// Stores IPC messages that would have been sent to the renderer. // Stores IPC messages that would have been sent to the renderer.
IPC::TestSink sink_; IPC::TestSink sink_;
...@@ -118,6 +122,7 @@ class MockRenderProcessHost : public RenderProcessHost { ...@@ -118,6 +122,7 @@ class MockRenderProcessHost : public RenderProcessHost {
bool fast_shutdown_started_; bool fast_shutdown_started_;
bool deletion_callback_called_; bool deletion_callback_called_;
bool is_isolated_guest_; bool is_isolated_guest_;
scoped_ptr<base::ProcessHandle> process_handle;
DISALLOW_COPY_AND_ASSIGN(MockRenderProcessHost); DISALLOW_COPY_AND_ASSIGN(MockRenderProcessHost);
}; };
......
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