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

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: Rate -> PercentPerHour 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/metrics/histogram.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/sys_info.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/power_usage_monitor.h"
19 #include "content/public/browser/render_process_host.h"
20
21 namespace content {
22
23 namespace {
24
25 // Wait this long after power on before enabling power usage monitoring.
26 const int kMinUptimeMinutes = 30;
27
28 // Minimum discharge time after which we collect the discharge rate.
29 const int kMinDischargeMinutes = 30;
30
31 class PowerUsageMonitorSystemInterface
32 : public PowerUsageMonitor::SystemInterface {
33 public:
34 explicit PowerUsageMonitorSystemInterface(PowerUsageMonitor* owner)
35 : power_usage_monitor_(owner),
36 weak_ptr_factory_(this) {}
37 ~PowerUsageMonitorSystemInterface() override {}
38
39 void ScheduleHistogramReport(base::TimeDelta delay) override {
40 BrowserThread::PostDelayedTask(
41 BrowserThread::UI,
42 FROM_HERE,
43 base::Bind(
44 &PowerUsageMonitorSystemInterface::ReportBatteryLevelHistogram,
45 weak_ptr_factory_.GetWeakPtr(),
46 Now(),
47 delay),
48 delay);
49 }
50
51 void CancelPendingHistogramReports() override {
52 weak_ptr_factory_.InvalidateWeakPtrs();
53 }
54
55 void RecordDischargePercentPerHour(int percent_per_hour) override {
56 UMA_HISTOGRAM_PERCENTAGE("Power.BatteryDischargePercentPerHour",
57 percent_per_hour);
58 }
59
60 base::Time Now() override { return base::Time::Now(); }
61
62 protected:
63 void ReportBatteryLevelHistogram(base::Time start_time,
64 base::TimeDelta discharge_time) {
65 // It's conceivable that the code to cancel pending histogram reports on
66 // system suspend, will only get called after the system has woken up.
67 // To mitigage this, check whether more time has passed than expected and
68 // abort histogram recording in this case.
69
70 // Delayed tasks are subject to timer coalescing and can fire anywhere from
71 // delay -> delay * 1.5) . In most cases, the OS should fire the task
72 // at the next wakeup and not as late as it can.
73 // A threshold of 2 minutes is used, since that should be large enough to
74 // take the slop factor due to coalescing into account.
75 base::TimeDelta threshold = discharge_time +
76 base::TimeDelta::FromMinutes(2);
77 if ((Now() - start_time) > threshold) {
78 UMA_HISTOGRAM_BOOLEAN("Power.BatteryDischargeReportsCancelled", true);
79 return;
80 }
81
82 const std::string histogram_name = base::StringPrintf(
83 "Power.BatteryDischarge_%d", discharge_time.InMinutes());
84 base::HistogramBase* histogram =
85 base::Histogram::FactoryGet(histogram_name,
86 1,
87 100,
88 101,
89 base::Histogram::kUmaTargetedHistogramFlag);
90 double discharge_amount = power_usage_monitor_->discharge_amount();
91 histogram->Add(discharge_amount * 100);
92 }
93
94 private:
95 PowerUsageMonitor* power_usage_monitor_; // Not owned.
96
97 // Used to cancel in progress delayed tasks.
98 base::WeakPtrFactory<PowerUsageMonitorSystemInterface> weak_ptr_factory_;
99 };
100
101 } // namespace
102
103 void StartPowerUsageMonitor() {
104 static base::LazyInstance<PowerUsageMonitor>::Leaky monitor =
105 LAZY_INSTANCE_INITIALIZER;
106 monitor.Get().Start();
107 }
108
109 PowerUsageMonitor::PowerUsageMonitor()
110 : callback_(base::Bind(&PowerUsageMonitor::OnBatteryStatusUpdate,
111 base::Unretained(this))),
112 system_interface_(new PowerUsageMonitorSystemInterface(this)),
113 started_(false),
114 tracking_discharge_(false),
115 on_battery_power_(false),
116 initial_battery_level_(0),
117 current_battery_level_(0) {
118 }
119
120 PowerUsageMonitor::~PowerUsageMonitor() {
121 if (started_)
122 base::PowerMonitor::Get()->RemoveObserver(this);
123 }
124
125 void PowerUsageMonitor::Start() {
126 // Delay initialization until the system has been up for a while.
127 // This is to mitigate the effect of increased power draw during system start.
128 base::TimeDelta uptime =
129 base::TimeDelta::FromMilliseconds(base::SysInfo::Uptime());
130 base::TimeDelta min_uptime = base::TimeDelta::FromMinutes(kMinUptimeMinutes);
131 if (uptime < min_uptime) {
132 base::TimeDelta delay = min_uptime - uptime;
133 BrowserThread::PostDelayedTask(
134 BrowserThread::UI,
135 FROM_HERE,
136 base::Bind(&PowerUsageMonitor::StartInternal, base::Unretained(this)),
137 delay);
138 } else {
139 StartInternal();
140 }
141 }
142
143 void PowerUsageMonitor::StartInternal() {
144 DCHECK(!started_);
145 started_ = true;
146
147 // PowerMonitor is used to get suspend/resume notifications.
148 base::PowerMonitor::Get()->AddObserver(this);
149
150 registrar_.Add(this,
151 NOTIFICATION_RENDERER_PROCESS_CREATED,
152 NotificationService::AllBrowserContextsAndSources());
153 registrar_.Add(this,
154 NOTIFICATION_RENDERER_PROCESS_CLOSED,
155 NotificationService::AllBrowserContextsAndSources());
156 subscription_ =
157 device::BatteryStatusService::GetInstance()->AddCallback(callback_);
158 }
159
160 void PowerUsageMonitor::DischargeStarted(double battery_level) {
161 on_battery_power_ = true;
162
163 // If all browser windows are closed, don't report power metrics since
164 // Chrome's power draw is likely not significant.
165 if (live_renderer_ids_.empty())
166 return;
167
168 // Cancel any in-progress ReportBatteryLevelHistogram() calls.
169 system_interface_->CancelPendingHistogramReports();
170
171 tracking_discharge_ = true;
172 start_discharge_time_ = system_interface_->Now();
173
174 initial_battery_level_ = battery_level;
175 current_battery_level_ = battery_level;
176
177 const int kBatteryReportingIntervalMinutes[] = {5, 15, 30};
178 for (auto reporting_interval : kBatteryReportingIntervalMinutes) {
179 base::TimeDelta delay = base::TimeDelta::FromMinutes(reporting_interval);
180 system_interface_->ScheduleHistogramReport(delay);
181 }
182 }
183
184 void PowerUsageMonitor::WallPowerConnected(double battery_level) {
185 on_battery_power_ = false;
186
187 if (tracking_discharge_) {
188 DCHECK(!start_discharge_time_.is_null());
189 base::TimeDelta discharge_time =
190 system_interface_->Now() - start_discharge_time_;
191
192 if (discharge_time.InMinutes() > kMinDischargeMinutes) {
193 // Record the rate at which the battery discharged over the entire period
194 // the system was on battery power.
195 double discharge_hours = discharge_time.InMinutes() / 60.0;
Daniel Erat 2014/11/09 17:07:14 nit: delete extra space before '='. probably also
jeremy 2014/11/10 06:08:47 Done.
196 int percent_per_hour = (discharge_amount() / discharge_hours) * 100.0;
Daniel Erat 2014/11/09 17:07:14 i think you should round this value. i don't think
jeremy 2014/11/10 06:08:47 Changed to floor( + 0.5)
197 system_interface_->RecordDischargePercentPerHour(percent_per_hour);
198 }
199 }
200
201 // Cancel any in-progress ReportBatteryLevelHistogram() calls.
202 system_interface_->CancelPendingHistogramReports();
203
204 initial_battery_level_ = 0;
205 current_battery_level_ = 0;
206 start_discharge_time_ = base::Time();
207 tracking_discharge_ = false;
208 }
209
210 void PowerUsageMonitor::OnBatteryStatusUpdate(
211 const device::BatteryStatus& status) {
212 bool now_on_battery_power = (status.charging == 0);
213 bool was_on_battery_power = on_battery_power_;
214 double battery_level = status.level;
215
216 if (now_on_battery_power == was_on_battery_power) {
217 if (now_on_battery_power)
218 current_battery_level_ = battery_level;
219 return;
220 } else if (now_on_battery_power) { // Wall power disconnected.
221 DischargeStarted(battery_level);
222 } else { // Wall power connected.
223 WallPowerConnected(battery_level);
224 }
225 }
226
227 void PowerUsageMonitor::OnRenderProcessNotification(int type, int rph_id) {
228 size_t previous_num_live_renderers = live_renderer_ids_.size();
229
230 if (type == NOTIFICATION_RENDERER_PROCESS_CREATED) {
231 live_renderer_ids_.insert(rph_id);
232 } else if (type == NOTIFICATION_RENDERER_PROCESS_CLOSED) {
233 live_renderer_ids_.erase(rph_id);
234 } else {
235 NOTREACHED() << "Unexpected notification type: " << type;
236 }
237
238 if (live_renderer_ids_.empty() && previous_num_live_renderers != 0) {
239 // All render processes have died.
240 CancelPendingHistogramReporting();
241 tracking_discharge_ = false;
242 }
243
244 }
245
246 void PowerUsageMonitor::SetSystemInterfaceForTest(
247 scoped_ptr<SystemInterface> interface) {
248 system_interface_ = interface.Pass();
249 }
250
251 void PowerUsageMonitor::OnPowerStateChange(bool on_battery_power) {
252 }
253
254 void PowerUsageMonitor::OnResume() {
255 }
256
257 void PowerUsageMonitor::OnSuspend() {
258 CancelPendingHistogramReporting();
259 }
260
261 void PowerUsageMonitor::Observe(int type,
262 const NotificationSource& source,
263 const NotificationDetails& details) {
264 RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr();
265 OnRenderProcessNotification(type, rph->GetID());
266 }
267
268 void PowerUsageMonitor::CancelPendingHistogramReporting() {
269 // Cancel any in-progress histogram reports and reporting of discharge UMA.
270 system_interface_->CancelPendingHistogramReports();
271 }
272
273 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698