Index: metrics_daemon.cc |
diff --git a/metrics_daemon.cc b/metrics_daemon.cc |
index a5059d9832bff092d4000a82746ba799f8759172..238754f39e3de10bdd334c149097a6c3afea8946 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,31 @@ 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[] = |
+ "Filesystem.ReadSectorsLong"; |
+const char MetricsDaemon::kMetricWriteSectorsLongName[] = |
+ "Filesystem.WriteSectorsLong"; |
+const char MetricsDaemon::kMetricReadSectorsShortName[] = |
+ "Filesystem.ReadSectorsShort"; |
+const char MetricsDaemon::kMetricWriteSectorsShortName[] = |
+ "Filesystem.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 |
+ |
+// Path to disk stats. |
+const char MetricsDaemon::kMetricsDiskStatsPath[] = "/sys/class/block/sda/stat"; |
petkov
2011/02/12 05:34:45
Unused? It seems that the current revision won't w
petkov
2011/02/13 17:28:47
Isn't this something like /sys/block/mmcblk0 on AR
Luigi Semenzato
2011/02/14 18:43:43
That path exists on my kaen, but the stats there s
|
+ |
// persistent metrics path |
const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics"; |
@@ -218,6 +244,8 @@ void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) { |
ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName); |
ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName); |
+ DiskStatsReporterInit(); |
+ |
// Don't setup D-Bus and GLib in test mode. |
if (testing) |
return; |
@@ -250,6 +278,12 @@ void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) { |
CHECK(dbus_connection_add_filter(connection, MessageFilter, this, NULL)); |
} |
+void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib, |
+ const char* diskstats_path) { |
+ diskstats_path_ = diskstats_path; |
+ Init(testing, metrics_lib); |
+} |
+ |
void MetricsDaemon::Loop() { |
GMainLoop* loop = g_main_loop_new(NULL, false); |
g_main_loop_run(loop); |
@@ -494,6 +528,104 @@ 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_; |
+ goto close_file; |
petkov
2011/02/12 05:34:45
goto is a bit evil. I'd suggestion two options:
-
Luigi Semenzato
2011/02/14 18:43:43
And a third option: an else clause. (It doesn't s
|
+ } |
+ 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"; |
+ close_file: |
+ 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_) { |
+ |
petkov
2011/02/12 05:34:45
remove blank line?
|
+ case kDiskStatsShort: |
+ SendMetric(kMetricReadSectorsShortName, |
+ (int) (read_sectors_now - read_sectors_) / |
+ kMetricDiskStatsShortInterval, |
+ 0, |
petkov
2011/02/12 05:34:45
I think 0 is invalid minimum for some reason-- min
|
+ kMetricSectorsIOMax, |
+ kMetricSectorsBuckets); |
+ SendMetric(kMetricWriteSectorsShortName, |
+ (int) (write_sectors_now - write_sectors_) / |
+ kMetricDiskStatsShortInterval, |
+ 0, |
+ kMetricSectorsIOMax, |
+ kMetricSectorsBuckets); |
+ // Schedule long callback. |
+ diskstats_state_ = kDiskStatsLong; |
+ ScheduleDiskStatsCallback(kMetricDiskStatsLongInterval - |
+ kMetricDiskStatsShortInterval); |
+ break; |
+ |
+ case kDiskStatsLong: |
+ SendMetric(kMetricReadSectorsLongName, |
+ (int) (read_sectors_now - read_sectors_) / |
+ kMetricDiskStatsLongInterval, |
+ 0, |
+ kMetricSectorsIOMax, |
+ kMetricSectorsBuckets); |
+ SendMetric(kMetricWriteSectorsLongName, |
+ (int) (write_sectors_now - write_sectors_) / |
+ kMetricDiskStatsLongInterval, |
+ 0, |
+ 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) |