Loading cmds/statsd/Android.mk +3 −1 Original line number Diff line number Diff line Loading @@ -165,6 +165,7 @@ LOCAL_CFLAGS += \ LOCAL_SRC_FILES := \ $(statsd_common_src) \ tests/dimension_test.cpp \ tests/AnomalyMonitor_test.cpp \ tests/anomaly/AnomalyTracker_test.cpp \ tests/ConfigManager_test.cpp \ Loading @@ -190,7 +191,8 @@ LOCAL_SRC_FILES := \ tests/e2e/WakelockDuration_e2e_test.cpp \ tests/e2e/MetricConditionLink_e2e_test.cpp \ tests/e2e/Attribution_e2e_test.cpp \ tests/e2e/GaugeMetric_e2e_test.cpp tests/e2e/GaugeMetric_e2e_test.cpp \ tests/e2e/DimensionInCondition_e2e_test.cpp LOCAL_STATIC_LIBRARIES := \ $(statsd_common_static_libraries) \ Loading cmds/statsd/src/HashableDimensionKey.cpp +23 −3 Original line number Diff line number Diff line Loading @@ -67,12 +67,16 @@ android::hash_t hashDimensionsValue(const DimensionsValue& value) { return hashDimensionsValue(0, value); } android::hash_t hashMetricDimensionKey(int64_t seed, const MetricDimensionKey& dimensionKey) { android::hash_t hash = seed; hash = android::JenkinsHashMix(hash, std::hash<MetricDimensionKey>{}(dimensionKey)); return JenkinsHashWhiten(hash); } using std::string; string HashableDimensionKey::toString() const { string flattened; DimensionsValueToString(getDimensionsValue(), &flattened); return flattened; return DimensionsValueToString(getDimensionsValue()); } bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) { Loading Loading @@ -162,6 +166,22 @@ bool HashableDimensionKey::operator<(const HashableDimensionKey& that) const { return LessThan(getDimensionsValue(), that.getDimensionsValue()); }; string MetricDimensionKey::toString() const { string flattened = mDimensionKeyInWhat.toString(); flattened += mDimensionKeyInCondition.toString(); return flattened; } bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const { return mDimensionKeyInWhat == that.getDimensionKeyInWhat() && mDimensionKeyInCondition == that.getDimensionKeyInCondition(); }; bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const { return toString().compare(that.toString()) < 0; }; } // namespace statsd } // namespace os } // namespace android No newline at end of file cmds/statsd/src/HashableDimensionKey.h +60 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,10 @@ public: return mDimensionsValue; } inline DimensionsValue* getMutableDimensionsValue() { return &mDimensionsValue; } bool operator==(const HashableDimensionKey& that) const; bool operator<(const HashableDimensionKey& that) const; Loading @@ -53,8 +57,52 @@ private: DimensionsValue mDimensionsValue; }; class MetricDimensionKey { public: explicit MetricDimensionKey(const HashableDimensionKey& dimensionKeyInWhat, const HashableDimensionKey& dimensionKeyInCondition) : mDimensionKeyInWhat(dimensionKeyInWhat), mDimensionKeyInCondition(dimensionKeyInCondition) {}; MetricDimensionKey(){}; MetricDimensionKey(const MetricDimensionKey& that) : mDimensionKeyInWhat(that.getDimensionKeyInWhat()), mDimensionKeyInCondition(that.getDimensionKeyInCondition()) {}; MetricDimensionKey& operator=(const MetricDimensionKey& from) = default; std::string toString() const; inline const HashableDimensionKey& getDimensionKeyInWhat() const { return mDimensionKeyInWhat; } inline const HashableDimensionKey& getDimensionKeyInCondition() const { return mDimensionKeyInCondition; } bool hasDimensionKeyInCondition() const { return mDimensionKeyInCondition.getDimensionsValue().has_field(); } bool operator==(const MetricDimensionKey& that) const; bool operator<(const MetricDimensionKey& that) const; inline const char* c_str() const { return toString().c_str(); } private: HashableDimensionKey mDimensionKeyInWhat; HashableDimensionKey mDimensionKeyInCondition; }; bool compareDimensionsValue(const DimensionsValue& s1, const DimensionsValue& s2); android::hash_t hashDimensionsValue(int64_t seed, const DimensionsValue& value); android::hash_t hashDimensionsValue(const DimensionsValue& value); android::hash_t hashMetricDimensionKey(int64_t see, const MetricDimensionKey& dimensionKey); } // namespace statsd } // namespace os Loading @@ -63,6 +111,7 @@ android::hash_t hashDimensionsValue(const DimensionsValue& value); namespace std { using android::os::statsd::HashableDimensionKey; using android::os::statsd::MetricDimensionKey; template <> struct hash<HashableDimensionKey> { Loading @@ -71,4 +120,14 @@ struct hash<HashableDimensionKey> { } }; template <> struct hash<MetricDimensionKey> { std::size_t operator()(const MetricDimensionKey& key) const { android::hash_t hash = hashDimensionsValue( key.getDimensionKeyInWhat().getDimensionsValue()); hash = android::JenkinsHashMix(hash, hashDimensionsValue(key.getDimensionKeyInCondition().getDimensionsValue())); return android::JenkinsHashWhiten(hash); } }; } // namespace std No newline at end of file cmds/statsd/src/StatsLogProcessor.h +4 −1 Original line number Diff line number Diff line Loading @@ -104,7 +104,10 @@ private: FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks); FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice); FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent); FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricNoLink); FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricWithLink); FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink); FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink); }; } // namespace statsd Loading cmds/statsd/src/anomaly/AnomalyTracker.cpp +9 −9 Original line number Diff line number Diff line Loading @@ -96,7 +96,7 @@ void AnomalyTracker::flushPastBuckets(const int64_t& latestPastBucketNum) { } } void AnomalyTracker::addPastBucket(const HashableDimensionKey& key, const int64_t& bucketValue, void AnomalyTracker::addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue, const int64_t& bucketNum) { flushPastBuckets(bucketNum); Loading Loading @@ -147,7 +147,7 @@ void AnomalyTracker::addBucketToSum(const shared_ptr<DimToValMap>& bucket) { } } int64_t AnomalyTracker::getPastBucketValue(const HashableDimensionKey& key, int64_t AnomalyTracker::getPastBucketValue(const MetricDimensionKey& key, const int64_t& bucketNum) const { const auto& bucket = mPastBuckets[index(bucketNum)]; if (bucket == nullptr) { Loading @@ -157,7 +157,7 @@ int64_t AnomalyTracker::getPastBucketValue(const HashableDimensionKey& key, return itr == bucket->end() ? 0 : itr->second; } int64_t AnomalyTracker::getSumOverPastBuckets(const HashableDimensionKey& key) const { int64_t AnomalyTracker::getSumOverPastBuckets(const MetricDimensionKey& key) const { const auto& itr = mSumOverPastBuckets.find(key); if (itr != mSumOverPastBuckets.end()) { return itr->second; Loading @@ -165,7 +165,7 @@ int64_t AnomalyTracker::getSumOverPastBuckets(const HashableDimensionKey& key) c return 0; } bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const HashableDimensionKey& key, bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const MetricDimensionKey& key, const int64_t& currentBucketValue) { if (currentBucketNum > mMostRecentBucketNum + 1) { // TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this. Loading @@ -175,7 +175,7 @@ bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const Hashab && getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt(); } void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const HashableDimensionKey& key) { void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const MetricDimensionKey& key) { // TODO: Why receive timestamp? RefractoryPeriod should always be based on real time right now. if (isInRefractoryPeriod(timestampNs, key)) { VLOG("Skipping anomaly declaration since within refractory period"); Loading @@ -199,14 +199,14 @@ void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const HashableD StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id()); // TODO: This should also take in the const HashableDimensionKey& key? // TODO: This should also take in the const MetricDimensionKey& key? android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(), mConfigKey.GetId(), mAlert.id()); } void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum, const HashableDimensionKey& key, const MetricDimensionKey& key, const int64_t& currentBucketValue) { if (detectAnomaly(currBucketNum, key, currentBucketValue)) { declareAnomaly(timestampNs, key); Loading @@ -214,7 +214,7 @@ void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs, } bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs, const HashableDimensionKey& key) { const MetricDimensionKey& key) { const auto& it = mRefractoryPeriodEndsSec.find(key); if (it != mRefractoryPeriodEndsSec.end()) { if ((timestampNs / NS_PER_SEC) <= it->second) { Loading @@ -226,7 +226,7 @@ bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs, return false; } void AnomalyTracker::informSubscribers(const HashableDimensionKey& key) { void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) { VLOG("informSubscribers called."); if (mSubscriptions.empty()) { ALOGE("Attempt to call with no subscribers."); Loading Loading
cmds/statsd/Android.mk +3 −1 Original line number Diff line number Diff line Loading @@ -165,6 +165,7 @@ LOCAL_CFLAGS += \ LOCAL_SRC_FILES := \ $(statsd_common_src) \ tests/dimension_test.cpp \ tests/AnomalyMonitor_test.cpp \ tests/anomaly/AnomalyTracker_test.cpp \ tests/ConfigManager_test.cpp \ Loading @@ -190,7 +191,8 @@ LOCAL_SRC_FILES := \ tests/e2e/WakelockDuration_e2e_test.cpp \ tests/e2e/MetricConditionLink_e2e_test.cpp \ tests/e2e/Attribution_e2e_test.cpp \ tests/e2e/GaugeMetric_e2e_test.cpp tests/e2e/GaugeMetric_e2e_test.cpp \ tests/e2e/DimensionInCondition_e2e_test.cpp LOCAL_STATIC_LIBRARIES := \ $(statsd_common_static_libraries) \ Loading
cmds/statsd/src/HashableDimensionKey.cpp +23 −3 Original line number Diff line number Diff line Loading @@ -67,12 +67,16 @@ android::hash_t hashDimensionsValue(const DimensionsValue& value) { return hashDimensionsValue(0, value); } android::hash_t hashMetricDimensionKey(int64_t seed, const MetricDimensionKey& dimensionKey) { android::hash_t hash = seed; hash = android::JenkinsHashMix(hash, std::hash<MetricDimensionKey>{}(dimensionKey)); return JenkinsHashWhiten(hash); } using std::string; string HashableDimensionKey::toString() const { string flattened; DimensionsValueToString(getDimensionsValue(), &flattened); return flattened; return DimensionsValueToString(getDimensionsValue()); } bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) { Loading Loading @@ -162,6 +166,22 @@ bool HashableDimensionKey::operator<(const HashableDimensionKey& that) const { return LessThan(getDimensionsValue(), that.getDimensionsValue()); }; string MetricDimensionKey::toString() const { string flattened = mDimensionKeyInWhat.toString(); flattened += mDimensionKeyInCondition.toString(); return flattened; } bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const { return mDimensionKeyInWhat == that.getDimensionKeyInWhat() && mDimensionKeyInCondition == that.getDimensionKeyInCondition(); }; bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const { return toString().compare(that.toString()) < 0; }; } // namespace statsd } // namespace os } // namespace android No newline at end of file
cmds/statsd/src/HashableDimensionKey.h +60 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,10 @@ public: return mDimensionsValue; } inline DimensionsValue* getMutableDimensionsValue() { return &mDimensionsValue; } bool operator==(const HashableDimensionKey& that) const; bool operator<(const HashableDimensionKey& that) const; Loading @@ -53,8 +57,52 @@ private: DimensionsValue mDimensionsValue; }; class MetricDimensionKey { public: explicit MetricDimensionKey(const HashableDimensionKey& dimensionKeyInWhat, const HashableDimensionKey& dimensionKeyInCondition) : mDimensionKeyInWhat(dimensionKeyInWhat), mDimensionKeyInCondition(dimensionKeyInCondition) {}; MetricDimensionKey(){}; MetricDimensionKey(const MetricDimensionKey& that) : mDimensionKeyInWhat(that.getDimensionKeyInWhat()), mDimensionKeyInCondition(that.getDimensionKeyInCondition()) {}; MetricDimensionKey& operator=(const MetricDimensionKey& from) = default; std::string toString() const; inline const HashableDimensionKey& getDimensionKeyInWhat() const { return mDimensionKeyInWhat; } inline const HashableDimensionKey& getDimensionKeyInCondition() const { return mDimensionKeyInCondition; } bool hasDimensionKeyInCondition() const { return mDimensionKeyInCondition.getDimensionsValue().has_field(); } bool operator==(const MetricDimensionKey& that) const; bool operator<(const MetricDimensionKey& that) const; inline const char* c_str() const { return toString().c_str(); } private: HashableDimensionKey mDimensionKeyInWhat; HashableDimensionKey mDimensionKeyInCondition; }; bool compareDimensionsValue(const DimensionsValue& s1, const DimensionsValue& s2); android::hash_t hashDimensionsValue(int64_t seed, const DimensionsValue& value); android::hash_t hashDimensionsValue(const DimensionsValue& value); android::hash_t hashMetricDimensionKey(int64_t see, const MetricDimensionKey& dimensionKey); } // namespace statsd } // namespace os Loading @@ -63,6 +111,7 @@ android::hash_t hashDimensionsValue(const DimensionsValue& value); namespace std { using android::os::statsd::HashableDimensionKey; using android::os::statsd::MetricDimensionKey; template <> struct hash<HashableDimensionKey> { Loading @@ -71,4 +120,14 @@ struct hash<HashableDimensionKey> { } }; template <> struct hash<MetricDimensionKey> { std::size_t operator()(const MetricDimensionKey& key) const { android::hash_t hash = hashDimensionsValue( key.getDimensionKeyInWhat().getDimensionsValue()); hash = android::JenkinsHashMix(hash, hashDimensionsValue(key.getDimensionKeyInCondition().getDimensionsValue())); return android::JenkinsHashWhiten(hash); } }; } // namespace std No newline at end of file
cmds/statsd/src/StatsLogProcessor.h +4 −1 Original line number Diff line number Diff line Loading @@ -104,7 +104,10 @@ private: FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks); FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice); FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent); FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricNoLink); FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricWithLink); FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink); FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink); }; } // namespace statsd Loading
cmds/statsd/src/anomaly/AnomalyTracker.cpp +9 −9 Original line number Diff line number Diff line Loading @@ -96,7 +96,7 @@ void AnomalyTracker::flushPastBuckets(const int64_t& latestPastBucketNum) { } } void AnomalyTracker::addPastBucket(const HashableDimensionKey& key, const int64_t& bucketValue, void AnomalyTracker::addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue, const int64_t& bucketNum) { flushPastBuckets(bucketNum); Loading Loading @@ -147,7 +147,7 @@ void AnomalyTracker::addBucketToSum(const shared_ptr<DimToValMap>& bucket) { } } int64_t AnomalyTracker::getPastBucketValue(const HashableDimensionKey& key, int64_t AnomalyTracker::getPastBucketValue(const MetricDimensionKey& key, const int64_t& bucketNum) const { const auto& bucket = mPastBuckets[index(bucketNum)]; if (bucket == nullptr) { Loading @@ -157,7 +157,7 @@ int64_t AnomalyTracker::getPastBucketValue(const HashableDimensionKey& key, return itr == bucket->end() ? 0 : itr->second; } int64_t AnomalyTracker::getSumOverPastBuckets(const HashableDimensionKey& key) const { int64_t AnomalyTracker::getSumOverPastBuckets(const MetricDimensionKey& key) const { const auto& itr = mSumOverPastBuckets.find(key); if (itr != mSumOverPastBuckets.end()) { return itr->second; Loading @@ -165,7 +165,7 @@ int64_t AnomalyTracker::getSumOverPastBuckets(const HashableDimensionKey& key) c return 0; } bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const HashableDimensionKey& key, bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const MetricDimensionKey& key, const int64_t& currentBucketValue) { if (currentBucketNum > mMostRecentBucketNum + 1) { // TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this. Loading @@ -175,7 +175,7 @@ bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const Hashab && getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt(); } void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const HashableDimensionKey& key) { void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const MetricDimensionKey& key) { // TODO: Why receive timestamp? RefractoryPeriod should always be based on real time right now. if (isInRefractoryPeriod(timestampNs, key)) { VLOG("Skipping anomaly declaration since within refractory period"); Loading @@ -199,14 +199,14 @@ void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const HashableD StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id()); // TODO: This should also take in the const HashableDimensionKey& key? // TODO: This should also take in the const MetricDimensionKey& key? android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(), mConfigKey.GetId(), mAlert.id()); } void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum, const HashableDimensionKey& key, const MetricDimensionKey& key, const int64_t& currentBucketValue) { if (detectAnomaly(currBucketNum, key, currentBucketValue)) { declareAnomaly(timestampNs, key); Loading @@ -214,7 +214,7 @@ void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs, } bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs, const HashableDimensionKey& key) { const MetricDimensionKey& key) { const auto& it = mRefractoryPeriodEndsSec.find(key); if (it != mRefractoryPeriodEndsSec.end()) { if ((timestampNs / NS_PER_SEC) <= it->second) { Loading @@ -226,7 +226,7 @@ bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs, return false; } void AnomalyTracker::informSubscribers(const HashableDimensionKey& key) { void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) { VLOG("informSubscribers called."); if (mSubscriptions.empty()) { ALOGE("Attempt to call with no subscribers."); Loading