OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 #include "chrome/browser/power/process_power_collector.h" | |
sky
2014/08/25 20:43:43
nit: newline between 3/4.
Daniel Nishi
2014/08/25 21:08:33
Done.
| |
5 | |
6 #include "apps/app_window.h" | |
7 #include "apps/app_window_registry.h" | |
8 #include "base/process/process_handle.h" | |
9 #include "base/process/process_metrics.h" | |
10 #include "chrome/browser/browser_process.h" | |
11 #include "chrome/browser/profiles/profile.h" | |
12 #include "chrome/browser/profiles/profile_manager.h" | |
13 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" | |
14 #include "components/power/origin_power_map.h" | |
15 #include "components/power/origin_power_map_factory.h" | |
16 #include "content/public/browser/browser_context.h" | |
17 #include "content/public/browser/render_process_host.h" | |
18 #include "content/public/browser/web_contents.h" | |
19 #include "url/gurl.h" | |
20 | |
21 #if defined(OS_CHROMEOS) | |
22 #include "chromeos/dbus/dbus_thread_manager.h" | |
23 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h" | |
24 #endif | |
25 | |
26 namespace { | |
27 const int kSecondsPerSample = 30; | |
28 } | |
29 | |
30 ProcessPowerCollector::PerProcessData::PerProcessData( | |
31 scoped_ptr<base::ProcessMetrics> metrics, | |
32 const GURL& origin, | |
33 Profile* profile) | |
34 : metrics_(metrics.Pass()), | |
35 profile_(profile), | |
36 last_origin_(origin), | |
37 last_cpu_percent_(0), | |
38 seen_this_cycle_(true) { | |
39 } | |
40 | |
41 ProcessPowerCollector::PerProcessData::PerProcessData() | |
42 : profile_(NULL), | |
43 last_cpu_percent_(0.0), | |
44 seen_this_cycle_(false) { | |
45 } | |
46 | |
47 ProcessPowerCollector::PerProcessData::~PerProcessData() { | |
48 } | |
49 | |
50 ProcessPowerCollector::ProcessPowerCollector() | |
51 : scale_factor_(1.0), | |
52 is_initialized_(false) | |
53 { | |
54 #if defined(OS_CHROMEOS) | |
55 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( | |
56 this); | |
57 #endif | |
58 } | |
59 | |
60 ProcessPowerCollector::~ProcessPowerCollector() { | |
61 #if defined(OS_CHROMEOS) | |
62 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( | |
63 this); | |
64 #endif | |
65 } | |
66 | |
67 #if defined(OS_CHROMEOS) | |
68 void ProcessPowerCollector::PowerChanged( | |
69 const power_manager::PowerSupplyProperties& prop) { | |
70 if (prop.battery_state() == | |
71 power_manager::PowerSupplyProperties::DISCHARGING) { | |
72 if (is_initialized_ && !timer_.IsRunning()) | |
73 Initialize(); | |
sky
2014/08/25 19:38:39
Init/Initialize methods are generally one shot fun
Daniel Nishi
2014/08/25 20:19:24
Now in a StartTimer().
I've changed the |is_initi
sky
2014/08/25 20:43:43
This patchset had the Initialize() function. The e
Daniel Nishi
2014/08/25 21:08:33
Initialize() brought back, StartTimer() made priva
| |
74 scale_factor_ = prop.battery_discharge_rate(); | |
75 } else { | |
76 timer_.Stop(); | |
77 } | |
78 } | |
79 #endif | |
80 | |
81 void ProcessPowerCollector::Initialize() { | |
82 DCHECK(!timer_.IsRunning()); | |
83 is_initialized_ = true; | |
84 timer_.Start(FROM_HERE, | |
85 base::TimeDelta::FromSeconds(kSecondsPerSample), | |
86 this, | |
87 &ProcessPowerCollector::HandleUpdateTimeout); | |
88 } | |
89 | |
90 double ProcessPowerCollector::UpdatePowerConsumptionForTesting() { | |
91 return UpdatePowerConsumption(); | |
92 } | |
93 | |
94 double ProcessPowerCollector::UpdatePowerConsumption() { | |
95 double total_cpu_percent = SynchronizeProcesses(); | |
96 RecordCpuUsageByOrigin(total_cpu_percent); | |
97 return total_cpu_percent; | |
98 } | |
99 | |
100 void ProcessPowerCollector::HandleUpdateTimeout() { | |
101 UpdatePowerConsumption(); | |
102 } | |
103 | |
104 double ProcessPowerCollector::SynchronizeProcesses() { | |
105 // Update all tabs. | |
106 for (TabContentsIterator it; !it.done(); it.Next()) { | |
107 content::RenderProcessHost* render_process = it->GetRenderProcessHost(); | |
108 // Skip incognito web contents. | |
109 if (render_process->GetBrowserContext()->IsOffTheRecord()) | |
110 continue; | |
111 UpdateProcessInMap(render_process, it->GetLastCommittedURL().GetOrigin()); | |
112 } | |
113 | |
114 // Iterate over all profiles to find all app windows to attribute all apps. | |
115 ProfileManager* pm = g_browser_process->profile_manager(); | |
116 std::vector<Profile*> open_profiles = pm->GetLoadedProfiles(); | |
117 for (std::vector<Profile*>::const_iterator it = open_profiles.begin(); | |
118 it != open_profiles.end(); | |
119 ++it) { | |
120 const apps::AppWindowRegistry::AppWindowList& app_windows = | |
121 apps::AppWindowRegistry::Get(*it)->app_windows(); | |
122 for (apps::AppWindowRegistry::AppWindowList::const_iterator itr = | |
123 app_windows.begin(); | |
124 itr != app_windows.end(); | |
125 ++itr) { | |
126 content::WebContents* web_contents = (*itr)->web_contents(); | |
127 | |
128 UpdateProcessInMap(web_contents->GetRenderProcessHost(), | |
129 web_contents->GetLastCommittedURL().GetOrigin()); | |
130 } | |
131 } | |
132 | |
133 // Remove invalid processes and sum up the cpu cycle. | |
134 double total_cpu_percent = 0.0; | |
135 ProcessMetricsMap::iterator it = metrics_map_.begin(); | |
136 while (it != metrics_map_.end()) { | |
137 if (!it->second->seen_this_cycle()) { | |
138 metrics_map_.erase(it++); | |
139 continue; | |
140 } | |
141 | |
142 total_cpu_percent += it->second->last_cpu_percent(); | |
143 it++; | |
sky
2014/08/25 19:38:40
++it;
Daniel Nishi
2014/08/25 20:19:24
Done.
Daniel Nishi
2014/08/25 20:19:24
Done.
| |
144 } | |
145 | |
146 return total_cpu_percent; | |
147 } | |
148 | |
149 void ProcessPowerCollector::RecordCpuUsageByOrigin(double total_cpu_percent) { | |
150 for (ProcessMetricsMap::iterator it = metrics_map_.begin(); | |
sky
2014/08/25 19:38:40
nit: It's a bit weird to do this pass in a functio
Daniel Nishi
2014/08/25 20:19:24
Moved to call site.
| |
151 it != metrics_map_.end(); | |
152 ++it) { | |
153 // Invalidate the process for the next cycle. | |
154 it->second->set_seen_this_cycle(false); | |
155 } | |
156 | |
157 if (total_cpu_percent <= 0) | |
sky
2014/08/25 19:38:39
I could see the total being 0, but < 0? Isn't that
Daniel Nishi
2014/08/25 20:19:24
Changed to DCHECKing on less than, return on ==.
| |
158 return; | |
159 | |
160 for (ProcessMetricsMap::iterator it = metrics_map_.begin(); | |
161 it != metrics_map_.end(); | |
162 ++it) { | |
163 double last_process_power_usage = it->second->last_cpu_percent(); | |
164 last_process_power_usage *= scale_factor_ / total_cpu_percent; | |
165 | |
166 GURL origin = it->second->last_origin(); | |
167 power::OriginPowerMap* origin_power_map = | |
168 power::OriginPowerMapFactory::GetForBrowserContext( | |
169 it->second->profile()); | |
170 DCHECK(origin_power_map); | |
171 origin_power_map->AddPowerForOrigin(origin, last_process_power_usage); | |
172 } | |
173 } | |
174 | |
175 void ProcessPowerCollector::UpdateProcessInMap( | |
176 const content::RenderProcessHost* rph, | |
177 const GURL& origin) { | |
178 base::ProcessHandle handle = rph->GetHandle(); | |
179 if (metrics_map_.find(handle) == metrics_map_.end()) { | |
180 metrics_map_[handle] = linked_ptr<PerProcessData>(new PerProcessData( | |
181 #if defined(OS_MACOSX) | |
182 scoped_ptr<base::ProcessMetrics>( | |
183 base::ProcessMetrics::CreateProcessMetrics(handle, NULL)), | |
184 #else | |
185 scoped_ptr<base::ProcessMetrics>( | |
186 base::ProcessMetrics::CreateProcessMetrics(handle)), | |
187 #endif | |
188 origin, | |
189 Profile::FromBrowserContext(rph->GetBrowserContext()))); | |
190 } | |
191 | |
192 linked_ptr<PerProcessData>& process_data = metrics_map_[handle]; | |
193 process_data->set_last_cpu_percent( | |
194 cpu_usage_callback_.is_null() ? process_data->metrics()->GetCPUUsage() | |
sky
2014/08/25 19:38:40
Is GetCPUUsage an expensive call? Does it do IO or
Daniel Nishi
2014/08/25 20:19:24
It shouldn't be that costly -- in the Linux implem
| |
195 : cpu_usage_callback_.Run(handle)); | |
196 // Skip errors. | |
197 if (process_data->last_cpu_percent() < 0) | |
198 process_data->set_last_cpu_percent(0); | |
sky
2014/08/25 19:38:40
nit: std::max(0, ... on 193 would take care of thi
| |
199 process_data->set_seen_this_cycle(true); | |
200 } | |
OLD | NEW |