Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(234)

Side by Side Diff: content/browser/power_usage_monitor_impl.cc

Issue 560553005: Battery impact UMA (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Minor style fixes. Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
5 #include "content/browser/power_usage_monitor_impl.h"
6
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/time/time.h"
15 #include "content/common/battery_status_messages.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/notification_source.h"
19 #include "content/public/browser/notification_types.h"
20 #include "content/public/browser/power_usage_monitor.h"
21 #include "content/public/browser/render_process_host.h"
22
23 namespace {
24
25 class PowerUsageMonitorSystemInterface
26 : public content::PowerUsageMonitor::SystemInterface {
27 public:
28 PowerUsageMonitorSystemInterface(content::PowerUsageMonitor* owner)
29 : power_usage_monitor_(owner), weak_ptr_factory_(this) {}
Daniel Erat 2014/10/23 19:05:34 nit: one per line
jeremy 2014/10/27 08:25:12 Sorry, clang-format did it :(
30 virtual ~PowerUsageMonitorSystemInterface() {}
31
32 virtual void ScheduleHistogramReport(base::TimeDelta delay) override {
Daniel Erat 2014/10/23 19:05:34 omit 'virtual' when using 'override' (also below)
jeremy 2014/10/27 08:25:12 Done.
33 content::BrowserThread::PostDelayedTask(
34 content::BrowserThread::IO,
35 FROM_HERE,
36 base::Bind(
37 &PowerUsageMonitorSystemInterface::ReportBatteryLevelHistogram,
38 weak_ptr_factory_.GetWeakPtr(),
39 Now(),
40 delay),
41 delay);
42 }
43
44 virtual void CancelPendingHistogramReports() override {
45 weak_ptr_factory_.InvalidateWeakPtrs();
46 }
47
48 virtual base::Time Now() override { return base::Time::Now(); }
49
50 protected:
51 void ReportBatteryLevelHistogram(base::Time start_time,
52 base::TimeDelta discharge_time) override {
53 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
54
55 // Handle case of system suspend not cancelling histogram reports.
56 // When the system suspends, a task is posted to the IO thread to cancel all
57 // in progress calls to this function. The delayed task could conceivably
58 // race the cancelation.
59 // If the function is executed later than expected, then cancel.
60 base::TimeDelta threshold =
61 base::TimeDelta::FromSeconds(discharge_time.InSecondsF() * 1.5);
Daniel Erat 2014/10/23 19:05:34 what's the significance of 1.5 times the delay? wh
jeremy 2014/10/27 08:25:12 Changed to 2 minutes, added comment.
62 if ((Now() - start_time) > threshold) {
63 UMA_HISTOGRAM_BOOLEAN("Power.BatteryDischargeReportsCancelled", true);
64 return;
65 }
66
67 const std::string histogram_name = base::StringPrintf(
68 "Power.BatteryDischarge_%d", discharge_time.InMinutes());
69 base::HistogramBase* histogram =
70 base::Histogram::FactoryGet(histogram_name,
71 0,
Daniel Erat 2014/10/23 19:05:34 the docs for Histogram::FactoryGet() say that the
jeremy 2014/10/27 08:25:12 Done.
72 100,
73 102,
74 base::Histogram::kUmaTargetedHistogramFlag);
75 double discharge_amount = power_usage_monitor_->DischargeAmount();
76 histogram->Add(discharge_amount * 100);
77
78 power_usage_monitor_->BatteryLevelReported();
79 }
80
81 private:
82 content::PowerUsageMonitor* power_usage_monitor_; // Not owned.
83
84 // Used to cancel in progress timers.
Daniel Erat 2014/10/23 19:05:34 s/timers/delayed tasks/
jeremy 2014/10/27 08:25:12 Done.
85 base::WeakPtrFactory<PowerUsageMonitorSystemInterface> weak_ptr_factory_;
86 };
87
88 } // namespace
89
90 namespace content {
91
92 void StartPowerUsageMonitor() {
93 base::LazyInstance<PowerUsageMonitor>::Leaky monitor =
94 LAZY_INSTANCE_INITIALIZER;
95 monitor.Get().Start();
96 }
97
98 PowerUsageMonitor::PowerUsageMonitor()
99 : system_interface_(new PowerUsageMonitorSystemInterface(this)),
100 started_(false),
101 on_battery_power_(false),
102 initial_battery_level_(0),
103 current_battery_level_(0) {
104 // PowerUsageMonitor gets battery level information.
105 callback_ = base::Bind(&PowerUsageMonitor::OnBatteryStatusUpdate,
106 base::Unretained(this));
107 }
108
109 PowerUsageMonitor::~PowerUsageMonitor() {
110 if (started_)
111 base::PowerMonitor::Get()->RemoveObserver(this);
112 }
113
114 void PowerUsageMonitor::Start() {
115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
116
117 started_ = true;
118
119 // Power Monitor used to get suspend/resume notifications.
Daniel Erat 2014/10/23 19:05:34 nit: s/used/is used/
jeremy 2014/10/27 08:25:12 Done.
120 base::PowerMonitor::Get()->AddObserver(this);
121
122 registrar_.Add(this,
123 NOTIFICATION_RENDERER_PROCESS_CREATED,
124 NotificationService::AllBrowserContextsAndSources());
125
126 registrar_.Add(this,
127 NOTIFICATION_RENDERER_PROCESS_TERMINATED,
128 NotificationService::AllBrowserContextsAndSources());
129 registrar_.Add(this,
130 NOTIFICATION_RENDERER_PROCESS_CLOSED,
131 NotificationService::AllBrowserContextsAndSources());
132
133 BrowserThread::PostTask(
134 BrowserThread::IO,
135 FROM_HERE,
136 base::Bind(&PowerUsageMonitor::StartOnIOThread, base::Unretained(this)));
137 }
138
139 void PowerUsageMonitor::StartOnIOThread() {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
141 subscription_ = BatteryStatusService::GetInstance()->AddCallback(callback_);
142 }
143
144 void PowerUsageMonitor::DischargeStarted(double battery_level) {
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
146
147 // Cancel any in-progress ReportBatteryLevelHistogram() calls.
148 system_interface_->CancelPendingHistogramReports();
149
150 // Rate-limit power recording to once every 24 hours.
Daniel Erat 2014/10/23 19:05:34 this seems a bit strange in that histograms will b
jeremy 2014/10/27 08:25:11 The reason I added rate-limiting is so as not to c
151 if (!first_histogram_report_timestamp_.is_null()) {
152 base::TimeDelta time_since_last_report =
153 system_interface_->Now() - first_histogram_report_timestamp_;
154 if (time_since_last_report.InHours() < 24)
155 return;
156
157 // More than 24 hours have passed, reset timestamp.
158 first_histogram_report_timestamp_ = base::Time();
159 }
160
161 on_battery_power_ = true;
162 initial_battery_level_ = battery_level;
163 current_battery_level_ = battery_level;
164 start_discharge_time_ = system_interface_->Now();
165
166 const int kBatteryReportingIntervalMinutes[] = {5, 15, 30};
167 for (auto reporting_interval : kBatteryReportingIntervalMinutes) {
168 base::TimeDelta delay = base::TimeDelta::FromMinutes(reporting_interval);
169 system_interface_->ScheduleHistogramReport(delay);
170 }
171 }
172
173 void PowerUsageMonitor::WallPowerConnected(double battery_level) {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
175
176 // Cancel any in-progress ReportBatteryLevelHistogram() calls.
177 system_interface_->CancelPendingHistogramReports();
178
179 if (!start_discharge_time_.is_null()) {
180 base::TimeDelta discharge_time =
181 system_interface_->Now() - start_discharge_time_;
182 double discharge_percent = initial_battery_level_ - battery_level;
183 double discharge_rate = discharge_percent / discharge_time.InMinutes();
184
185 if (discharge_time.InMinutes() > 30)
186 UMA_HISTOGRAM_PERCENTAGE("Power.BatteryDischargeRateWhenUnplugged",
187 discharge_rate * 100.0);
188 }
189
190 on_battery_power_ = false;
191 initial_battery_level_ = 0;
192 current_battery_level_ = 0;
193 start_discharge_time_ = base::Time();
194 }
195
196 void PowerUsageMonitor::OnBatteryStatusUpdate(
197 const blink::WebBatteryStatus& status) {
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
199
200 bool now_on_battery_power = (status.charging == 0);
201 bool was_on_battery_power = on_battery_power_;
202 double battery_level = status.level;
203
204 if (now_on_battery_power == was_on_battery_power) {
205 if (now_on_battery_power)
206 current_battery_level_ = battery_level;
207 return;
208 } else if (now_on_battery_power) { // Wall power disconnected.
209 // If all browser windows are closed, don't report power metrics since
210 // Chrome's power draw is likely not significant.
211 if (live_renderer_ids_.size() > 0)
212 DischargeStarted(battery_level);
Daniel Erat 2014/10/23 19:05:34 i don't understand this. if this if condition is f
jeremy 2014/10/27 08:25:12 Moved to DischargeStarted(), OnBatteryStatusUpdate
213 } else { // Wall power connected.
214 WallPowerConnected(battery_level);
215 }
216 }
217
218 void PowerUsageMonitor::BatteryLevelReported() {
219 if (first_histogram_report_timestamp_.is_null()) {
220 // Record timestamp of first histogram report.
Daniel Erat 2014/10/23 19:05:34 delete unnecessary comment and omit curly brackets
jeremy 2014/10/27 08:25:12 Done.
221 first_histogram_report_timestamp_ = system_interface_->Now();
222 }
223 }
224
225 void PowerUsageMonitor::SetSystemInterfaceForTest(
226 scoped_ptr<SystemInterface> interface) {
227 system_interface_ = interface.Pass();
228 }
229
230 void PowerUsageMonitor::SetNumLiveRenderersForTest(int num_renderers) {
231 live_renderer_ids_.clear();
232 for (int i = 0; i < num_renderers; ++i) {
Daniel Erat 2014/10/23 19:05:34 nit: omit curly brackets
jeremy 2014/10/27 08:25:11 Done.
233 live_renderer_ids_.insert(1);
234 }
235 }
236
237 void PowerUsageMonitor::OnSuspend() {
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239
240 BrowserThread::PostTask(
241 BrowserThread::IO,
242 FROM_HERE,
243 base::Bind(&PowerUsageMonitor::CancelPendingHistogramRecording,
244 base::Unretained(this)));
245 }
246
247 void PowerUsageMonitor::Observe(int type,
248 const NotificationSource& source,
249 const NotificationDetails& details) {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
251
252 RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr();
253
254 size_t previous_num_live_renderers = live_renderer_ids_.size();
255
256 if (type == NOTIFICATION_RENDERER_PROCESS_CREATED) {
257 live_renderer_ids_.insert(rph->GetID());
258 } else if (type == NOTIFICATION_RENDERER_PROCESS_TERMINATED ||
259 type == NOTIFICATION_RENDERER_PROCESS_CLOSED) {
260 live_renderer_ids_.erase(rph->GetID());
261 }
262
263 size_t num_live_renderers = live_renderer_ids_.size();
264 if (num_live_renderers == 0 && previous_num_live_renderers != 0) {
265 // All render processes have died.
266 BrowserThread::PostTask(
267 BrowserThread::IO,
268 FROM_HERE,
269 base::Bind(&PowerUsageMonitor::CancelPendingHistogramRecording,
270 base::Unretained(this)));
271 }
272 }
273
274 void PowerUsageMonitor::CancelPendingHistogramRecording() {
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
276
277 // Cancel any in-progress histogram reports and reporting of discharge UMA.
278 system_interface_->CancelPendingHistogramReports();
279 start_discharge_time_ = base::Time();
280 }
281
282 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698