OLD | NEW |
---|---|
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 #include "metrics_library.h" | 6 #include "metrics_library.h" |
7 | 7 |
8 #include <dbus/dbus-glib-lowlevel.h> | 8 #include <dbus/dbus-glib-lowlevel.h> |
9 #include <sys/file.h> | 9 #include <sys/file.h> |
10 | 10 |
(...skipping 19 matching lines...) Expand all Loading... | |
30 | 30 |
31 // The daily use monitor is scheduled to a 1-minute interval after | 31 // The daily use monitor is scheduled to a 1-minute interval after |
32 // initial user activity and then it's exponentially backed off to | 32 // initial user activity and then it's exponentially backed off to |
33 // 10-minute intervals. Although not required, the back off is | 33 // 10-minute intervals. Although not required, the back off is |
34 // implemented because the histogram buckets are spaced exponentially | 34 // implemented because the histogram buckets are spaced exponentially |
35 // anyway and to avoid too frequent metrics daemon process wake-ups | 35 // anyway and to avoid too frequent metrics daemon process wake-ups |
36 // and file I/O. | 36 // and file I/O. |
37 static const int kUseMonitorIntervalInit = 1 * kSecondsPerMinute; | 37 static const int kUseMonitorIntervalInit = 1 * kSecondsPerMinute; |
38 static const int kUseMonitorIntervalMax = 10 * kSecondsPerMinute; | 38 static const int kUseMonitorIntervalMax = 10 * kSecondsPerMinute; |
39 | 39 |
40 // static metrics parameters. | |
41 const char MetricsDaemon::kMetricDailyUseTimeName[] = | |
42 "Logging.DailyUseTime"; | |
43 const int MetricsDaemon::kMetricDailyUseTimeMin = 1; | |
44 const int MetricsDaemon::kMetricDailyUseTimeMax = kMinutesPerDay; | |
45 const int MetricsDaemon::kMetricDailyUseTimeBuckets = 50; | |
46 | |
47 const char MetricsDaemon::kMetricTimeToNetworkDropName[] = | |
48 "Network.TimeToDrop"; | |
49 const int MetricsDaemon::kMetricTimeToNetworkDropMin = 1; | |
50 const int MetricsDaemon::kMetricTimeToNetworkDropMax = | |
51 8 /* hours */ * kMinutesPerHour * kSecondsPerMinute; | |
52 const int MetricsDaemon::kMetricTimeToNetworkDropBuckets = 50; | |
53 | |
40 // static | 54 // static |
41 const char* MetricsDaemon::kDBusMatches_[] = { | 55 const char* MetricsDaemon::kDBusMatches_[] = { |
42 "type='signal'," | 56 "type='signal'," |
43 "sender='org.moblin.connman'," | 57 "sender='org.moblin.connman'," |
44 "interface='" DBUS_IFACE_CONNMAN_MANAGER "'," | 58 "interface='" DBUS_IFACE_CONNMAN_MANAGER "'," |
45 "path='/'," | 59 "path='/'," |
46 "member='StateChanged'", | 60 "member='StateChanged'", |
47 | 61 |
48 "type='signal'," | 62 "type='signal'," |
49 "interface='" DBUS_IFACE_POWER_MANAGER "'," | 63 "interface='" DBUS_IFACE_POWER_MANAGER "'," |
(...skipping 29 matching lines...) Expand all Loading... | |
79 #define STATE(name, capname) #name, | 93 #define STATE(name, capname) #name, |
80 #include "screensaver_states.h" | 94 #include "screensaver_states.h" |
81 }; | 95 }; |
82 | 96 |
83 // static | 97 // static |
84 const char* MetricsDaemon::kSessionStates_[] = { | 98 const char* MetricsDaemon::kSessionStates_[] = { |
85 #define STATE(name, capname) #name, | 99 #define STATE(name, capname) #name, |
86 #include "session_states.h" | 100 #include "session_states.h" |
87 }; | 101 }; |
88 | 102 |
89 void MetricsDaemon::Run(bool run_as_daemon, bool testing) { | 103 void MetricsDaemon::Run(bool run_as_daemon) { |
90 Init(testing); | 104 Init(false); |
91 if (!run_as_daemon || daemon(0, 0) == 0) { | 105 if (!run_as_daemon || daemon(0, 0) == 0) { |
92 Loop(); | 106 Loop(); |
93 } | 107 } |
94 } | 108 } |
95 | 109 |
96 void MetricsDaemon::Init(bool testing) { | 110 void MetricsDaemon::Init(bool testing) { |
97 testing_ = testing; | 111 testing_ = testing; |
112 daily_use_record_file_ = kDailyUseRecordFile; | |
113 | |
114 // Don't setup D-Bus and GLib in test mode. | |
115 if (testing) | |
116 return; | |
98 | 117 |
99 g_thread_init(NULL); | 118 g_thread_init(NULL); |
100 g_type_init(); | 119 g_type_init(); |
101 dbus_g_thread_init(); | 120 dbus_g_thread_init(); |
102 | 121 |
103 DBusError error; | 122 DBusError error; |
104 dbus_error_init(&error); | 123 dbus_error_init(&error); |
105 | 124 |
106 DBusConnection *connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); | 125 DBusConnection *connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); |
107 LOG_IF(FATAL, dbus_error_is_set(&error)) << | 126 LOG_IF(FATAL, dbus_error_is_set(&error)) << |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
185 | 204 |
186 return DBUS_HANDLER_RESULT_HANDLED; | 205 return DBUS_HANDLER_RESULT_HANDLED; |
187 } | 206 } |
188 | 207 |
189 void MetricsDaemon::NetStateChanged(const char* state_name, time_t now) { | 208 void MetricsDaemon::NetStateChanged(const char* state_name, time_t now) { |
190 DLOG(INFO) << "network state: " << state_name; | 209 DLOG(INFO) << "network state: " << state_name; |
191 | 210 |
192 NetworkState state = LookupNetworkState(state_name); | 211 NetworkState state = LookupNetworkState(state_name); |
193 | 212 |
194 // Logs the time in seconds between the network going online to | 213 // Logs the time in seconds between the network going online to |
195 // going offline in order to measure the mean time to network | 214 // going offline (or, more precisely, going not online) in order to |
196 // dropping. Going offline as part of suspend-to-RAM is not logged | 215 // measure the mean time to network dropping. Going offline as part |
197 // as network drop -- the assumption is that the message for | 216 // of suspend-to-RAM is not logged as network drop -- the assumption |
198 // suspend-to-RAM comes before the network offline message which | 217 // is that the message for suspend-to-RAM comes before the network |
199 // seems to and should be the case. | 218 // offline message which seems to and should be the case. |
200 if (state == kNetworkStateOffline && | 219 if (state != kNetworkStateOnline && |
201 network_state_ == kNetworkStateOnline && | 220 network_state_ == kNetworkStateOnline && |
202 power_state_ != kPowerStateMem) { | 221 power_state_ != kPowerStateMem) { |
203 int online_time = static_cast<int>(now - network_state_last_); | 222 int online_time = static_cast<int>(now - network_state_last_); |
204 PublishMetric("Network.TimeToDrop", online_time, | 223 PublishMetric(kMetricTimeToNetworkDropName, online_time, |
205 1, 8 /* hours */ * 60 * 60, 50); | 224 kMetricTimeToNetworkDropMin, |
225 kMetricTimeToNetworkDropMax, | |
226 kMetricTimeToNetworkDropBuckets); | |
206 } | 227 } |
207 | 228 |
208 network_state_ = state; | 229 network_state_ = state; |
209 network_state_last_ = now; | 230 network_state_last_ = now; |
210 } | 231 } |
211 | 232 |
212 MetricsDaemon::NetworkState | 233 MetricsDaemon::NetworkState |
213 MetricsDaemon::LookupNetworkState(const char* state_name) { | 234 MetricsDaemon::LookupNetworkState(const char* state_name) { |
214 for (int i = 0; i < kNumberNetworkStates; i++) { | 235 for (int i = 0; i < kNumberNetworkStates; i++) { |
215 if (strcmp(state_name, kNetworkStates_[i]) == 0) { | 236 if (strcmp(state_name, kNetworkStates_[i]) == 0) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
297 user_active_last_ = now; | 318 user_active_last_ = now; |
298 } | 319 } |
299 | 320 |
300 void MetricsDaemon::LogDailyUseRecord(int day, int seconds) { | 321 void MetricsDaemon::LogDailyUseRecord(int day, int seconds) { |
301 // If there's no new active use today and the last record in the | 322 // If there's no new active use today and the last record in the |
302 // usage aggregation file is today, there's nothing to do. | 323 // usage aggregation file is today, there's nothing to do. |
303 if (seconds == 0 && day == daily_use_day_last_) | 324 if (seconds == 0 && day == daily_use_day_last_) |
304 return; | 325 return; |
305 | 326 |
306 DLOG(INFO) << "day: " << day << " usage: " << seconds << " seconds"; | 327 DLOG(INFO) << "day: " << day << " usage: " << seconds << " seconds"; |
307 int fd = HANDLE_EINTR(open(kDailyUseRecordFile, | 328 int fd = HANDLE_EINTR(open(daily_use_record_file_, |
308 O_RDWR | O_CREAT, | 329 O_RDWR | O_CREAT, |
309 S_IRUSR | S_IWUSR)); | 330 S_IRUSR | S_IWUSR)); |
310 if (fd < 0) { | 331 if (fd < 0) { |
311 DLOG(WARNING) << "Unable to open the daily use file."; | 332 PLOG(WARNING) << "Unable to open the daily use file"; |
312 return; | 333 return; |
313 } | 334 } |
314 | 335 |
315 bool same_day = false; | 336 bool same_day = false; |
316 UseRecord record; | 337 UseRecord record; |
317 if (HANDLE_EINTR(read(fd, &record, sizeof(record))) == sizeof(record)) { | 338 if (HANDLE_EINTR(read(fd, &record, sizeof(record))) == sizeof(record)) { |
318 if (record.day_ == day) { | 339 if (record.day_ == day) { |
319 // If there's an existing record for today, aggregates the usage | 340 // If there's an existing record for today, aggregates the usage |
320 // time. | 341 // time. |
321 same_day = true; | 342 same_day = true; |
322 record.seconds_ += seconds; | 343 record.seconds_ += seconds; |
323 } else { | 344 } else { |
324 // If there's an existing record for a day in the past, rounds | 345 // If there's an existing record for a day in the past, rounds |
325 // the usage to the nearest minute and sends it to UMA. | 346 // the usage to the nearest minute and sends it to UMA. |
326 int minutes = | 347 int minutes = |
327 (record.seconds_ + kSecondsPerMinute / 2) / kSecondsPerMinute; | 348 (record.seconds_ + kSecondsPerMinute / 2) / kSecondsPerMinute; |
328 PublishMetric("Logging.DailyUseTime", | 349 PublishMetric(kMetricDailyUseTimeName, minutes, |
329 minutes, 1, kMinutesPerDay, 50); | 350 kMetricDailyUseTimeMin, |
351 kMetricDailyUseTimeMax, | |
352 kMetricDailyUseTimeBuckets); | |
330 | 353 |
331 // Truncates the usage file to ensure that no duplicate usage is | 354 // Truncates the usage file to ensure that no duplicate usage is |
332 // sent to UMA. | 355 // sent to UMA. |
333 LOG_IF(WARNING, HANDLE_EINTR(ftruncate(fd, 0)) != 0); | 356 PLOG_IF(WARNING, HANDLE_EINTR(ftruncate(fd, 0)) != 0); |
334 } | 357 } |
335 } | 358 } |
336 | 359 |
337 // Updates the use record in the daily usage file if there's new | 360 // Updates the use record in the daily usage file if there's new |
338 // usage today. | 361 // usage today. |
339 if (seconds > 0) { | 362 if (seconds > 0) { |
340 if (!same_day) { | 363 if (!same_day) { |
341 record.day_ = day; | 364 record.day_ = day; |
342 record.seconds_ = seconds; | 365 record.seconds_ = seconds; |
343 } | 366 } |
344 // else an already existing record for the same day will be | 367 // else an already existing record for the same day will be |
345 // overwritten with updated usage below. | 368 // overwritten with updated usage below. |
346 | 369 |
347 LOG_IF(WARNING, HANDLE_EINTR(lseek(fd, 0, SEEK_SET)) != 0); | 370 PLOG_IF(WARNING, HANDLE_EINTR(lseek(fd, 0, SEEK_SET)) != 0); |
348 LOG_IF(WARNING, | 371 PLOG_IF(WARNING, |
349 HANDLE_EINTR(write(fd, &record, sizeof(record))) != sizeof(record)); | 372 HANDLE_EINTR(write(fd, &record, sizeof(record))) != |
373 sizeof(record)); | |
350 } | 374 } |
351 | 375 |
352 HANDLE_EINTR(close(fd)); | 376 HANDLE_EINTR(close(fd)); |
353 | 377 |
354 // Remembers the day of the use record in the usage aggregation file | 378 // Remembers the day of the use record in the usage aggregation file |
355 // to reduce file I/O. This is not really useful now but potentially | 379 // to reduce file I/O. This is not really useful now but potentially |
356 // allows frequent LogDailyUseRecord calls with no unnecessary I/O | 380 // allows frequent LogDailyUseRecord calls with no unnecessary I/O |
357 // overhead. | 381 // overhead. |
358 daily_use_day_last_ = day; | 382 daily_use_day_last_ = day; |
359 } | 383 } |
360 | 384 |
361 // static | 385 // static |
362 gboolean MetricsDaemon::UseMonitorStatic(gpointer data) { | 386 gboolean MetricsDaemon::UseMonitorStatic(gpointer data) { |
363 return static_cast<MetricsDaemon*>(data)->UseMonitor() ? TRUE : FALSE; | 387 return static_cast<MetricsDaemon*>(data)->UseMonitor() ? TRUE : FALSE; |
364 } | 388 } |
365 | 389 |
366 bool MetricsDaemon::UseMonitor() { | 390 bool MetricsDaemon::UseMonitor() { |
367 SetUserActiveState(user_active_, time(NULL)); | 391 SetUserActiveState(user_active_, time(NULL)); |
368 | 392 |
369 // If a new monitor source/instance is scheduled, returns false to | 393 // If a new monitor source/instance is scheduled, returns false to |
370 // tell GLib to destroy this monitor source/instance. Returns true | 394 // tell GLib to destroy this monitor source/instance. Returns true |
371 // otherwise to keep calling back this monitor. | 395 // otherwise to keep calling back this monitor. |
372 return !ScheduleUseMonitor(usemon_interval_ * 2, /* backoff */ true); | 396 return !ScheduleUseMonitor(usemon_interval_ * 2, /* backoff */ true); |
373 } | 397 } |
374 | 398 |
375 bool MetricsDaemon::ScheduleUseMonitor(int interval, bool backoff) | 399 bool MetricsDaemon::ScheduleUseMonitor(int interval, bool backoff) |
376 { | 400 { |
401 if (testing_) | |
kmixter1
2010/05/10 19:06:31
Ideally you'd want to make this function available
| |
402 return false; | |
403 | |
377 // Caps the interval -- the bigger the interval, the more active use | 404 // Caps the interval -- the bigger the interval, the more active use |
378 // time will be potentially dropped on system shutdown. | 405 // time will be potentially dropped on system shutdown. |
379 if (interval > kUseMonitorIntervalMax) | 406 if (interval > kUseMonitorIntervalMax) |
380 interval = kUseMonitorIntervalMax; | 407 interval = kUseMonitorIntervalMax; |
381 | 408 |
382 if (backoff) { | 409 if (backoff) { |
383 // Back-off mode is used by the use monitor to reschedule itself | 410 // Back-off mode is used by the use monitor to reschedule itself |
384 // with exponential back-off in time. This mode doesn't create a | 411 // with exponential back-off in time. This mode doesn't create a |
385 // new timeout source if the new interval is the same as the old | 412 // new timeout source if the new interval is the same as the old |
386 // one. Also, if a new timeout source is created, the old one is | 413 // one. Also, if a new timeout source is created, the old one is |
(...skipping 23 matching lines...) Expand all Loading... | |
410 return; | 437 return; |
411 | 438 |
412 DLOG(INFO) << "destroying use monitor"; | 439 DLOG(INFO) << "destroying use monitor"; |
413 g_source_destroy(usemon_source_); | 440 g_source_destroy(usemon_source_); |
414 usemon_source_ = NULL; | 441 usemon_source_ = NULL; |
415 usemon_interval_ = 0; | 442 usemon_interval_ = 0; |
416 } | 443 } |
417 | 444 |
418 void MetricsDaemon::PublishMetric(const char* name, int sample, | 445 void MetricsDaemon::PublishMetric(const char* name, int sample, |
419 int min, int max, int nbuckets) { | 446 int min, int max, int nbuckets) { |
420 DLOG(INFO) << "received metric: " << name << " " << sample << " " | 447 LOG(INFO) << "received metric: " << name << " " << sample << " " |
421 << min << " " << max << " " << nbuckets; | 448 << min << " " << max << " " << nbuckets; |
422 if (!testing_) { | 449 if (!testing_) { |
423 MetricsLibrary::SendToChrome(name, sample, min, max, nbuckets); | 450 MetricsLibrary::SendToChrome(name, sample, min, max, nbuckets); |
424 } | 451 } |
425 } | 452 } |
OLD | NEW |