Loading cmds/statsd/src/guardrail/StatsdStats.cpp +38 −6 Original line number Diff line number Diff line Loading @@ -117,36 +117,60 @@ void StatsdStats::noteConfigRemoved(const ConfigKey& key) { } void StatsdStats::noteBroadcastSent(const ConfigKey& key) { noteBroadcastSent(key, time(nullptr)); } void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) { lock_guard<std::mutex> lock(mLock); auto it = mConfigStats.find(key); if (it == mConfigStats.end()) { ALOGE("Config key %s not found!", key.ToString().c_str()); return; } it->second.add_broadcast_sent_time_sec(time(nullptr)); if (it->second.broadcast_sent_time_sec_size() >= kMaxTimestampCount) { auto timestampList = it->second.mutable_broadcast_sent_time_sec(); // This is O(N) operation. It shouldn't happen often, and N is only 20. timestampList->erase(timestampList->begin()); } it->second.add_broadcast_sent_time_sec(timeSec); } void StatsdStats::noteDataDropped(const ConfigKey& key) { noteDataDropped(key, time(nullptr)); } void StatsdStats::noteDataDropped(const ConfigKey& key, int32_t timeSec) { lock_guard<std::mutex> lock(mLock); auto it = mConfigStats.find(key); if (it == mConfigStats.end()) { ALOGE("Config key %s not found!", key.ToString().c_str()); return; } it->second.add_data_drop_time_sec(time(nullptr)); if (it->second.data_drop_time_sec_size() >= kMaxTimestampCount) { auto timestampList = it->second.mutable_data_drop_time_sec(); // This is O(N) operation. It shouldn't happen often, and N is only 20. timestampList->erase(timestampList->begin()); } it->second.add_data_drop_time_sec(timeSec); } void StatsdStats::noteMetricsReportSent(const ConfigKey& key) { noteMetricsReportSent(key, time(nullptr)); } void StatsdStats::noteMetricsReportSent(const ConfigKey& key, int32_t timeSec) { lock_guard<std::mutex> lock(mLock); auto it = mConfigStats.find(key); if (it == mConfigStats.end()) { ALOGE("Config key %s not found!", key.ToString().c_str()); return; } it->second.add_dump_report_time_sec(time(nullptr)); if (it->second.dump_report_time_sec_size() >= kMaxTimestampCount) { auto timestampList = it->second.mutable_dump_report_time_sec(); // This is O(N) operation. It shouldn't happen often, and N is only 20. timestampList->erase(timestampList->begin()); } it->second.add_dump_report_time_sec(timeSec); } void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const string& name, int size) { Loading Loading @@ -201,6 +225,14 @@ void StatsdStats::resetInternalLocked() { mMetricsStats.clear(); std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0); mMatcherStats.clear(); for (auto& config : mConfigStats) { config.second.clear_broadcast_sent_time_sec(); config.second.clear_data_drop_time_sec(); config.second.clear_dump_report_time_sec(); config.second.clear_matcher_stats(); config.second.clear_condition_stats(); config.second.clear_metric_stats(); } } void StatsdStats::addSubStatsToConfig(const ConfigKey& key, Loading cmds/statsd/src/guardrail/StatsdStats.h +9 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ public: const static int kMaxMetricCountPerConfig = 300; const static int kMaxMatcherCountPerConfig = 500; const static int kMaxTimestampCount = 20; /** * Report a new config has been received and report the static stats about the config. * Loading Loading @@ -162,11 +164,18 @@ private: void addSubStatsToConfig(const ConfigKey& key, StatsdStatsReport_ConfigStats& configStats); void noteDataDropped(const ConfigKey& key, int32_t timeSec); void noteMetricsReportSent(const ConfigKey& key, int32_t timeSec); void noteBroadcastSent(const ConfigKey& key, int32_t timeSec); FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd); FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd); FRIEND_TEST(StatsdStatsTest, TestConfigRemove); FRIEND_TEST(StatsdStatsTest, TestSubStats); FRIEND_TEST(StatsdStatsTest, TestAtomLog); FRIEND_TEST(StatsdStatsTest, TestTimestampThreshold); }; } // namespace statsd Loading cmds/statsd/tests/guardrail/StatsdStats_test.cpp +42 −0 Original line number Diff line number Diff line Loading @@ -224,6 +224,48 @@ TEST(StatsdStatsTest, TestAtomLog) { EXPECT_TRUE(sensorAtomGood); } TEST(StatsdStatsTest, TestTimestampThreshold) { StatsdStats stats; vector<int32_t> timestamps; for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) { timestamps.push_back(i); } ConfigKey key(0, "test"); stats.noteConfigReceived(key, 2, 3, 4, 5, true); for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) { stats.noteDataDropped(key, timestamps[i]); stats.noteBroadcastSent(key, timestamps[i]); stats.noteMetricsReportSent(key, timestamps[i]); } int32_t newTimestamp = 10000; // now it should trigger removing oldest timestamp stats.noteDataDropped(key, 10000); stats.noteBroadcastSent(key, 10000); stats.noteMetricsReportSent(key, 10000); EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end()); const auto& configStats = stats.mConfigStats[key]; int maxCount = StatsdStats::kMaxTimestampCount; EXPECT_EQ(maxCount, configStats.broadcast_sent_time_sec_size()); EXPECT_EQ(maxCount, configStats.data_drop_time_sec_size()); EXPECT_EQ(maxCount, configStats.dump_report_time_sec_size()); // the oldest timestamp is the second timestamp in history EXPECT_EQ(1, configStats.broadcast_sent_time_sec(0)); EXPECT_EQ(1, configStats.broadcast_sent_time_sec(0)); EXPECT_EQ(1, configStats.broadcast_sent_time_sec(0)); // the last timestamp is the newest timestamp. EXPECT_EQ(newTimestamp, configStats.broadcast_sent_time_sec(StatsdStats::kMaxTimestampCount - 1)); EXPECT_EQ(newTimestamp, configStats.data_drop_time_sec(StatsdStats::kMaxTimestampCount - 1)); EXPECT_EQ(newTimestamp, configStats.dump_report_time_sec(StatsdStats::kMaxTimestampCount - 1)); } } // namespace statsd } // namespace os } // namespace android Loading Loading
cmds/statsd/src/guardrail/StatsdStats.cpp +38 −6 Original line number Diff line number Diff line Loading @@ -117,36 +117,60 @@ void StatsdStats::noteConfigRemoved(const ConfigKey& key) { } void StatsdStats::noteBroadcastSent(const ConfigKey& key) { noteBroadcastSent(key, time(nullptr)); } void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) { lock_guard<std::mutex> lock(mLock); auto it = mConfigStats.find(key); if (it == mConfigStats.end()) { ALOGE("Config key %s not found!", key.ToString().c_str()); return; } it->second.add_broadcast_sent_time_sec(time(nullptr)); if (it->second.broadcast_sent_time_sec_size() >= kMaxTimestampCount) { auto timestampList = it->second.mutable_broadcast_sent_time_sec(); // This is O(N) operation. It shouldn't happen often, and N is only 20. timestampList->erase(timestampList->begin()); } it->second.add_broadcast_sent_time_sec(timeSec); } void StatsdStats::noteDataDropped(const ConfigKey& key) { noteDataDropped(key, time(nullptr)); } void StatsdStats::noteDataDropped(const ConfigKey& key, int32_t timeSec) { lock_guard<std::mutex> lock(mLock); auto it = mConfigStats.find(key); if (it == mConfigStats.end()) { ALOGE("Config key %s not found!", key.ToString().c_str()); return; } it->second.add_data_drop_time_sec(time(nullptr)); if (it->second.data_drop_time_sec_size() >= kMaxTimestampCount) { auto timestampList = it->second.mutable_data_drop_time_sec(); // This is O(N) operation. It shouldn't happen often, and N is only 20. timestampList->erase(timestampList->begin()); } it->second.add_data_drop_time_sec(timeSec); } void StatsdStats::noteMetricsReportSent(const ConfigKey& key) { noteMetricsReportSent(key, time(nullptr)); } void StatsdStats::noteMetricsReportSent(const ConfigKey& key, int32_t timeSec) { lock_guard<std::mutex> lock(mLock); auto it = mConfigStats.find(key); if (it == mConfigStats.end()) { ALOGE("Config key %s not found!", key.ToString().c_str()); return; } it->second.add_dump_report_time_sec(time(nullptr)); if (it->second.dump_report_time_sec_size() >= kMaxTimestampCount) { auto timestampList = it->second.mutable_dump_report_time_sec(); // This is O(N) operation. It shouldn't happen often, and N is only 20. timestampList->erase(timestampList->begin()); } it->second.add_dump_report_time_sec(timeSec); } void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const string& name, int size) { Loading Loading @@ -201,6 +225,14 @@ void StatsdStats::resetInternalLocked() { mMetricsStats.clear(); std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0); mMatcherStats.clear(); for (auto& config : mConfigStats) { config.second.clear_broadcast_sent_time_sec(); config.second.clear_data_drop_time_sec(); config.second.clear_dump_report_time_sec(); config.second.clear_matcher_stats(); config.second.clear_condition_stats(); config.second.clear_metric_stats(); } } void StatsdStats::addSubStatsToConfig(const ConfigKey& key, Loading
cmds/statsd/src/guardrail/StatsdStats.h +9 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ public: const static int kMaxMetricCountPerConfig = 300; const static int kMaxMatcherCountPerConfig = 500; const static int kMaxTimestampCount = 20; /** * Report a new config has been received and report the static stats about the config. * Loading Loading @@ -162,11 +164,18 @@ private: void addSubStatsToConfig(const ConfigKey& key, StatsdStatsReport_ConfigStats& configStats); void noteDataDropped(const ConfigKey& key, int32_t timeSec); void noteMetricsReportSent(const ConfigKey& key, int32_t timeSec); void noteBroadcastSent(const ConfigKey& key, int32_t timeSec); FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd); FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd); FRIEND_TEST(StatsdStatsTest, TestConfigRemove); FRIEND_TEST(StatsdStatsTest, TestSubStats); FRIEND_TEST(StatsdStatsTest, TestAtomLog); FRIEND_TEST(StatsdStatsTest, TestTimestampThreshold); }; } // namespace statsd Loading
cmds/statsd/tests/guardrail/StatsdStats_test.cpp +42 −0 Original line number Diff line number Diff line Loading @@ -224,6 +224,48 @@ TEST(StatsdStatsTest, TestAtomLog) { EXPECT_TRUE(sensorAtomGood); } TEST(StatsdStatsTest, TestTimestampThreshold) { StatsdStats stats; vector<int32_t> timestamps; for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) { timestamps.push_back(i); } ConfigKey key(0, "test"); stats.noteConfigReceived(key, 2, 3, 4, 5, true); for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) { stats.noteDataDropped(key, timestamps[i]); stats.noteBroadcastSent(key, timestamps[i]); stats.noteMetricsReportSent(key, timestamps[i]); } int32_t newTimestamp = 10000; // now it should trigger removing oldest timestamp stats.noteDataDropped(key, 10000); stats.noteBroadcastSent(key, 10000); stats.noteMetricsReportSent(key, 10000); EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end()); const auto& configStats = stats.mConfigStats[key]; int maxCount = StatsdStats::kMaxTimestampCount; EXPECT_EQ(maxCount, configStats.broadcast_sent_time_sec_size()); EXPECT_EQ(maxCount, configStats.data_drop_time_sec_size()); EXPECT_EQ(maxCount, configStats.dump_report_time_sec_size()); // the oldest timestamp is the second timestamp in history EXPECT_EQ(1, configStats.broadcast_sent_time_sec(0)); EXPECT_EQ(1, configStats.broadcast_sent_time_sec(0)); EXPECT_EQ(1, configStats.broadcast_sent_time_sec(0)); // the last timestamp is the newest timestamp. EXPECT_EQ(newTimestamp, configStats.broadcast_sent_time_sec(StatsdStats::kMaxTimestampCount - 1)); EXPECT_EQ(newTimestamp, configStats.data_drop_time_sec(StatsdStats::kMaxTimestampCount - 1)); EXPECT_EQ(newTimestamp, configStats.dump_report_time_sec(StatsdStats::kMaxTimestampCount - 1)); } } // namespace statsd } // namespace os } // namespace android Loading