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

Side by Side Diff: metrics_daemon.cc

Issue 2731008: Implement a persistent storage aggregation counter class. (Closed) Base URL: ssh://git@chromiumos-git/metrics.git
Patch Set: Address kmixter's comments. Created 10 years, 6 months 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
« no previous file with comments | « metrics_daemon.h ('k') | metrics_daemon_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "metrics_daemon.h" 5 #include "metrics_daemon.h"
6 6
7 #include <dbus/dbus-glib-lowlevel.h> 7 #include <dbus/dbus-glib-lowlevel.h>
8 #include <sys/file.h>
9 8
10 #include <base/eintr_wrapper.h>
11 #include <base/logging.h> 9 #include <base/logging.h>
12 10
11 #include "counter.h"
12
13 using base::Time; 13 using base::Time;
14 using base::TimeDelta; 14 using base::TimeDelta;
15 using base::TimeTicks; 15 using base::TimeTicks;
16 16
17 #define SAFE_MESSAGE(e) (e.message ? e.message : "unknown error") 17 #define SAFE_MESSAGE(e) (e.message ? e.message : "unknown error")
18 #define DBUS_IFACE_FLIMFLAM_MANAGER "org.chromium.flimflam.Manager" 18 #define DBUS_IFACE_FLIMFLAM_MANAGER "org.chromium.flimflam.Manager"
19 #define DBUS_IFACE_POWER_MANAGER "org.chromium.PowerManager" 19 #define DBUS_IFACE_POWER_MANAGER "org.chromium.PowerManager"
20 #define DBUS_IFACE_SESSION_MANAGER "org.chromium.SessionManagerInterface" 20 #define DBUS_IFACE_SESSION_MANAGER "org.chromium.SessionManagerInterface"
21 21
22 // File to aggregate daily usage before sending to UMA. 22 // File to aggregate daily usage before sending to UMA.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 #define STATE(name, capname) #name, 82 #define STATE(name, capname) #name,
83 #include "power_states.h" 83 #include "power_states.h"
84 }; 84 };
85 85
86 // static 86 // static
87 const char* MetricsDaemon::kSessionStates_[] = { 87 const char* MetricsDaemon::kSessionStates_[] = {
88 #define STATE(name, capname) #name, 88 #define STATE(name, capname) #name,
89 #include "session_states.h" 89 #include "session_states.h"
90 }; 90 };
91 91
92 MetricsDaemon::MetricsDaemon()
93 : network_state_(kUnknownNetworkState),
94 power_state_(kUnknownPowerState),
95 session_state_(kUnknownSessionState),
96 user_active_(false),
97 usemon_interval_(0),
98 usemon_source_(NULL) {}
99
100 MetricsDaemon::~MetricsDaemon() {}
101
92 void MetricsDaemon::Run(bool run_as_daemon) { 102 void MetricsDaemon::Run(bool run_as_daemon) {
93 if (!run_as_daemon || daemon(0, 0) == 0) { 103 if (!run_as_daemon || daemon(0, 0) == 0) {
94 Loop(); 104 Loop();
95 } 105 }
96 } 106 }
97 107
98 void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) { 108 void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) {
99 testing_ = testing; 109 testing_ = testing;
100 DCHECK(metrics_lib != NULL); 110 DCHECK(metrics_lib != NULL);
101 metrics_lib_ = metrics_lib; 111 metrics_lib_ = metrics_lib;
102 daily_use_record_file_ = kDailyUseRecordFile; 112 daily_use_.reset(new chromeos_metrics::TaggedCounter());
113 daily_use_->Init(kDailyUseRecordFile, &DailyUseReporter, this);
103 114
104 // Don't setup D-Bus and GLib in test mode. 115 // Don't setup D-Bus and GLib in test mode.
105 if (testing) 116 if (testing)
106 return; 117 return;
107 118
108 g_thread_init(NULL); 119 g_thread_init(NULL);
109 g_type_init(); 120 g_type_init();
110 dbus_g_thread_init(); 121 dbus_g_thread_init();
111 122
112 DBusError error; 123 DBusError error;
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 int seconds = 0; 287 int seconds = 0;
277 if (user_active_ && now > user_active_last_) { 288 if (user_active_ && now > user_active_last_) {
278 TimeDelta since_active = now - user_active_last_; 289 TimeDelta since_active = now - user_active_last_;
279 if (since_active < TimeDelta::FromSeconds( 290 if (since_active < TimeDelta::FromSeconds(
280 kUseMonitorIntervalMax + kSecondsPerMinute)) { 291 kUseMonitorIntervalMax + kSecondsPerMinute)) {
281 seconds = static_cast<int>(since_active.InSeconds()); 292 seconds = static_cast<int>(since_active.InSeconds());
282 } 293 }
283 } 294 }
284 TimeDelta since_epoch = now - Time(); 295 TimeDelta since_epoch = now - Time();
285 int day = since_epoch.InDays(); 296 int day = since_epoch.InDays();
286 LogDailyUseRecord(day, seconds); 297 daily_use_->Update(day, seconds);
287 298
288 // Schedules a use monitor on inactive->active transitions and 299 // Schedules a use monitor on inactive->active transitions and
289 // unschedules it on active->inactive transitions. 300 // unschedules it on active->inactive transitions.
290 if (!user_active_ && active) 301 if (!user_active_ && active)
291 ScheduleUseMonitor(kUseMonitorIntervalInit, /* backoff */ false); 302 ScheduleUseMonitor(kUseMonitorIntervalInit, /* backoff */ false);
292 else if (user_active_ && !active) 303 else if (user_active_ && !active)
293 UnscheduleUseMonitor(); 304 UnscheduleUseMonitor();
294 305
295 // Remembers the current active state and the time of the last 306 // Remembers the current active state and the time of the last
296 // activity update. 307 // activity update.
297 user_active_ = active; 308 user_active_ = active;
298 user_active_last_ = now; 309 user_active_last_ = now;
299 } 310 }
300 311
301 void MetricsDaemon::LogDailyUseRecord(int day, int seconds) {
302 // If there's no new active use today and the last record in the
303 // usage aggregation file is today, there's nothing to do.
304 if (seconds == 0 && day == daily_use_day_last_)
305 return;
306
307 DLOG(INFO) << "day: " << day << " usage: " << seconds << " seconds";
308 int fd = HANDLE_EINTR(open(daily_use_record_file_,
309 O_RDWR | O_CREAT,
310 S_IRUSR | S_IWUSR));
311 if (fd < 0) {
312 PLOG(WARNING) << "Unable to open the daily use file";
313 return;
314 }
315
316 bool same_day = false;
317 UseRecord record;
318 if (HANDLE_EINTR(read(fd, &record, sizeof(record))) == sizeof(record)) {
319 if (record.day_ == day) {
320 // If there's an existing record for today, aggregates the usage
321 // time.
322 same_day = true;
323 record.seconds_ += seconds;
324 } else {
325 // If there's an existing record for a day in the past, rounds
326 // the usage to the nearest minute and sends it to UMA.
327 int minutes =
328 (record.seconds_ + kSecondsPerMinute / 2) / kSecondsPerMinute;
329 SendMetric(kMetricDailyUseTimeName, minutes,
330 kMetricDailyUseTimeMin,
331 kMetricDailyUseTimeMax,
332 kMetricDailyUseTimeBuckets);
333
334 // Truncates the usage file to ensure that no duplicate usage is
335 // sent to UMA.
336 PLOG_IF(WARNING, HANDLE_EINTR(ftruncate(fd, 0)) != 0);
337 }
338 }
339
340 // Updates the use record in the daily usage file if there's new
341 // usage today.
342 if (seconds > 0) {
343 if (!same_day) {
344 record.day_ = day;
345 record.seconds_ = seconds;
346 }
347 // else an already existing record for the same day will be
348 // overwritten with updated usage below.
349
350 PLOG_IF(WARNING, HANDLE_EINTR(lseek(fd, 0, SEEK_SET)) != 0);
351 PLOG_IF(WARNING,
352 HANDLE_EINTR(write(fd, &record, sizeof(record))) !=
353 sizeof(record));
354 }
355
356 HANDLE_EINTR(close(fd));
357
358 // Remembers the day of the use record in the usage aggregation file
359 // to reduce file I/O. This is not really useful now but potentially
360 // allows frequent LogDailyUseRecord calls with no unnecessary I/O
361 // overhead.
362 daily_use_day_last_ = day;
363 }
364
365 // static 312 // static
366 gboolean MetricsDaemon::UseMonitorStatic(gpointer data) { 313 gboolean MetricsDaemon::UseMonitorStatic(gpointer data) {
367 return static_cast<MetricsDaemon*>(data)->UseMonitor() ? TRUE : FALSE; 314 return static_cast<MetricsDaemon*>(data)->UseMonitor() ? TRUE : FALSE;
368 } 315 }
369 316
370 bool MetricsDaemon::UseMonitor() { 317 bool MetricsDaemon::UseMonitor() {
371 SetUserActiveState(user_active_, Time::Now()); 318 SetUserActiveState(user_active_, Time::Now());
372 319
373 // If a new monitor source/instance is scheduled, returns false to 320 // If a new monitor source/instance is scheduled, returns false to
374 // tell GLib to destroy this monitor source/instance. Returns true 321 // tell GLib to destroy this monitor source/instance. Returns true
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 // If there's a use monitor scheduled already, destroys it. 362 // If there's a use monitor scheduled already, destroys it.
416 if (usemon_source_ == NULL) 363 if (usemon_source_ == NULL)
417 return; 364 return;
418 365
419 DLOG(INFO) << "destroying use monitor"; 366 DLOG(INFO) << "destroying use monitor";
420 g_source_destroy(usemon_source_); 367 g_source_destroy(usemon_source_);
421 usemon_source_ = NULL; 368 usemon_source_ = NULL;
422 usemon_interval_ = 0; 369 usemon_interval_ = 0;
423 } 370 }
424 371
372 // static
373 void MetricsDaemon::DailyUseReporter(void* handle, int tag, int count) {
374 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle);
375 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute;
376 daemon->SendMetric(kMetricDailyUseTimeName, minutes,
377 kMetricDailyUseTimeMin,
378 kMetricDailyUseTimeMax,
379 kMetricDailyUseTimeBuckets);
380 }
381
425 void MetricsDaemon::SendMetric(const std::string& name, int sample, 382 void MetricsDaemon::SendMetric(const std::string& name, int sample,
426 int min, int max, int nbuckets) { 383 int min, int max, int nbuckets) {
427 DLOG(INFO) << "received metric: " << name << " " << sample << " " 384 DLOG(INFO) << "received metric: " << name << " " << sample << " "
428 << min << " " << max << " " << nbuckets; 385 << min << " " << max << " " << nbuckets;
429 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); 386 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets);
430 } 387 }
OLDNEW
« no previous file with comments | « metrics_daemon.h ('k') | metrics_daemon_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698