| 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 | 6 |
| 7 #include <fcntl.h> |
| 7 #include <string.h> | 8 #include <string.h> |
| 8 | 9 |
| 9 #include <base/file_util.h> | 10 #include <base/file_util.h> |
| 10 #include <base/logging.h> | 11 #include <base/logging.h> |
| 11 #include <dbus/dbus-glib-lowlevel.h> | 12 #include <dbus/dbus-glib-lowlevel.h> |
| 12 | 13 |
| 13 #include "counter.h" | 14 #include "counter.h" |
| 14 | 15 |
| 15 using base::Time; | 16 using base::Time; |
| 16 using base::TimeDelta; | 17 using base::TimeDelta; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 const char MetricsDaemon::kMetricUncleanShutdownsWeeklyName[] = | 78 const char MetricsDaemon::kMetricUncleanShutdownsWeeklyName[] = |
| 78 "Logging.UncleanShutdownsWeekly"; | 79 "Logging.UncleanShutdownsWeekly"; |
| 79 const char MetricsDaemon::kMetricUserCrashesDailyName[] = | 80 const char MetricsDaemon::kMetricUserCrashesDailyName[] = |
| 80 "Logging.UserCrashesDaily"; | 81 "Logging.UserCrashesDaily"; |
| 81 const char MetricsDaemon::kMetricUserCrashesWeeklyName[] = | 82 const char MetricsDaemon::kMetricUserCrashesWeeklyName[] = |
| 82 "Logging.UserCrashesWeekly"; | 83 "Logging.UserCrashesWeekly"; |
| 83 const char MetricsDaemon::kMetricCrashFrequencyMin = 1; | 84 const char MetricsDaemon::kMetricCrashFrequencyMin = 1; |
| 84 const char MetricsDaemon::kMetricCrashFrequencyMax = 100; | 85 const char MetricsDaemon::kMetricCrashFrequencyMax = 100; |
| 85 const char MetricsDaemon::kMetricCrashFrequencyBuckets = 50; | 86 const char MetricsDaemon::kMetricCrashFrequencyBuckets = 50; |
| 86 | 87 |
| 88 // disk stats metrics |
| 89 |
| 90 // The {Read,Write}Sectors numbers are in sectors/second. |
| 91 // A sector is usually 512 bytes. |
| 92 |
| 93 const char MetricsDaemon::kMetricReadSectorsLongName[] = |
| 94 "Platform.ReadSectorsLong"; |
| 95 const char MetricsDaemon::kMetricWriteSectorsLongName[] = |
| 96 "Platform.WriteSectorsLong"; |
| 97 const char MetricsDaemon::kMetricReadSectorsShortName[] = |
| 98 "Platform.ReadSectorsShort"; |
| 99 const char MetricsDaemon::kMetricWriteSectorsShortName[] = |
| 100 "Platform.WriteSectorsShort"; |
| 101 |
| 102 const int MetricsDaemon::kMetricDiskStatsShortInterval = 1; // seconds |
| 103 const int MetricsDaemon::kMetricDiskStatsLongInterval = 30; // seconds |
| 104 |
| 105 // Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte |
| 106 // sectors. |
| 107 const int MetricsDaemon::kMetricSectorsIOMax = 500000; // sectors/second |
| 108 const int MetricsDaemon::kMetricSectorsBuckets = 50; // buckets |
| 109 |
| 87 // persistent metrics path | 110 // persistent metrics path |
| 88 const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics"; | 111 const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics"; |
| 89 | 112 |
| 90 | 113 |
| 91 // static | 114 // static |
| 92 const char* MetricsDaemon::kDBusMatches_[] = { | 115 const char* MetricsDaemon::kDBusMatches_[] = { |
| 93 "type='signal'," | 116 "type='signal'," |
| 94 "interface='" DBUS_IFACE_CRASH_REPORTER "'," | 117 "interface='" DBUS_IFACE_CRASH_REPORTER "'," |
| 95 "path='/'," | 118 "path='/'," |
| 96 "member='UserCrash'", | 119 "member='UserCrash'", |
| (...skipping 19 matching lines...) Expand all Loading... |
| 116 const char* MetricsDaemon::kSessionStates_[] = { | 139 const char* MetricsDaemon::kSessionStates_[] = { |
| 117 #define STATE(name, capname) #name, | 140 #define STATE(name, capname) #name, |
| 118 #include "session_states.h" | 141 #include "session_states.h" |
| 119 }; | 142 }; |
| 120 | 143 |
| 121 MetricsDaemon::MetricsDaemon() | 144 MetricsDaemon::MetricsDaemon() |
| 122 : power_state_(kUnknownPowerState), | 145 : power_state_(kUnknownPowerState), |
| 123 session_state_(kUnknownSessionState), | 146 session_state_(kUnknownSessionState), |
| 124 user_active_(false), | 147 user_active_(false), |
| 125 usemon_interval_(0), | 148 usemon_interval_(0), |
| 126 usemon_source_(NULL) {} | 149 usemon_source_(NULL), |
| 150 diskstats_path_(NULL) {} |
| 127 | 151 |
| 128 MetricsDaemon::~MetricsDaemon() { | 152 MetricsDaemon::~MetricsDaemon() { |
| 129 DeleteFrequencyCounters(); | 153 DeleteFrequencyCounters(); |
| 130 } | 154 } |
| 131 | 155 |
| 132 void MetricsDaemon::DeleteFrequencyCounters() { | 156 void MetricsDaemon::DeleteFrequencyCounters() { |
| 133 for (FrequencyCounters::iterator i = frequency_counters_.begin(); | 157 for (FrequencyCounters::iterator i = frequency_counters_.begin(); |
| 134 i != frequency_counters_.end(); ++i) { | 158 i != frequency_counters_.end(); ++i) { |
| 135 delete i->second; | 159 delete i->second; |
| 136 i->second = NULL; | 160 i->second = NULL; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 time_t cycle_duration = strstr(histogram_name, "Weekly") != NULL ? | 207 time_t cycle_duration = strstr(histogram_name, "Weekly") != NULL ? |
| 184 chromeos_metrics::kSecondsPerWeek : | 208 chromeos_metrics::kSecondsPerWeek : |
| 185 chromeos_metrics::kSecondsPerDay; | 209 chromeos_metrics::kSecondsPerDay; |
| 186 new_counter->Init( | 210 new_counter->Init( |
| 187 static_cast<chromeos_metrics::TaggedCounterInterface*>( | 211 static_cast<chromeos_metrics::TaggedCounterInterface*>( |
| 188 reporter.release()), | 212 reporter.release()), |
| 189 cycle_duration); | 213 cycle_duration); |
| 190 frequency_counters_[histogram_name] = new_counter.release(); | 214 frequency_counters_[histogram_name] = new_counter.release(); |
| 191 } | 215 } |
| 192 | 216 |
| 193 void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) { | 217 void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib, |
| 218 const char* diskstats_path) { |
| 194 testing_ = testing; | 219 testing_ = testing; |
| 195 DCHECK(metrics_lib != NULL); | 220 DCHECK(metrics_lib != NULL); |
| 196 metrics_lib_ = metrics_lib; | 221 metrics_lib_ = metrics_lib; |
| 197 chromeos_metrics::TaggedCounterReporter:: | 222 chromeos_metrics::TaggedCounterReporter:: |
| 198 SetMetricsLibraryInterface(metrics_lib); | 223 SetMetricsLibraryInterface(metrics_lib); |
| 199 | 224 |
| 200 static const char kDailyUseRecordFile[] = "/var/log/metrics/daily-usage"; | 225 static const char kDailyUseRecordFile[] = "/var/log/metrics/daily-usage"; |
| 201 daily_use_.reset(new chromeos_metrics::TaggedCounter()); | 226 daily_use_.reset(new chromeos_metrics::TaggedCounter()); |
| 202 daily_use_->Init(kDailyUseRecordFile, &ReportDailyUse, this); | 227 daily_use_->Init(kDailyUseRecordFile, &ReportDailyUse, this); |
| 203 | 228 |
| 204 ConfigureCrashIntervalReporter(kMetricKernelCrashIntervalName, | 229 ConfigureCrashIntervalReporter(kMetricKernelCrashIntervalName, |
| 205 &kernel_crash_interval_); | 230 &kernel_crash_interval_); |
| 206 ConfigureCrashIntervalReporter(kMetricUncleanShutdownIntervalName, | 231 ConfigureCrashIntervalReporter(kMetricUncleanShutdownIntervalName, |
| 207 &unclean_shutdown_interval_); | 232 &unclean_shutdown_interval_); |
| 208 ConfigureCrashIntervalReporter(kMetricUserCrashIntervalName, | 233 ConfigureCrashIntervalReporter(kMetricUserCrashIntervalName, |
| 209 &user_crash_interval_); | 234 &user_crash_interval_); |
| 210 | 235 |
| 211 DeleteFrequencyCounters(); | 236 DeleteFrequencyCounters(); |
| 212 ConfigureCrashFrequencyReporter(kMetricAnyCrashesDailyName); | 237 ConfigureCrashFrequencyReporter(kMetricAnyCrashesDailyName); |
| 213 ConfigureCrashFrequencyReporter(kMetricAnyCrashesWeeklyName); | 238 ConfigureCrashFrequencyReporter(kMetricAnyCrashesWeeklyName); |
| 214 ConfigureCrashFrequencyReporter(kMetricKernelCrashesDailyName); | 239 ConfigureCrashFrequencyReporter(kMetricKernelCrashesDailyName); |
| 215 ConfigureCrashFrequencyReporter(kMetricKernelCrashesWeeklyName); | 240 ConfigureCrashFrequencyReporter(kMetricKernelCrashesWeeklyName); |
| 216 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsDailyName); | 241 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsDailyName); |
| 217 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsWeeklyName); | 242 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsWeeklyName); |
| 218 ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName); | 243 ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName); |
| 219 ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName); | 244 ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName); |
| 220 | 245 |
| 246 diskstats_path_ = diskstats_path; |
| 247 DiskStatsReporterInit(); |
| 248 |
| 221 // Don't setup D-Bus and GLib in test mode. | 249 // Don't setup D-Bus and GLib in test mode. |
| 222 if (testing) | 250 if (testing) |
| 223 return; | 251 return; |
| 224 | 252 |
| 225 g_thread_init(NULL); | 253 g_thread_init(NULL); |
| 226 g_type_init(); | 254 g_type_init(); |
| 227 dbus_g_thread_init(); | 255 dbus_g_thread_init(); |
| 228 | 256 |
| 229 DBusError error; | 257 DBusError error; |
| 230 dbus_error_init(&error); | 258 dbus_error_init(&error); |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 // If there's a use monitor scheduled already, destroys it. | 515 // If there's a use monitor scheduled already, destroys it. |
| 488 if (usemon_source_ == NULL) | 516 if (usemon_source_ == NULL) |
| 489 return; | 517 return; |
| 490 | 518 |
| 491 DLOG(INFO) << "destroying use monitor"; | 519 DLOG(INFO) << "destroying use monitor"; |
| 492 g_source_destroy(usemon_source_); | 520 g_source_destroy(usemon_source_); |
| 493 usemon_source_ = NULL; | 521 usemon_source_ = NULL; |
| 494 usemon_interval_ = 0; | 522 usemon_interval_ = 0; |
| 495 } | 523 } |
| 496 | 524 |
| 525 void MetricsDaemon::DiskStatsReporterInit() { |
| 526 DiskStatsReadStats(&read_sectors_, &write_sectors_); |
| 527 // The first time around just run the long stat, so we don't delay boot. |
| 528 diskstats_state_ = kDiskStatsLong; |
| 529 ScheduleDiskStatsCallback(kMetricDiskStatsLongInterval); |
| 530 } |
| 531 |
| 532 void MetricsDaemon::ScheduleDiskStatsCallback(int wait) { |
| 533 if (testing_) { |
| 534 return; |
| 535 } |
| 536 g_timeout_add_seconds(wait, DiskStatsCallbackStatic, this); |
| 537 } |
| 538 |
| 539 void MetricsDaemon::DiskStatsReadStats(long int* read_sectors, |
| 540 long int* write_sectors) { |
| 541 int nchars; |
| 542 int nitems; |
| 543 char line[200]; |
| 544 int file = HANDLE_EINTR(open(diskstats_path_, O_RDONLY)); |
| 545 if (file < 0) { |
| 546 PLOG(WARNING) << "cannot open " << diskstats_path_; |
| 547 return; |
| 548 } |
| 549 nchars = HANDLE_EINTR(read(file, line, sizeof(line))); |
| 550 if (nchars < 0) { |
| 551 PLOG(WARNING) << "cannot read from " << diskstats_path_; |
| 552 } else { |
| 553 LOG_IF(WARNING, nchars == sizeof(line)) << "line too long in " |
| 554 << diskstats_path_; |
| 555 line[nchars] = '\0'; |
| 556 nitems = sscanf(line, "%*d %*d %ld %*d %*d %*d %ld", |
| 557 read_sectors, write_sectors); |
| 558 LOG_IF(WARNING, nitems != 2) << "found " << nitems << " items in " |
| 559 << diskstats_path_ << ", expected 2"; |
| 560 } |
| 561 HANDLE_EINTR(close(file)); |
| 562 } |
| 563 |
| 564 // static |
| 565 gboolean MetricsDaemon::DiskStatsCallbackStatic(void* handle) { |
| 566 (static_cast<MetricsDaemon*>(handle))->DiskStatsCallback(); |
| 567 return false; // one-time callback |
| 568 } |
| 569 |
| 570 void MetricsDaemon::DiskStatsCallback() { |
| 571 long int read_sectors_now, write_sectors_now; |
| 572 DiskStatsReadStats(&read_sectors_now, &write_sectors_now); |
| 573 |
| 574 switch (diskstats_state_) { |
| 575 case kDiskStatsShort: |
| 576 SendMetric(kMetricReadSectorsShortName, |
| 577 (int) (read_sectors_now - read_sectors_) / |
| 578 kMetricDiskStatsShortInterval, |
| 579 1, |
| 580 kMetricSectorsIOMax, |
| 581 kMetricSectorsBuckets); |
| 582 SendMetric(kMetricWriteSectorsShortName, |
| 583 (int) (write_sectors_now - write_sectors_) / |
| 584 kMetricDiskStatsShortInterval, |
| 585 1, |
| 586 kMetricSectorsIOMax, |
| 587 kMetricSectorsBuckets); |
| 588 // Schedule long callback. |
| 589 diskstats_state_ = kDiskStatsLong; |
| 590 ScheduleDiskStatsCallback(kMetricDiskStatsLongInterval - |
| 591 kMetricDiskStatsShortInterval); |
| 592 break; |
| 593 case kDiskStatsLong: |
| 594 SendMetric(kMetricReadSectorsLongName, |
| 595 (int) (read_sectors_now - read_sectors_) / |
| 596 kMetricDiskStatsLongInterval, |
| 597 1, |
| 598 kMetricSectorsIOMax, |
| 599 kMetricSectorsBuckets); |
| 600 SendMetric(kMetricWriteSectorsLongName, |
| 601 (int) (write_sectors_now - write_sectors_) / |
| 602 kMetricDiskStatsLongInterval, |
| 603 1, |
| 604 kMetricSectorsIOMax, |
| 605 kMetricSectorsBuckets); |
| 606 // Reset sector counters |
| 607 read_sectors_ = read_sectors_now; |
| 608 write_sectors_ = write_sectors_now; |
| 609 // Schedule short callback. |
| 610 diskstats_state_ = kDiskStatsShort; |
| 611 ScheduleDiskStatsCallback(kMetricDiskStatsShortInterval); |
| 612 break; |
| 613 default: |
| 614 LOG(FATAL) << "Invalid disk stats state"; |
| 615 } |
| 616 } |
| 617 |
| 497 // static | 618 // static |
| 498 void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) { | 619 void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) { |
| 499 if (count <= 0) | 620 if (count <= 0) |
| 500 return; | 621 return; |
| 501 | 622 |
| 502 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle); | 623 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle); |
| 503 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute; | 624 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute; |
| 504 daemon->SendMetric(kMetricDailyUseTimeName, minutes, | 625 daemon->SendMetric(kMetricDailyUseTimeName, minutes, |
| 505 kMetricDailyUseTimeMin, | 626 kMetricDailyUseTimeMin, |
| 506 kMetricDailyUseTimeMax, | 627 kMetricDailyUseTimeMax, |
| 507 kMetricDailyUseTimeBuckets); | 628 kMetricDailyUseTimeBuckets); |
| 508 } | 629 } |
| 509 | 630 |
| 510 void MetricsDaemon::SendMetric(const string& name, int sample, | 631 void MetricsDaemon::SendMetric(const string& name, int sample, |
| 511 int min, int max, int nbuckets) { | 632 int min, int max, int nbuckets) { |
| 512 DLOG(INFO) << "received metric: " << name << " " << sample << " " | 633 DLOG(INFO) << "received metric: " << name << " " << sample << " " |
| 513 << min << " " << max << " " << nbuckets; | 634 << min << " " << max << " " << nbuckets; |
| 514 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); | 635 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); |
| 515 } | 636 } |
| OLD | NEW |