summaryrefslogtreecommitdiffstats
path: root/metricsd
diff options
context:
space:
mode:
authorBertrand SIMONNET <bsimonnet@google.com>2015-09-29 11:07:24 -0700
committerBertrand SIMONNET <bsimonnet@google.com>2015-10-01 16:45:56 -0700
commit7a9640559b59cb4088b10f4a15e6ca80158abfe7 (patch)
tree537567e14c113d2d41c0d639367d8698fa106a1d /metricsd
parent659f5ade04a5a07347dfbec9db4ef97636f1ebfe (diff)
downloadcore-7a9640559b59cb4088b10f4a15e6ca80158abfe7.tar.gz
core-7a9640559b59cb4088b10f4a15e6ca80158abfe7.tar.bz2
core-7a9640559b59cb4088b10f4a15e6ca80158abfe7.zip
metricsd: Only collect metrics over a short period.
Instead of reporting the metrics over both a long and a short period, collect and report only over a short period. This makes the code simpler and the metrics easier to understand. Also move the collection out of metrics_daemon and into a separate collector to make it simpler to understand. BUG: 24464945 Change-Id: I17e52536aaa75321a5e34f42ed488545c2c3efde
Diffstat (limited to 'metricsd')
-rw-r--r--metricsd/Android.mk4
-rw-r--r--metricsd/collectors/averaged_statistics_collector.cc216
-rw-r--r--metricsd/collectors/averaged_statistics_collector.h79
-rw-r--r--metricsd/collectors/averaged_statistics_collector_test.cc99
-rw-r--r--metricsd/metrics_daemon.cc253
-rw-r--r--metricsd/metrics_daemon.h47
-rw-r--r--metricsd/metrics_daemon_test.cc61
7 files changed, 412 insertions, 347 deletions
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 03b5739c0..9fd27f527 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -26,6 +26,7 @@ metrics_client_sources := \
metrics_client.cc
metrics_daemon_sources := \
+ collectors/averaged_statistics_collector.cc \
collectors/disk_usage_collector.cc \
metrics_daemon.cc \
metrics_daemon_main.cc \
@@ -40,6 +41,8 @@ metrics_daemon_sources := \
serialization/serialization_utils.cc
metrics_tests_sources := \
+ collectors/averaged_statistics_collector.cc \
+ collectors/averaged_statistics_collector_test.cc \
collectors/disk_usage_collector.cc \
metrics_daemon.cc \
metrics_daemon_test.cc \
@@ -146,6 +149,7 @@ include $(BUILD_EXECUTABLE)
# ========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := metrics_tests
+LOCAL_CLANG := true
LOCAL_CFLAGS := $(metrics_CFLAGS)
LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
LOCAL_CPPFLAGS := $(metrics_CPPFLAGS) -Wno-sign-compare
diff --git a/metricsd/collectors/averaged_statistics_collector.cc b/metricsd/collectors/averaged_statistics_collector.cc
new file mode 100644
index 000000000..0931e7bd5
--- /dev/null
+++ b/metricsd/collectors/averaged_statistics_collector.cc
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "averaged_statistics_collector.h"
+
+#include <base/files/file_util.h>
+#include <base/files/file_path.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+
+#include "metrics_daemon.h"
+
+namespace {
+
+// disk stats metrics
+
+// The {Read,Write}Sectors numbers are in sectors/second.
+// A sector is usually 512 bytes.
+const char kReadSectorsHistogramName[] = "Platform.ReadSectors";
+const char kWriteSectorsHistogramName[] = "Platform.WriteSectors";
+const int kDiskMetricsStatItemCount = 11;
+
+// Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte
+// sectors.
+const int kSectorsIOMax = 500000; // sectors/second
+const int kSectorsBuckets = 50; // buckets
+
+// Page size is 4k, sector size is 0.5k. We're not interested in page fault
+// rates that the disk cannot sustain.
+const int kPageFaultsMax = kSectorsIOMax / 8; // Page faults/second
+const int kPageFaultsBuckets = 50;
+
+// Major page faults, i.e. the ones that require data to be read from disk.
+const char kPageFaultsHistogramName[] = "Platform.PageFaults";
+
+// Swap in and Swap out
+const char kSwapInHistogramName[] = "Platform.SwapIn";
+const char kSwapOutHistogramName[] = "Platform.SwapOut";
+
+const int kIntervalBetweenCollection = 60; // seconds
+const int kCollectionDuration = 1; // seconds
+
+} // namespace
+
+AveragedStatisticsCollector::AveragedStatisticsCollector(
+ MetricsLibraryInterface* metrics_library,
+ const std::string& diskstats_path,
+ const std::string& vmstats_path) :
+ metrics_lib_(metrics_library),
+ diskstats_path_(diskstats_path),
+ vmstats_path_(vmstats_path) {
+}
+
+void AveragedStatisticsCollector::ScheduleWait() {
+ base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ base::Bind(&AveragedStatisticsCollector::WaitCallback,
+ base::Unretained(this)),
+ base::TimeDelta::FromSeconds(
+ kIntervalBetweenCollection - kCollectionDuration));
+}
+
+void AveragedStatisticsCollector::ScheduleCollect() {
+ base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ base::Bind(&AveragedStatisticsCollector::CollectCallback,
+ base::Unretained(this)),
+ base::TimeDelta::FromSeconds(kCollectionDuration));
+}
+
+void AveragedStatisticsCollector::WaitCallback() {
+ ReadInitialValues();
+ ScheduleCollect();
+}
+
+void AveragedStatisticsCollector::CollectCallback() {
+ Collect();
+ ScheduleWait();
+}
+
+void AveragedStatisticsCollector::ReadInitialValues() {
+ stats_start_time_ = MetricsDaemon::GetActiveTime();
+ DiskStatsReadStats(&read_sectors_, &write_sectors_);
+ VmStatsReadStats(&vmstats_);
+}
+
+bool AveragedStatisticsCollector::DiskStatsReadStats(
+ uint64_t* read_sectors, uint64_t* write_sectors) {
+ CHECK(read_sectors);
+ CHECK(write_sectors);
+ std::string line;
+ if (diskstats_path_.empty()) {
+ return false;
+ }
+
+ if (!base::ReadFileToString(base::FilePath(diskstats_path_), &line)) {
+ PLOG(WARNING) << "Could not read disk stats from "
+ << diskstats_path_.value();
+ return false;
+ }
+
+ std::vector<std::string> parts = base::SplitString(
+ line, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (parts.size() != kDiskMetricsStatItemCount) {
+ LOG(ERROR) << "Could not parse disk stat correctly. Expected "
+ << kDiskMetricsStatItemCount << " elements but got "
+ << parts.size();
+ return false;
+ }
+ if (!base::StringToUint64(parts[2], read_sectors)) {
+ LOG(ERROR) << "Couldn't convert read sectors " << parts[2] << " to uint64";
+ return false;
+ }
+ if (!base::StringToUint64(parts[6], write_sectors)) {
+ LOG(ERROR) << "Couldn't convert write sectors " << parts[6] << " to uint64";
+ return false;
+ }
+
+ return true;
+}
+
+bool AveragedStatisticsCollector::VmStatsParseStats(
+ const char* stats, struct VmstatRecord* record) {
+ CHECK(stats);
+ CHECK(record);
+ base::StringPairs pairs;
+ base::SplitStringIntoKeyValuePairs(stats, ' ', '\n', &pairs);
+
+ for (base::StringPairs::iterator it = pairs.begin();
+ it != pairs.end(); ++it) {
+ if (it->first == "pgmajfault" &&
+ !base::StringToUint64(it->second, &record->page_faults)) {
+ return false;
+ }
+ if (it->first == "pswpin" &&
+ !base::StringToUint64(it->second, &record->swap_in)) {
+ return false;
+ }
+ if (it->first == "pswpout" &&
+ !base::StringToUint64(it->second, &record->swap_out)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool AveragedStatisticsCollector::VmStatsReadStats(struct VmstatRecord* stats) {
+ CHECK(stats);
+ std::string value_string;
+ if (!base::ReadFileToString(vmstats_path_, &value_string)) {
+ LOG(WARNING) << "cannot read " << vmstats_path_.value();
+ return false;
+ }
+ return VmStatsParseStats(value_string.c_str(), stats);
+}
+
+void AveragedStatisticsCollector::Collect() {
+ uint64_t read_sectors_now, write_sectors_now;
+ struct VmstatRecord vmstats_now;
+ double time_now = MetricsDaemon::GetActiveTime();
+ double delta_time = time_now - stats_start_time_;
+ bool diskstats_success = DiskStatsReadStats(&read_sectors_now,
+ &write_sectors_now);
+
+ int delta_read = read_sectors_now - read_sectors_;
+ int delta_write = write_sectors_now - write_sectors_;
+ int read_sectors_per_second = delta_read / delta_time;
+ int write_sectors_per_second = delta_write / delta_time;
+ bool vmstats_success = VmStatsReadStats(&vmstats_now);
+ uint64_t delta_faults = vmstats_now.page_faults - vmstats_.page_faults;
+ uint64_t delta_swap_in = vmstats_now.swap_in - vmstats_.swap_in;
+ uint64_t delta_swap_out = vmstats_now.swap_out - vmstats_.swap_out;
+ uint64_t page_faults_per_second = delta_faults / delta_time;
+ uint64_t swap_in_per_second = delta_swap_in / delta_time;
+ uint64_t swap_out_per_second = delta_swap_out / delta_time;
+ if (diskstats_success) {
+ metrics_lib_->SendToUMA(kReadSectorsHistogramName,
+ read_sectors_per_second,
+ 1,
+ kSectorsIOMax,
+ kSectorsBuckets);
+ metrics_lib_->SendToUMA(kWriteSectorsHistogramName,
+ write_sectors_per_second,
+ 1,
+ kSectorsIOMax,
+ kSectorsBuckets);
+ }
+ if (vmstats_success) {
+ metrics_lib_->SendToUMA(kPageFaultsHistogramName,
+ page_faults_per_second,
+ 1,
+ kPageFaultsMax,
+ kPageFaultsBuckets);
+ metrics_lib_->SendToUMA(kSwapInHistogramName,
+ swap_in_per_second,
+ 1,
+ kPageFaultsMax,
+ kPageFaultsBuckets);
+ metrics_lib_->SendToUMA(kSwapOutHistogramName,
+ swap_out_per_second,
+ 1,
+ kPageFaultsMax,
+ kPageFaultsBuckets);
+ }
+}
diff --git a/metricsd/collectors/averaged_statistics_collector.h b/metricsd/collectors/averaged_statistics_collector.h
new file mode 100644
index 000000000..753f70c7d
--- /dev/null
+++ b/metricsd/collectors/averaged_statistics_collector.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRICSD_COLLECTORS_AVERAGED_STATISTICS_COLLECTOR_H_
+#define METRICSD_COLLECTORS_AVERAGED_STATISTICS_COLLECTOR_H_
+
+#include "metrics/metrics_library.h"
+
+class AveragedStatisticsCollector {
+ public:
+ AveragedStatisticsCollector(MetricsLibraryInterface* metrics_library,
+ const std::string& diskstats_path,
+ const std::string& vmstat_path);
+
+ // Schedule a wait period.
+ void ScheduleWait();
+
+ // Schedule a collection period.
+ void ScheduleCollect();
+
+ // Callback used by the main loop.
+ void CollectCallback();
+
+ // Callback used by the main loop.
+ void WaitCallback();
+
+ // Read and store the initial values at the beginning of a collection cycle.
+ void ReadInitialValues();
+
+ // Collect the disk usage statistics and report them.
+ void Collect();
+
+ private:
+ friend class AveragedStatisticsTest;
+ FRIEND_TEST(AveragedStatisticsTest, ParseDiskStats);
+ FRIEND_TEST(AveragedStatisticsTest, ParseVmStats);
+
+ // Record for retrieving and reporting values from /proc/vmstat
+ struct VmstatRecord {
+ uint64_t page_faults; // major faults
+ uint64_t swap_in; // pages swapped in
+ uint64_t swap_out; // pages swapped out
+ };
+
+ // Read the disk read/write statistics for the main disk.
+ bool DiskStatsReadStats(uint64_t* read_sectors, uint64_t* write_sectors);
+
+ // Parse the content of the vmstats file into |record|.
+ bool VmStatsParseStats(const char* stats, struct VmstatRecord* record);
+
+ // Read the vmstats into |stats|.
+ bool VmStatsReadStats(struct VmstatRecord* stats);
+
+ MetricsLibraryInterface* metrics_lib_;
+ base::FilePath diskstats_path_;
+ base::FilePath vmstats_path_;
+
+ // Values observed at the beginning of the collection period.
+ uint64_t read_sectors_;
+ uint64_t write_sectors_;
+ struct VmstatRecord vmstats_;
+
+ double stats_start_time_;
+};
+
+#endif // METRICSD_COLLECTORS_AVERAGED_STATISTICS_COLLECTOR_H_
diff --git a/metricsd/collectors/averaged_statistics_collector_test.cc b/metricsd/collectors/averaged_statistics_collector_test.cc
new file mode 100644
index 000000000..9c97f0011
--- /dev/null
+++ b/metricsd/collectors/averaged_statistics_collector_test.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "averaged_statistics_collector.h"
+
+#include <inttypes.h>
+
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <base/memory/scoped_ptr.h>
+#include <base/strings/stringprintf.h>
+#include <gtest/gtest.h>
+
+
+static const char kFakeDiskStatsFormat[] =
+ " 1793 1788 %" PRIu64 " 105580 "
+ " 196 175 %" PRIu64 " 30290 "
+ " 0 44060 135850\n";
+static const uint64_t kFakeReadSectors[] = {80000, 100000};
+static const uint64_t kFakeWriteSectors[] = {3000, 4000};
+
+
+class AveragedStatisticsTest : public testing::Test {
+ protected:
+ std::string kFakeDiskStats0;
+ std::string kFakeDiskStats1;
+
+ virtual void SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ disk_stats_path_ = temp_dir_.path().Append("disk_stats");
+ collector_.reset(new AveragedStatisticsCollector(
+ &metrics_lib_, disk_stats_path_.value(), ""));
+
+ kFakeDiskStats0 = base::StringPrintf(kFakeDiskStatsFormat,
+ kFakeReadSectors[0],
+ kFakeWriteSectors[0]);
+ kFakeDiskStats1 = base::StringPrintf(kFakeDiskStatsFormat,
+ kFakeReadSectors[1],
+ kFakeWriteSectors[1]);
+
+ CreateFakeDiskStatsFile(kFakeDiskStats0);
+ }
+
+ // Creates or overwrites an input file containing fake disk stats.
+ void CreateFakeDiskStatsFile(const std::string& fake_stats) {
+ EXPECT_EQ(base::WriteFile(disk_stats_path_,
+ fake_stats.data(), fake_stats.size()),
+ fake_stats.size());
+ }
+
+ // Collector used for tests.
+ scoped_ptr<AveragedStatisticsCollector> collector_;
+
+ // Temporary directory used for tests.
+ base::ScopedTempDir temp_dir_;
+
+ // Path for the fake files.
+ base::FilePath disk_stats_path_;
+
+ MetricsLibrary metrics_lib_;
+};
+
+TEST_F(AveragedStatisticsTest, ParseDiskStats) {
+ uint64_t read_sectors_now, write_sectors_now;
+ CreateFakeDiskStatsFile(kFakeDiskStats0);
+ ASSERT_TRUE(collector_->DiskStatsReadStats(&read_sectors_now,
+ &write_sectors_now));
+ EXPECT_EQ(read_sectors_now, kFakeReadSectors[0]);
+ EXPECT_EQ(write_sectors_now, kFakeWriteSectors[0]);
+
+ CreateFakeDiskStatsFile(kFakeDiskStats1);
+ ASSERT_TRUE(collector_->DiskStatsReadStats(&read_sectors_now,
+ &write_sectors_now));
+ EXPECT_EQ(read_sectors_now, kFakeReadSectors[1]);
+ EXPECT_EQ(write_sectors_now, kFakeWriteSectors[1]);
+}
+
+TEST_F(AveragedStatisticsTest, ParseVmStats) {
+ static char kVmStats[] = "pswpin 1345\npswpout 8896\n"
+ "foo 100\nbar 200\npgmajfault 42\netcetc 300\n";
+ struct AveragedStatisticsCollector::VmstatRecord stats;
+ EXPECT_TRUE(collector_->VmStatsParseStats(kVmStats, &stats));
+ EXPECT_EQ(stats.page_faults, 42);
+ EXPECT_EQ(stats.swap_in, 1345);
+ EXPECT_EQ(stats.swap_out, 8896);
+}
diff --git a/metricsd/metrics_daemon.cc b/metricsd/metrics_daemon.cc
index 3b81cf824..9eb680213 100644
--- a/metricsd/metrics_daemon.cc
+++ b/metricsd/metrics_daemon.cc
@@ -16,10 +16,6 @@
#include "metrics_daemon.h"
-#include <fcntl.h>
-#include <inttypes.h>
-#include <math.h>
-#include <string.h>
#include <sysexits.h>
#include <time.h>
@@ -71,48 +67,12 @@ const char kKernelCrashDetectedFile[] = "/var/run/kernel-crash-detected";
const char kUncleanShutdownDetectedFile[] =
"/var/run/unclean-shutdown-detected";
-// disk stats metrics
-
-// The {Read,Write}Sectors numbers are in sectors/second.
-// A sector is usually 512 bytes.
-
-const char kMetricReadSectorsLongName[] = "Platform.ReadSectors.PerMinute";
-const char kMetricWriteSectorsLongName[] = "Platform.WriteSectors.PerMinute";
-const char kMetricReadSectorsShortName[] = "Platform.ReadSectors.PerSecond";
-const char kMetricWriteSectorsShortName[] = "Platform.WriteSectors.PerSecond";
-
-const int kMetricStatsShortInterval = 1; // seconds
-const int kMetricStatsLongInterval = 60; // seconds
-
const int kMetricMeminfoInterval = 30; // seconds
-// Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte
-// sectors.
-const int kMetricSectorsIOMax = 500000; // sectors/second
-const int kMetricSectorsBuckets = 50; // buckets
-// Page size is 4k, sector size is 0.5k. We're not interested in page fault
-// rates that the disk cannot sustain.
-const int kMetricPageFaultsMax = kMetricSectorsIOMax / 8;
-const int kMetricPageFaultsBuckets = 50;
-
-// Major page faults, i.e. the ones that require data to be read from disk.
-
-const char kMetricPageFaultsLongName[] = "Platform.PageFaults.PerMinute";
-const char kMetricPageFaultsShortName[] = "Platform.PageFaults.PerSecond";
-
-// Swap in and Swap out
-
-const char kMetricSwapInLongName[] = "Platform.SwapIn.PerMinute";
-const char kMetricSwapInShortName[] = "Platform.SwapIn.PerSecond";
-
-const char kMetricSwapOutLongName[] = "Platform.SwapOut.PerMinute";
-const char kMetricSwapOutShortName[] = "Platform.SwapOut.PerSecond";
-
const char kMetricsProcStatFileName[] = "/proc/stat";
-const char kVmStatFileName[] = "/proc/vmstat";
const char kMeminfoFileName[] = "/proc/meminfo";
+const char kVmStatFileName[] = "/proc/vmstat";
const int kMetricsProcStatFirstLineItemsCount = 11;
-const int kDiskMetricsStatItemCount = 11;
// Thermal CPU throttling.
@@ -142,17 +102,13 @@ static const int kMemuseIntervals[] = {
MetricsDaemon::MetricsDaemon()
: memuse_final_time_(0),
memuse_interval_index_(0),
- read_sectors_(0),
- write_sectors_(0),
- vmstats_(),
- stats_state_(kStatsShort),
- stats_initial_time_(0),
ticks_per_second_(0),
latest_cpu_use_ticks_(0) {}
MetricsDaemon::~MetricsDaemon() {
}
+// static
double MetricsDaemon::GetActiveTime() {
struct timespec ts;
int r = clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -275,14 +231,12 @@ void MetricsDaemon::Init(bool testing,
weekly_cycle_.reset(new PersistentInteger("weekly.cycle"));
version_cycle_.reset(new PersistentInteger("version.cycle"));
- diskstats_path_ = diskstats_path;
scaling_max_freq_path_ = scaling_max_freq_path;
cpuinfo_max_freq_path_ = cpuinfo_max_freq_path;
disk_usage_collector_.reset(new DiskUsageCollector(metrics_lib_));
-
- // If testing, initialize Stats Reporter without connecting DBus
- if (testing_)
- StatsReporterInit();
+ averaged_stats_collector_.reset(
+ new AveragedStatisticsCollector(metrics_lib_, diskstats_path,
+ kVmStatFileName));
}
int MetricsDaemon::OnInit() {
@@ -494,94 +448,12 @@ bool MetricsDaemon::CheckSystemCrash(const string& crash_file) {
void MetricsDaemon::StatsReporterInit() {
disk_usage_collector_->Schedule();
- DiskStatsReadStats(&read_sectors_, &write_sectors_);
- VmStatsReadStats(&vmstats_);
- // The first time around just run the long stat, so we don't delay boot.
- stats_state_ = kStatsLong;
- stats_initial_time_ = GetActiveTime();
- if (stats_initial_time_ < 0) {
- LOG(WARNING) << "not collecting disk stats";
- } else {
- ScheduleStatsCallback(kMetricStatsLongInterval);
- }
-}
-void MetricsDaemon::ScheduleStatsCallback(int wait) {
- if (testing_) {
- return;
- }
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&MetricsDaemon::StatsCallback, base::Unretained(this)),
- base::TimeDelta::FromSeconds(wait));
+ // Don't start a collection cycle during the first run to avoid delaying the
+ // boot.
+ averaged_stats_collector_->ScheduleWait();
}
-bool MetricsDaemon::DiskStatsReadStats(uint64_t* read_sectors,
- uint64_t* write_sectors) {
- CHECK(read_sectors);
- CHECK(write_sectors);
- std::string line;
- if (diskstats_path_.empty()) {
- return false;
- }
-
- if (!base::ReadFileToString(base::FilePath(diskstats_path_), &line)) {
- PLOG(WARNING) << "Could not read disk stats from " << diskstats_path_;
- return false;
- }
-
- std::vector<std::string> parts = base::SplitString(
- line, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- if (parts.size() != kDiskMetricsStatItemCount) {
- LOG(ERROR) << "Could not parse disk stat correctly. Expected "
- << kDiskMetricsStatItemCount << " elements but got "
- << parts.size();
- return false;
- }
- if (!base::StringToUint64(parts[2], read_sectors)) {
- LOG(ERROR) << "Couldn't convert read sectors " << parts[2] << " to uint64";
- return false;
- }
- if (!base::StringToUint64(parts[6], write_sectors)) {
- LOG(ERROR) << "Couldn't convert write sectors " << parts[6] << " to uint64";
- return false;
- }
-
- return true;
-}
-
-bool MetricsDaemon::VmStatsParseStats(const char* stats,
- struct VmstatRecord* record) {
- CHECK(stats);
- CHECK(record);
- base::StringPairs pairs;
- base::SplitStringIntoKeyValuePairs(stats, ' ', '\n', &pairs);
-
- for (base::StringPairs::iterator it = pairs.begin(); it != pairs.end(); ++it) {
- if (it->first == "pgmajfault" &&
- !base::StringToUint64(it->second, &record->page_faults_)) {
- return false;
- }
- if (it->first == "pswpin" &&
- !base::StringToUint64(it->second, &record->swap_in_)) {
- return false;
- }
- if (it->first == "pswpout" &&
- !base::StringToUint64(it->second, &record->swap_out_)) {
- return false;
- }
- }
- return true;
-}
-
-bool MetricsDaemon::VmStatsReadStats(struct VmstatRecord* stats) {
- CHECK(stats);
- string value_string;
- if (!base::ReadFileToString(base::FilePath(kVmStatFileName), &value_string)) {
- LOG(WARNING) << "cannot read " << kVmStatFileName;
- return false;
- }
- return VmStatsParseStats(value_string.c_str(), stats);
-}
bool MetricsDaemon::ReadFreqToInt(const string& sysfs_file_name, int* value) {
const FilePath sysfs_path(sysfs_file_name);
@@ -639,115 +511,6 @@ void MetricsDaemon::SendCpuThrottleMetrics() {
SendLinearSample(kMetricScaledCpuFrequencyName, percent, 101, 102);
}
-// Collects disk and vm stats alternating over a short and a long interval.
-
-void MetricsDaemon::StatsCallback() {
- uint64_t read_sectors_now, write_sectors_now;
- struct VmstatRecord vmstats_now;
- double time_now = GetActiveTime();
- double delta_time = time_now - stats_initial_time_;
- if (testing_) {
- // Fake the time when testing.
- delta_time = stats_state_ == kStatsShort ?
- kMetricStatsShortInterval : kMetricStatsLongInterval;
- }
- bool diskstats_success = DiskStatsReadStats(&read_sectors_now,
- &write_sectors_now);
- int delta_read = read_sectors_now - read_sectors_;
- int delta_write = write_sectors_now - write_sectors_;
- int read_sectors_per_second = delta_read / delta_time;
- int write_sectors_per_second = delta_write / delta_time;
- bool vmstats_success = VmStatsReadStats(&vmstats_now);
- uint64_t delta_faults = vmstats_now.page_faults_ - vmstats_.page_faults_;
- uint64_t delta_swap_in = vmstats_now.swap_in_ - vmstats_.swap_in_;
- uint64_t delta_swap_out = vmstats_now.swap_out_ - vmstats_.swap_out_;
- uint64_t page_faults_per_second = delta_faults / delta_time;
- uint64_t swap_in_per_second = delta_swap_in / delta_time;
- uint64_t swap_out_per_second = delta_swap_out / delta_time;
-
- switch (stats_state_) {
- case kStatsShort:
- if (diskstats_success) {
- SendSample(kMetricReadSectorsShortName,
- read_sectors_per_second,
- 1,
- kMetricSectorsIOMax,
- kMetricSectorsBuckets);
- SendSample(kMetricWriteSectorsShortName,
- write_sectors_per_second,
- 1,
- kMetricSectorsIOMax,
- kMetricSectorsBuckets);
- }
- if (vmstats_success) {
- SendSample(kMetricPageFaultsShortName,
- page_faults_per_second,
- 1,
- kMetricPageFaultsMax,
- kMetricPageFaultsBuckets);
- SendSample(kMetricSwapInShortName,
- swap_in_per_second,
- 1,
- kMetricPageFaultsMax,
- kMetricPageFaultsBuckets);
- SendSample(kMetricSwapOutShortName,
- swap_out_per_second,
- 1,
- kMetricPageFaultsMax,
- kMetricPageFaultsBuckets);
- }
- // Schedule long callback.
- stats_state_ = kStatsLong;
- ScheduleStatsCallback(kMetricStatsLongInterval -
- kMetricStatsShortInterval);
- break;
- case kStatsLong:
- if (diskstats_success) {
- SendSample(kMetricReadSectorsLongName,
- read_sectors_per_second,
- 1,
- kMetricSectorsIOMax,
- kMetricSectorsBuckets);
- SendSample(kMetricWriteSectorsLongName,
- write_sectors_per_second,
- 1,
- kMetricSectorsIOMax,
- kMetricSectorsBuckets);
- // Reset sector counters.
- read_sectors_ = read_sectors_now;
- write_sectors_ = write_sectors_now;
- }
- if (vmstats_success) {
- SendSample(kMetricPageFaultsLongName,
- page_faults_per_second,
- 1,
- kMetricPageFaultsMax,
- kMetricPageFaultsBuckets);
- SendSample(kMetricSwapInLongName,
- swap_in_per_second,
- 1,
- kMetricPageFaultsMax,
- kMetricPageFaultsBuckets);
- SendSample(kMetricSwapOutLongName,
- swap_out_per_second,
- 1,
- kMetricPageFaultsMax,
- kMetricPageFaultsBuckets);
-
- vmstats_ = vmstats_now;
- }
- SendCpuThrottleMetrics();
- // Set start time for new cycle.
- stats_initial_time_ = time_now;
- // Schedule short callback.
- stats_state_ = kStatsShort;
- ScheduleStatsCallback(kMetricStatsShortInterval);
- break;
- default:
- LOG(FATAL) << "Invalid stats state";
- }
-}
-
void MetricsDaemon::ScheduleMeminfoCallback(int wait) {
if (testing_) {
return;
diff --git a/metricsd/metrics_daemon.h b/metricsd/metrics_daemon.h
index eaa82192b..612dfe209 100644
--- a/metricsd/metrics_daemon.h
+++ b/metricsd/metrics_daemon.h
@@ -29,6 +29,7 @@
#include <chromeos/daemons/dbus_daemon.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
+#include "collectors/averaged_statistics_collector.h"
#include "collectors/disk_usage_collector.h"
#include "metrics/metrics_library.h"
#include "persistent_integer.h"
@@ -65,6 +66,9 @@ class MetricsDaemon : public chromeos::DBusDaemon {
// Triggers an upload event and exit. (Used to test UploadService)
void RunUploaderTest();
+ // Returns the active time since boot (uptime minus sleep time) in seconds.
+ static double GetActiveTime();
+
protected:
// Used also by the unit tests.
static const char kComprDataSizeName[];
@@ -79,8 +83,6 @@ class MetricsDaemon : public chromeos::DBusDaemon {
FRIEND_TEST(MetricsDaemonTest, GetHistogramPath);
FRIEND_TEST(MetricsDaemonTest, IsNewEpoch);
FRIEND_TEST(MetricsDaemonTest, MessageFilter);
- FRIEND_TEST(MetricsDaemonTest, ParseDiskStats);
- FRIEND_TEST(MetricsDaemonTest, ParseVmStats);
FRIEND_TEST(MetricsDaemonTest, ProcessKernelCrash);
FRIEND_TEST(MetricsDaemonTest, ProcessMeminfo);
FRIEND_TEST(MetricsDaemonTest, ProcessMeminfo2);
@@ -95,12 +97,6 @@ class MetricsDaemon : public chromeos::DBusDaemon {
FRIEND_TEST(MetricsDaemonTest, SendCpuThrottleMetrics);
FRIEND_TEST(MetricsDaemonTest, SendZramMetrics);
- // State for disk stats collector callback.
- enum StatsState {
- kStatsShort, // short wait before short interval collection
- kStatsLong, // final wait before new collection
- };
-
// Type of scale to use for meminfo histograms. For most of them we use
// percent of total RAM, but for some we use absolute numbers, usually in
// megabytes, on a log scale from 0 to 4000, and 0 to 8000 for compressed
@@ -120,16 +116,6 @@ class MetricsDaemon : public chromeos::DBusDaemon {
int value; // value from /proc/meminfo
};
- // Record for retrieving and reporting values from /proc/vmstat
- struct VmstatRecord {
- uint64_t page_faults_; // major faults
- uint64_t swap_in_; // pages swapped in
- uint64_t swap_out_; // pages swapped out
- };
-
- // Returns the active time since boot (uptime minus sleep time) in seconds.
- double GetActiveTime();
-
// D-Bus filter callback.
static DBusHandlerResult MessageFilter(DBusConnection* connection,
DBusMessage* message,
@@ -189,21 +175,6 @@ class MetricsDaemon : public chromeos::DBusDaemon {
// Initializes vm and disk stats reporting.
void StatsReporterInit();
- // Schedules a callback for the next vm and disk stats collection.
- void ScheduleStatsCallback(int wait);
-
- // Reads cumulative disk statistics from sysfs. Returns true for success.
- bool DiskStatsReadStats(uint64_t* read_sectors, uint64_t* write_sectors);
-
- // Reads cumulative vm statistics from procfs. Returns true for success.
- bool VmStatsReadStats(struct VmstatRecord* stats);
-
- // Parse cumulative vm statistics from a C string. Returns true for success.
- bool VmStatsParseStats(const char* stats, struct VmstatRecord* record);
-
- // Reports disk and vm statistics.
- void StatsCallback();
-
// Schedules meminfo collection callback.
void ScheduleMeminfoCallback(int wait);
@@ -286,14 +257,6 @@ class MetricsDaemon : public chromeos::DBusDaemon {
// Selects the wait time for the next memory use callback.
unsigned int memuse_interval_index_;
- // Contain the most recent disk and vm cumulative stats.
- uint64_t read_sectors_;
- uint64_t write_sectors_;
- struct VmstatRecord vmstats_;
-
- StatsState stats_state_;
- double stats_initial_time_;
-
// The system "HZ", or frequency of ticks. Some system data uses ticks as a
// unit, and this is used to convert to standard time units.
uint32_t ticks_per_second_;
@@ -329,8 +292,8 @@ class MetricsDaemon : public chromeos::DBusDaemon {
scoped_ptr<PersistentInteger> unclean_shutdowns_daily_count_;
scoped_ptr<PersistentInteger> unclean_shutdowns_weekly_count_;
scoped_ptr<DiskUsageCollector> disk_usage_collector_;
+ scoped_ptr<AveragedStatisticsCollector> averaged_stats_collector_;
- std::string diskstats_path_;
std::string scaling_max_freq_path_;
std::string cpuinfo_max_freq_path_;
diff --git a/metricsd/metrics_daemon_test.cc b/metricsd/metrics_daemon_test.cc
index cc00cc27e..3a8fc3a2d 100644
--- a/metricsd/metrics_daemon_test.cc
+++ b/metricsd/metrics_daemon_test.cc
@@ -14,17 +14,12 @@
* limitations under the License.
*/
-#include <inttypes.h>
-#include <utime.h>
-
-#include <string>
#include <vector>
#include <base/at_exit.h>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/strings/string_number_conversions.h>
-#include <base/strings/stringprintf.h>
#include <chromeos/flag_helper.h>
#include <gtest/gtest.h>
@@ -34,10 +29,7 @@
#include "persistent_integer_mock.h"
using base::FilePath;
-using base::StringPrintf;
-using base::Time;
using base::TimeDelta;
-using base::TimeTicks;
using std::string;
using std::vector;
using ::testing::_;
@@ -47,34 +39,15 @@ using ::testing::Return;
using ::testing::StrictMock;
using chromeos_metrics::PersistentIntegerMock;
-static const char kFakeDiskStatsFormat[] =
- " 1793 1788 %" PRIu64 " 105580 "
- " 196 175 %" PRIu64 " 30290 "
- " 0 44060 135850\n";
-static const uint64_t kFakeReadSectors[] = {80000, 100000};
-static const uint64_t kFakeWriteSectors[] = {3000, 4000};
-
class MetricsDaemonTest : public testing::Test {
protected:
- std::string kFakeDiskStats0;
- std::string kFakeDiskStats1;
-
virtual void SetUp() {
chromeos::FlagHelper::Init(0, nullptr, "");
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
scaling_max_freq_path_ = temp_dir_.path().Append("scaling_max");
cpu_max_freq_path_ = temp_dir_.path().Append("cpu_freq_max");
- disk_stats_path_ = temp_dir_.path().Append("disk_stats");
- kFakeDiskStats0 = base::StringPrintf(kFakeDiskStatsFormat,
- kFakeReadSectors[0],
- kFakeWriteSectors[0]);
- kFakeDiskStats1 = base::StringPrintf(kFakeDiskStatsFormat,
- kFakeReadSectors[1],
- kFakeWriteSectors[1]);
-
- CreateFakeDiskStatsFile(kFakeDiskStats0);
CreateUint64ValueFile(cpu_max_freq_path_, 10000000);
CreateUint64ValueFile(scaling_max_freq_path_, 10000000);
@@ -84,7 +57,7 @@ class MetricsDaemonTest : public testing::Test {
false,
true,
&metrics_lib_,
- disk_stats_path_.value(),
+ "",
scaling_max_freq_path_.value(),
cpu_max_freq_path_.value(),
base::TimeDelta::FromMinutes(30),
@@ -131,12 +104,6 @@ class MetricsDaemonTest : public testing::Test {
dbus_message_unref(msg);
}
- // Creates or overwrites an input file containing fake disk stats.
- void CreateFakeDiskStatsFile(const string& fake_stats) {
- EXPECT_EQ(base::WriteFile(disk_stats_path_,
- fake_stats.data(), fake_stats.size()),
- fake_stats.size());
- }
// Creates or overwrites the file in |path| so that it contains the printable
// representation of |value|.
@@ -156,7 +123,6 @@ class MetricsDaemonTest : public testing::Test {
// Path for the fake files.
base::FilePath scaling_max_freq_path_;
base::FilePath cpu_max_freq_path_;
- base::FilePath disk_stats_path_;
// Mocks. They are strict mock so that all unexpected
// calls are marked as failures.
@@ -200,21 +166,6 @@ TEST_F(MetricsDaemonTest, SendSample) {
/* min */ 1, /* max */ 100, /* buckets */ 50);
}
-TEST_F(MetricsDaemonTest, ParseDiskStats) {
- uint64_t read_sectors_now, write_sectors_now;
- CreateFakeDiskStatsFile(kFakeDiskStats0);
- ASSERT_TRUE(daemon_.DiskStatsReadStats(&read_sectors_now,
- &write_sectors_now));
- EXPECT_EQ(read_sectors_now, kFakeReadSectors[0]);
- EXPECT_EQ(write_sectors_now, kFakeWriteSectors[0]);
-
- CreateFakeDiskStatsFile(kFakeDiskStats1);
- ASSERT_TRUE(daemon_.DiskStatsReadStats(&read_sectors_now,
- &write_sectors_now));
- EXPECT_EQ(read_sectors_now, kFakeReadSectors[1]);
- EXPECT_EQ(write_sectors_now, kFakeWriteSectors[1]);
-}
-
TEST_F(MetricsDaemonTest, ProcessMeminfo) {
string meminfo =
"MemTotal: 2000000 kB\nMemFree: 500000 kB\n"
@@ -258,16 +209,6 @@ TEST_F(MetricsDaemonTest, ProcessMeminfo2) {
EXPECT_FALSE(daemon_.ProcessMeminfo(meminfo));
}
-TEST_F(MetricsDaemonTest, ParseVmStats) {
- static char kVmStats[] = "pswpin 1345\npswpout 8896\n"
- "foo 100\nbar 200\npgmajfault 42\netcetc 300\n";
- struct MetricsDaemon::VmstatRecord stats;
- EXPECT_TRUE(daemon_.VmStatsParseStats(kVmStats, &stats));
- EXPECT_EQ(stats.page_faults_, 42);
- EXPECT_EQ(stats.swap_in_, 1345);
- EXPECT_EQ(stats.swap_out_, 8896);
-}
-
TEST_F(MetricsDaemonTest, ReadFreqToInt) {
const int fake_scaled_freq = 1666999;
const int fake_max_freq = 2000000;