metrics: Initialize "last update time".
Before this change, when metrics_daemon started, it initialized its
"last update time" to 0 ticks and used this as the basis for computing
daily usage time statistics. If metrics daemon starts right after boot
(and ticks start counting from 0 on boot) this is reasonably accurate,
but if metrics daemon restarts for some reason (e.g. it crashes),
counting from 0 will provide a measure of total system uptime rather
than recent usage.
To fix this, initialize the "last update time" to the current number of
ticks when metrics daemon is initialized.
BUG=chromium:1159236
TEST=unit tests
Change-Id: I31151c00865d34708a83d6cd045e1c6e05e70912
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2593717
Tested-by: Miriam Zimmerman <mutexlox@chromium.org>
Reviewed-by: Ian Barkley-Yeung <iby@chromium.org>
Commit-Queue: Miriam Zimmerman <mutexlox@chromium.org>
diff --git a/metrics/metrics_daemon.cc b/metrics/metrics_daemon.cc
index f221813..a4c2e0a 100644
--- a/metrics/metrics_daemon.cc
+++ b/metrics/metrics_daemon.cc
@@ -403,6 +403,20 @@
vmstats_daily_success = VmStatsReadStats(&vmstats_daily_start);
+ // Start the "last update" time at the time of metrics daemon starting.
+ // This isn't entirely accurate -- in general, the tick counter will start
+ // counting when the kernel starts executing, while metrics_daemon will only
+ // start up once boot has mostly completed.
+ // However, we need to initialize because:
+ // 1. metrics_daemon might crash and restart. In this case, if we did not
+ // initialize last_update_stats_time_, the first values we calculate based on
+ // it will be based on the overall uptime of the device, rather than the
+ // actual interval between updates.
+ // 2. TimeTicks doesn't guarantee anything about when the value it returns
+ // will be zero -- only that the value is monotonically nondecreasing. In
+ // principle, on some platforms, it could start at a large number on boot.
+ last_update_stats_time_ = TimeTicks::Now();
+
// If testing, initialize Stats Reporter without connecting DBus
if (testing_)
StatsReporterInit();
diff --git a/metrics/metrics_daemon.h b/metrics/metrics_daemon.h
index 400d66c..2b4cbaf 100644
--- a/metrics/metrics_daemon.h
+++ b/metrics/metrics_daemon.h
@@ -135,6 +135,7 @@
FRIEND_TEST(MetricsDaemonTest, SendZramMetricsOld);
FRIEND_TEST(MetricsDaemonTest, SendZramMetricsWithIncompressiblePageStats);
FRIEND_TEST(MetricsDaemonTest, GetDetachableBaseTimes);
+ FRIEND_TEST(MetricsDaemonTest, UpdateUsageStats);
// State for disk stats collector callback.
enum StatsState {
diff --git a/metrics/metrics_daemon_test.cc b/metrics/metrics_daemon_test.cc
index 4b3e4be..8ae825c 100644
--- a/metrics/metrics_daemon_test.cc
+++ b/metrics/metrics_daemon_test.cc
@@ -32,6 +32,7 @@
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::AtLeast;
+using ::testing::Le;
using ::testing::Return;
using ::testing::StrictMock;
@@ -72,6 +73,8 @@
CHECK(persistent_integer_backing_dir_.CreateUniqueTempDir());
base::FilePath backing_dir_path = persistent_integer_backing_dir_.GetPath();
+ test_start_ = base::TimeTicks::Now();
+
daemon_.Init(true, false, &metrics_lib_, kFakeDiskStatsName,
kFakeVmStatsName, kFakeScalingMaxFreqPath,
kFakeCpuinfoMaxFreqPath, base::TimeDelta::FromMinutes(30),
@@ -104,16 +107,16 @@
EXPECT_EQ(0, unlink(kFakeCpuinfoMaxFreqPath));
}
- // Adds active use aggregation counters update expectations that the
- // specified count will be added.
- void ExpectActiveUseUpdate(int count) {
- EXPECT_CALL(*daily_active_use_mock_, Add(count))
+ // Adds active use aggregation counters update expectations that a count no
+ // larger than the specified upper bound will be added.
+ void ExpectActiveUseUpdate(int upper_bound) {
+ EXPECT_CALL(*daily_active_use_mock_, Add(Le(upper_bound)))
.Times(1)
.RetiresOnSaturation();
- EXPECT_CALL(*kernel_crash_interval_mock_, Add(count))
+ EXPECT_CALL(*kernel_crash_interval_mock_, Add(Le(upper_bound)))
.Times(1)
.RetiresOnSaturation();
- EXPECT_CALL(*user_crash_interval_mock_, Add(count))
+ EXPECT_CALL(*user_crash_interval_mock_, Add(Le(upper_bound)))
.Times(1)
.RetiresOnSaturation();
}
@@ -208,6 +211,8 @@
// The MetricsDaemon under test.
MetricsDaemon daemon_;
+ // The system time just before the daemon was initialized.
+ base::TimeTicks test_start_;
// The temporary directory for backing files.
base::ScopedTempDir persistent_integer_backing_dir_;
@@ -662,6 +667,21 @@
EXPECT_EQ(suspended_time, 20);
}
+TEST_F(MetricsDaemonTest, UpdateUsageStats) {
+ // Ignore calls to SendToUMA.
+ EXPECT_CALL(metrics_lib_, SendToUMA(_, _, _, _, _)).Times(AnyNumber());
+
+ // Add an arbitrary amount to the test start.
+ const int elapsed_seconds = 42;
+ base::TimeTicks end =
+ test_start_ + base::TimeDelta::FromSeconds(elapsed_seconds);
+ ASSERT_EQ(elapsed_seconds, (end - test_start_).InSeconds());
+
+ ExpectActiveUseUpdate(elapsed_seconds);
+
+ daemon_.UpdateStats(end, base::Time::Now());
+}
+
} // namespace chromeos_metrics
int main(int argc, char** argv) {