| Index: metrics_daemon.cc
|
| diff --git a/metrics_daemon.cc b/metrics_daemon.cc
|
| index a5059d9832bff092d4000a82746ba799f8759172..1e15e1dde7396490d42a473d4f94074583197350 100644
|
| --- a/metrics_daemon.cc
|
| +++ b/metrics_daemon.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "metrics_daemon.h"
|
|
|
| +#include <fcntl.h>
|
| #include <string.h>
|
|
|
| #include <base/file_util.h>
|
| @@ -84,6 +85,28 @@ const char MetricsDaemon::kMetricCrashFrequencyMin = 1;
|
| const char MetricsDaemon::kMetricCrashFrequencyMax = 100;
|
| const char MetricsDaemon::kMetricCrashFrequencyBuckets = 50;
|
|
|
| +// disk stats metrics
|
| +
|
| +// The {Read,Write}Sectors numbers are in sectors/second.
|
| +// A sector is usually 512 bytes.
|
| +
|
| +const char MetricsDaemon::kMetricReadSectorsLongName[] =
|
| + "Platform.ReadSectorsLong";
|
| +const char MetricsDaemon::kMetricWriteSectorsLongName[] =
|
| + "Platform.WriteSectorsLong";
|
| +const char MetricsDaemon::kMetricReadSectorsShortName[] =
|
| + "Platform.ReadSectorsShort";
|
| +const char MetricsDaemon::kMetricWriteSectorsShortName[] =
|
| + "Platform.WriteSectorsShort";
|
| +
|
| +const int MetricsDaemon::kMetricDiskStatsShortInterval = 1; // seconds
|
| +const int MetricsDaemon::kMetricDiskStatsLongInterval = 30; // seconds
|
| +
|
| +// Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte
|
| +// sectors.
|
| +const int MetricsDaemon::kMetricSectorsIOMax = 500000; // sectors/second
|
| +const int MetricsDaemon::kMetricSectorsBuckets = 50; // buckets
|
| +
|
| // persistent metrics path
|
| const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics";
|
|
|
| @@ -123,7 +146,8 @@ MetricsDaemon::MetricsDaemon()
|
| session_state_(kUnknownSessionState),
|
| user_active_(false),
|
| usemon_interval_(0),
|
| - usemon_source_(NULL) {}
|
| + usemon_source_(NULL),
|
| + diskstats_path_(NULL) {}
|
|
|
| MetricsDaemon::~MetricsDaemon() {
|
| DeleteFrequencyCounters();
|
| @@ -190,7 +214,8 @@ void MetricsDaemon::ConfigureCrashFrequencyReporter(
|
| frequency_counters_[histogram_name] = new_counter.release();
|
| }
|
|
|
| -void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) {
|
| +void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib,
|
| + const char* diskstats_path) {
|
| testing_ = testing;
|
| DCHECK(metrics_lib != NULL);
|
| metrics_lib_ = metrics_lib;
|
| @@ -218,6 +243,9 @@ void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) {
|
| ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName);
|
| ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName);
|
|
|
| + diskstats_path_ = diskstats_path;
|
| + DiskStatsReporterInit();
|
| +
|
| // Don't setup D-Bus and GLib in test mode.
|
| if (testing)
|
| return;
|
| @@ -494,6 +522,99 @@ void MetricsDaemon::UnscheduleUseMonitor() {
|
| usemon_interval_ = 0;
|
| }
|
|
|
| +void MetricsDaemon::DiskStatsReporterInit() {
|
| + DiskStatsReadStats(&read_sectors_, &write_sectors_);
|
| + // The first time around just run the long stat, so we don't delay boot.
|
| + diskstats_state_ = kDiskStatsLong;
|
| + ScheduleDiskStatsCallback(kMetricDiskStatsLongInterval);
|
| +}
|
| +
|
| +void MetricsDaemon::ScheduleDiskStatsCallback(int wait) {
|
| + if (testing_) {
|
| + return;
|
| + }
|
| + g_timeout_add_seconds(wait, DiskStatsCallbackStatic, this);
|
| +}
|
| +
|
| +void MetricsDaemon::DiskStatsReadStats(long int* read_sectors,
|
| + long int* write_sectors) {
|
| + int nchars;
|
| + int nitems;
|
| + char line[200];
|
| + int file = HANDLE_EINTR(open(diskstats_path_, O_RDONLY));
|
| + if (file < 0) {
|
| + PLOG(WARNING) << "cannot open " << diskstats_path_;
|
| + return;
|
| + }
|
| + nchars = HANDLE_EINTR(read(file, line, sizeof(line)));
|
| + if (nchars < 0) {
|
| + PLOG(WARNING) << "cannot read from " << diskstats_path_;
|
| + } else {
|
| + LOG_IF(WARNING, nchars == sizeof(line)) << "line too long in "
|
| + << diskstats_path_;
|
| + line[nchars] = '\0';
|
| + nitems = sscanf(line, "%*d %*d %ld %*d %*d %*d %ld",
|
| + read_sectors, write_sectors);
|
| + LOG_IF(WARNING, nitems != 2) << "found " << nitems << " items in "
|
| + << diskstats_path_ << ", expected 2";
|
| + }
|
| + HANDLE_EINTR(close(file));
|
| +}
|
| +
|
| +// static
|
| +gboolean MetricsDaemon::DiskStatsCallbackStatic(void* handle) {
|
| + (static_cast<MetricsDaemon*>(handle))->DiskStatsCallback();
|
| + return false; // one-time callback
|
| +}
|
| +
|
| +void MetricsDaemon::DiskStatsCallback() {
|
| + long int read_sectors_now, write_sectors_now;
|
| + DiskStatsReadStats(&read_sectors_now, &write_sectors_now);
|
| +
|
| + switch (diskstats_state_) {
|
| + case kDiskStatsShort:
|
| + SendMetric(kMetricReadSectorsShortName,
|
| + (int) (read_sectors_now - read_sectors_) /
|
| + kMetricDiskStatsShortInterval,
|
| + 1,
|
| + kMetricSectorsIOMax,
|
| + kMetricSectorsBuckets);
|
| + SendMetric(kMetricWriteSectorsShortName,
|
| + (int) (write_sectors_now - write_sectors_) /
|
| + kMetricDiskStatsShortInterval,
|
| + 1,
|
| + kMetricSectorsIOMax,
|
| + kMetricSectorsBuckets);
|
| + // Schedule long callback.
|
| + diskstats_state_ = kDiskStatsLong;
|
| + ScheduleDiskStatsCallback(kMetricDiskStatsLongInterval -
|
| + kMetricDiskStatsShortInterval);
|
| + break;
|
| + case kDiskStatsLong:
|
| + SendMetric(kMetricReadSectorsLongName,
|
| + (int) (read_sectors_now - read_sectors_) /
|
| + kMetricDiskStatsLongInterval,
|
| + 1,
|
| + kMetricSectorsIOMax,
|
| + kMetricSectorsBuckets);
|
| + SendMetric(kMetricWriteSectorsLongName,
|
| + (int) (write_sectors_now - write_sectors_) /
|
| + kMetricDiskStatsLongInterval,
|
| + 1,
|
| + kMetricSectorsIOMax,
|
| + kMetricSectorsBuckets);
|
| + // Reset sector counters
|
| + read_sectors_ = read_sectors_now;
|
| + write_sectors_ = write_sectors_now;
|
| + // Schedule short callback.
|
| + diskstats_state_ = kDiskStatsShort;
|
| + ScheduleDiskStatsCallback(kMetricDiskStatsShortInterval);
|
| + break;
|
| + default:
|
| + LOG(FATAL) << "Invalid disk stats state";
|
| + }
|
| +}
|
| +
|
| // static
|
| void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) {
|
| if (count <= 0)
|
|
|