Perform update for duration metric
Creates a new metric if the metric is new/needs replacement. Preserves the metrics that can be preserved. Ensures that indices are updated, including within duration trackers. Does not handle if a condition is true for a new metric based on an existing condition. Test: atest statsd_test Bug: 162323124 Change-Id: Ibe0baf54678c1c6efde5aeba6a4b9b7fa2634c55
This commit is contained in:
@@ -17,14 +17,17 @@
|
||||
#define DEBUG false
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include "DurationMetricProducer.h"
|
||||
#include "guardrail/StatsdStats.h"
|
||||
#include "stats_util.h"
|
||||
#include "stats_log_util.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "guardrail/StatsdStats.h"
|
||||
#include "metrics/parsing_utils/metrics_manager_util.h"
|
||||
#include "stats_log_util.h"
|
||||
#include "stats_util.h"
|
||||
|
||||
using android::util::FIELD_COUNT_REPEATED;
|
||||
using android::util::FIELD_TYPE_BOOL;
|
||||
using android::util::FIELD_TYPE_FLOAT;
|
||||
@@ -64,8 +67,8 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
|
||||
|
||||
DurationMetricProducer::DurationMetricProducer(
|
||||
const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
|
||||
const vector<ConditionState>& initialConditionCache, const size_t startIndex,
|
||||
const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
|
||||
const vector<ConditionState>& initialConditionCache, const int startIndex,
|
||||
const int stopIndex, const int stopAllIndex, const bool nesting,
|
||||
const sp<ConditionWizard>& wizard, const uint64_t protoHash,
|
||||
const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
|
||||
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
|
||||
@@ -143,6 +146,84 @@ DurationMetricProducer::~DurationMetricProducer() {
|
||||
VLOG("~DurationMetric() called");
|
||||
}
|
||||
|
||||
bool DurationMetricProducer::onConfigUpdatedLocked(
|
||||
const StatsdConfig& config, const int configIndex, const int metricIndex,
|
||||
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
|
||||
const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
|
||||
const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
|
||||
const sp<EventMatcherWizard>& matcherWizard,
|
||||
const vector<sp<ConditionTracker>>& allConditionTrackers,
|
||||
const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
|
||||
const unordered_map<int64_t, int>& metricToActivationMap,
|
||||
unordered_map<int, vector<int>>& trackerToMetricMap,
|
||||
unordered_map<int, vector<int>>& conditionToMetricMap,
|
||||
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
|
||||
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
vector<int>& metricsWithActivation) {
|
||||
if (!MetricProducer::onConfigUpdatedLocked(
|
||||
config, configIndex, metricIndex, allAtomMatchingTrackers,
|
||||
oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
|
||||
allConditionTrackers, conditionTrackerMap, wizard, metricToActivationMap,
|
||||
trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap,
|
||||
deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const DurationMetric& metric = config.duration_metric(configIndex);
|
||||
const auto& what_it = conditionTrackerMap.find(metric.what());
|
||||
if (what_it == conditionTrackerMap.end()) {
|
||||
ALOGE("DurationMetric's \"what\" is not present in the config");
|
||||
return false;
|
||||
}
|
||||
|
||||
const Predicate& durationWhat = config.predicate(what_it->second);
|
||||
if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
|
||||
ALOGE("DurationMetric's \"what\" must be a simple condition");
|
||||
return false;
|
||||
}
|
||||
|
||||
const SimplePredicate& simplePredicate = durationWhat.simple_predicate();
|
||||
|
||||
// Update indices: mStartIndex, mStopIndex, mStopAllIndex, mConditionIndex and MetricsManager
|
||||
// maps.
|
||||
if (!handleMetricWithAtomMatchingTrackers(simplePredicate.start(), metricIndex,
|
||||
metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, newAtomMatchingTrackerMap,
|
||||
trackerToMetricMap, mStartIndex)) {
|
||||
ALOGE("Duration metrics must specify a valid start event matcher");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (simplePredicate.has_stop() &&
|
||||
!handleMetricWithAtomMatchingTrackers(simplePredicate.stop(), metricIndex,
|
||||
metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, newAtomMatchingTrackerMap,
|
||||
trackerToMetricMap, mStopIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (simplePredicate.has_stop_all() &&
|
||||
!handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex,
|
||||
metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, newAtomMatchingTrackerMap,
|
||||
trackerToMetricMap, mStopAllIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (metric.has_condition() &&
|
||||
!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
|
||||
metric.links(), allConditionTrackers, mConditionTrackerIndex,
|
||||
conditionToMetricMap)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& it : mCurrentSlicedDurationTrackerMap) {
|
||||
it.second->onConfigUpdated(wizard, mConditionTrackerIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
|
||||
const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
@@ -550,7 +631,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
|
||||
}
|
||||
|
||||
// Handles Stopall events.
|
||||
if (matcherIndex == mStopAllIndex) {
|
||||
if ((int)matcherIndex == mStopAllIndex) {
|
||||
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
|
||||
whatIt.second->noteStopAll(event.GetElapsedTimestampNs());
|
||||
}
|
||||
@@ -598,7 +679,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
|
||||
}
|
||||
|
||||
// Handles Stop events.
|
||||
if (matcherIndex == mStopIndex) {
|
||||
if ((int)matcherIndex == mStopIndex) {
|
||||
if (mUseWhatDimensionAsInternalDimension) {
|
||||
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
|
||||
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
|
||||
|
||||
@@ -40,8 +40,8 @@ class DurationMetricProducer : public MetricProducer {
|
||||
public:
|
||||
DurationMetricProducer(
|
||||
const ConfigKey& key, const DurationMetric& durationMetric, const int conditionIndex,
|
||||
const vector<ConditionState>& initialConditionCache, const size_t startIndex,
|
||||
const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
|
||||
const vector<ConditionState>& initialConditionCache, const int startIndex,
|
||||
const int stopIndex, const int stopAllIndex, const bool nesting,
|
||||
const sp<ConditionWizard>& wizard, const uint64_t protoHash,
|
||||
const FieldMatcher& internalDimensions, const int64_t timeBaseNs,
|
||||
const int64_t startTimeNs,
|
||||
@@ -112,16 +112,32 @@ private:
|
||||
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
|
||||
const int64_t& nextBucketStartTimeNs) override;
|
||||
|
||||
bool onConfigUpdatedLocked(
|
||||
const StatsdConfig& config, const int configIndex, const int metricIndex,
|
||||
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
|
||||
const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
|
||||
const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
|
||||
const sp<EventMatcherWizard>& matcherWizard,
|
||||
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
|
||||
const std::unordered_map<int64_t, int>& conditionTrackerMap,
|
||||
const sp<ConditionWizard>& wizard,
|
||||
const std::unordered_map<int64_t, int>& metricToActivationMap,
|
||||
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
std::vector<int>& metricsWithActivation) override;
|
||||
|
||||
const DurationMetric_AggregationType mAggregationType;
|
||||
|
||||
// Index of the SimpleAtomMatcher which defines the start.
|
||||
const size_t mStartIndex;
|
||||
int mStartIndex;
|
||||
|
||||
// Index of the SimpleAtomMatcher which defines the stop.
|
||||
const size_t mStopIndex;
|
||||
int mStopIndex;
|
||||
|
||||
// Index of the SimpleAtomMatcher which defines the stop all for all dimensions.
|
||||
const size_t mStopAllIndex;
|
||||
int mStopAllIndex;
|
||||
|
||||
// nest counting -- for the same key, stops must match the number of starts to make real stop
|
||||
const bool mNested;
|
||||
@@ -167,6 +183,8 @@ private:
|
||||
TestSumDurationWithSplitInFollowingBucket);
|
||||
FRIEND_TEST(DurationMetricProducerTest_PartialBucket, TestMaxDuration);
|
||||
FRIEND_TEST(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextBucket);
|
||||
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
|
||||
};
|
||||
|
||||
} // namespace statsd
|
||||
|
||||
@@ -569,6 +569,7 @@ protected:
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateCountMetrics);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateEventMetrics);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateGaugeMetrics);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateMetricsMultipleTypes);
|
||||
};
|
||||
|
||||
|
||||
@@ -89,6 +89,12 @@ public:
|
||||
|
||||
virtual ~DurationTracker(){};
|
||||
|
||||
void onConfigUpdated(const sp<ConditionWizard>& wizard, const int conditionTrackerIndex) {
|
||||
sp<ConditionWizard> tmpWizard = mWizard;
|
||||
mWizard = wizard;
|
||||
mConditionTrackerIndex = conditionTrackerIndex;
|
||||
};
|
||||
|
||||
virtual void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
|
||||
const ConditionKey& conditionKey) = 0;
|
||||
virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
|
||||
@@ -191,7 +197,7 @@ protected:
|
||||
|
||||
sp<ConditionWizard> mWizard;
|
||||
|
||||
const int mConditionTrackerIndex;
|
||||
int mConditionTrackerIndex;
|
||||
|
||||
const int64_t mBucketSizeNs;
|
||||
|
||||
@@ -217,6 +223,8 @@ protected:
|
||||
FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
|
||||
FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
|
||||
FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
|
||||
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
|
||||
};
|
||||
|
||||
} // namespace statsd
|
||||
|
||||
@@ -697,6 +697,43 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
|
||||
}
|
||||
newMetricProducers.push_back(producer.value());
|
||||
}
|
||||
for (int i = 0; i < config.duration_metric_size(); i++, metricIndex++) {
|
||||
const DurationMetric& metric = config.duration_metric(i);
|
||||
newMetricProducerMap[metric.id()] = metricIndex;
|
||||
optional<sp<MetricProducer>> producer;
|
||||
switch (metricsToUpdate[metricIndex]) {
|
||||
case UPDATE_PRESERVE: {
|
||||
producer = updateMetric(
|
||||
config, i, metricIndex, metric.id(), allAtomMatchingTrackers,
|
||||
oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
|
||||
allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap,
|
||||
oldMetricProducers, metricToActivationMap, trackerToMetricMap,
|
||||
conditionToMetricMap, activationAtomTrackerToMetricMap,
|
||||
deactivationAtomTrackerToMetricMap, metricsWithActivation);
|
||||
break;
|
||||
}
|
||||
case UPDATE_REPLACE:
|
||||
case UPDATE_NEW: {
|
||||
producer = createDurationMetricProducerAndUpdateMetadata(
|
||||
key, config, timeBaseNs, currentTimeNs, metric, metricIndex,
|
||||
allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers,
|
||||
conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
|
||||
allStateGroupMaps, metricToActivationMap, trackerToMetricMap,
|
||||
conditionToMetricMap, activationAtomTrackerToMetricMap,
|
||||
deactivationAtomTrackerToMetricMap, metricsWithActivation);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ALOGE("Metric \"%lld\" update state is unknown. This should never happen",
|
||||
(long long)metric.id());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!producer) {
|
||||
return false;
|
||||
}
|
||||
newMetricProducers.push_back(producer.value());
|
||||
}
|
||||
for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
|
||||
newMetricProducerMap[config.event_metric(i).id()] = metricIndex;
|
||||
const EventMetric& metric = config.event_metric(i);
|
||||
@@ -770,7 +807,7 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
|
||||
}
|
||||
newMetricProducers.push_back(producer.value());
|
||||
}
|
||||
// TODO: perform update for value, duration metric.
|
||||
// TODO: perform update for value metric.
|
||||
|
||||
const set<int> atomsAllowedFromAnyUid(config.whitelisted_atom_ids().begin(),
|
||||
config.whitelisted_atom_ids().end());
|
||||
|
||||
@@ -365,7 +365,7 @@ optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata(
|
||||
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
vector<int>& metricsWithActivation) {
|
||||
if (!metric.has_id() || !metric.has_what()) {
|
||||
ALOGW("cannot find metric id or \"what\" in CountMetric \"%lld\"", (long long)metric.id());
|
||||
ALOGE("cannot find metric id or \"what\" in CountMetric \"%lld\"", (long long)metric.id());
|
||||
return nullopt;
|
||||
}
|
||||
int trackerIndex;
|
||||
@@ -423,6 +423,125 @@ optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata(
|
||||
eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
|
||||
}
|
||||
|
||||
optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
|
||||
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
|
||||
const int64_t currentTimeNs, const DurationMetric& metric, const int metricIndex,
|
||||
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
|
||||
const unordered_map<int64_t, int>& atomMatchingTrackerMap,
|
||||
vector<sp<ConditionTracker>>& allConditionTrackers,
|
||||
const unordered_map<int64_t, int>& conditionTrackerMap,
|
||||
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
|
||||
const unordered_map<int64_t, int>& stateAtomIdMap,
|
||||
const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
|
||||
const unordered_map<int64_t, int>& metricToActivationMap,
|
||||
unordered_map<int, vector<int>>& trackerToMetricMap,
|
||||
unordered_map<int, vector<int>>& conditionToMetricMap,
|
||||
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
|
||||
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
vector<int>& metricsWithActivation) {
|
||||
if (!metric.has_id() || !metric.has_what()) {
|
||||
ALOGE("cannot find metric id or \"what\" in DurationMetric \"%lld\"",
|
||||
(long long)metric.id());
|
||||
return nullopt;
|
||||
}
|
||||
const auto& what_it = conditionTrackerMap.find(metric.what());
|
||||
if (what_it == conditionTrackerMap.end()) {
|
||||
ALOGE("DurationMetric's \"what\" is not present in the condition trackers");
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
const Predicate& durationWhat = config.predicate(what_it->second);
|
||||
if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
|
||||
ALOGE("DurationMetric's \"what\" must be a simple condition");
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
const SimplePredicate& simplePredicate = durationWhat.simple_predicate();
|
||||
bool nesting = simplePredicate.count_nesting();
|
||||
|
||||
int startIndex = -1, stopIndex = -1, stopAllIndex = -1;
|
||||
if (!simplePredicate.has_start() ||
|
||||
!handleMetricWithAtomMatchingTrackers(
|
||||
simplePredicate.start(), metricIndex, metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, startIndex)) {
|
||||
ALOGE("Duration metrics must specify a valid start event matcher");
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
if (simplePredicate.has_stop() &&
|
||||
!handleMetricWithAtomMatchingTrackers(
|
||||
simplePredicate.stop(), metricIndex, metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, stopIndex)) {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
if (simplePredicate.has_stop_all() &&
|
||||
!handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex,
|
||||
metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap,
|
||||
trackerToMetricMap, stopAllIndex)) {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
FieldMatcher internalDimensions = simplePredicate.dimensions();
|
||||
|
||||
int conditionIndex = -1;
|
||||
if (metric.has_condition()) {
|
||||
if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
|
||||
metric.links(), allConditionTrackers, conditionIndex,
|
||||
conditionToMetricMap)) {
|
||||
return nullopt;
|
||||
}
|
||||
} else if (metric.links_size() > 0) {
|
||||
ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
std::vector<int> slicedStateAtoms;
|
||||
unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
|
||||
if (metric.slice_by_state_size() > 0) {
|
||||
if (metric.aggregation_type() == DurationMetric::MAX_SPARSE) {
|
||||
ALOGE("DurationMetric with aggregation type MAX_SPARSE cannot be sliced by state");
|
||||
return nullopt;
|
||||
}
|
||||
if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
|
||||
allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
|
||||
return nullopt;
|
||||
}
|
||||
} else if (metric.state_link_size() > 0) {
|
||||
ALOGW("DurationMetric has a MetricStateLink but doesn't have a sliced state");
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
// Check that all metric state links are a subset of dimensions_in_what fields.
|
||||
std::vector<Matcher> dimensionsInWhat;
|
||||
translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
|
||||
for (const auto& stateLink : metric.state_link()) {
|
||||
if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) {
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
|
||||
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
|
||||
if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
|
||||
atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
|
||||
deactivationAtomTrackerToMetricMap, metricsWithActivation,
|
||||
eventActivationMap, eventDeactivationMap)) {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
uint64_t metricHash;
|
||||
if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
return {new DurationMetricProducer(
|
||||
key, metric, conditionIndex, initialConditionCache, startIndex, stopIndex, stopAllIndex,
|
||||
nesting, wizard, metricHash, internalDimensions, timeBaseNs, currentTimeNs,
|
||||
eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
|
||||
}
|
||||
|
||||
optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
|
||||
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
|
||||
const EventMetric& metric, const int metricIndex,
|
||||
@@ -438,7 +557,7 @@ optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
|
||||
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
vector<int>& metricsWithActivation) {
|
||||
if (!metric.has_id() || !metric.has_what()) {
|
||||
ALOGW("cannot find the metric name or what in config");
|
||||
ALOGE("cannot find the metric name or what in config");
|
||||
return nullopt;
|
||||
}
|
||||
int trackerIndex;
|
||||
@@ -497,7 +616,7 @@ optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata(
|
||||
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
vector<int>& metricsWithActivation) {
|
||||
if (!metric.has_id() || !metric.has_what()) {
|
||||
ALOGW("cannot find metric id or \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
|
||||
ALOGE("cannot find metric id or \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
@@ -760,114 +879,17 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
|
||||
const DurationMetric& metric = config.duration_metric(i);
|
||||
metricMap.insert({metric.id(), metricIndex});
|
||||
|
||||
auto what_it = conditionTrackerMap.find(metric.what());
|
||||
if (what_it == conditionTrackerMap.end()) {
|
||||
ALOGE("DurationMetric's \"what\" is invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
const Predicate& durationWhat = config.predicate(what_it->second);
|
||||
|
||||
if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
|
||||
ALOGE("DurationMetric's \"what\" must be a simple condition");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& simplePredicate = durationWhat.simple_predicate();
|
||||
|
||||
bool nesting = simplePredicate.count_nesting();
|
||||
|
||||
int trackerIndices[3] = {-1, -1, -1};
|
||||
if (!simplePredicate.has_start() ||
|
||||
!handleMetricWithAtomMatchingTrackers(simplePredicate.start(), metricIndex,
|
||||
metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap,
|
||||
trackerToMetricMap, trackerIndices[0])) {
|
||||
ALOGE("Duration metrics must specify a valid the start event matcher");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (simplePredicate.has_stop() &&
|
||||
!handleMetricWithAtomMatchingTrackers(simplePredicate.stop(), metricIndex,
|
||||
metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap,
|
||||
trackerToMetricMap, trackerIndices[1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (simplePredicate.has_stop_all() &&
|
||||
!handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex,
|
||||
metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap,
|
||||
trackerToMetricMap, trackerIndices[2])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FieldMatcher internalDimensions = simplePredicate.dimensions();
|
||||
|
||||
int conditionIndex = -1;
|
||||
|
||||
if (metric.has_condition()) {
|
||||
bool good = handleMetricWithConditions(
|
||||
metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
|
||||
allConditionTrackers, conditionIndex, conditionToMetricMap);
|
||||
if (!good) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (metric.links_size() > 0) {
|
||||
ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> slicedStateAtoms;
|
||||
unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
|
||||
if (metric.slice_by_state_size() > 0) {
|
||||
if (metric.aggregation_type() == DurationMetric::MAX_SPARSE) {
|
||||
ALOGE("DurationMetric with aggregation type MAX_SPARSE cannot be sliced by state");
|
||||
return false;
|
||||
}
|
||||
if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
|
||||
allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (metric.state_link_size() > 0) {
|
||||
ALOGW("DurationMetric has a MetricStateLink but doesn't have a sliced state");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all metric state links are a subset of dimensions_in_what fields.
|
||||
std::vector<Matcher> dimensionsInWhat;
|
||||
translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
|
||||
for (const auto& stateLink : metric.state_link()) {
|
||||
if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
|
||||
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
|
||||
bool success = handleMetricActivation(
|
||||
config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
|
||||
optional<sp<MetricProducer>> producer = createDurationMetricProducerAndUpdateMetadata(
|
||||
key, config, timeBaseTimeNs, currentTimeNs, metric, metricIndex,
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
|
||||
conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
|
||||
allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
|
||||
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
|
||||
metricsWithActivation, eventActivationMap, eventDeactivationMap);
|
||||
if (!success) return false;
|
||||
|
||||
uint64_t metricHash;
|
||||
if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
|
||||
metricsWithActivation);
|
||||
if (!producer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sp<MetricProducer> durationMetric = new DurationMetricProducer(
|
||||
key, metric, conditionIndex, initialConditionCache, trackerIndices[0],
|
||||
trackerIndices[1], trackerIndices[2], nesting, wizard, metricHash,
|
||||
internalDimensions, timeBaseTimeNs, currentTimeNs, eventActivationMap,
|
||||
eventDeactivationMap, slicedStateAtoms, stateGroupMap);
|
||||
|
||||
allMetricProducers.push_back(durationMetric);
|
||||
allMetricProducers.push_back(producer.value());
|
||||
}
|
||||
|
||||
// build EventMetricProducer
|
||||
|
||||
@@ -112,6 +112,25 @@ optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata(
|
||||
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
std::vector<int>& metricsWithActivation);
|
||||
|
||||
// Creates a DurationMetricProducer and updates the vectors/maps used by MetricsManager with
|
||||
// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
|
||||
optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
|
||||
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
|
||||
const int64_t currentTimeNs, const DurationMetric& metric, const int metricIndex,
|
||||
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
|
||||
const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
|
||||
std::vector<sp<ConditionTracker>>& allConditionTrackers,
|
||||
const std::unordered_map<int64_t, int>& conditionTrackerMap,
|
||||
const std::vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
|
||||
const std::unordered_map<int64_t, int>& stateAtomIdMap,
|
||||
const std::unordered_map<int64_t, std::unordered_map<int, int64_t>>& allStateGroupMaps,
|
||||
const std::unordered_map<int64_t, int>& metricToActivationMap,
|
||||
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
|
||||
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
std::vector<int>& metricsWithActivation);
|
||||
|
||||
// Creates an EventMetricProducer and updates the vectors/maps used by MetricsManager with
|
||||
// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
|
||||
optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "src/condition/CombinationConditionTracker.h"
|
||||
#include "src/condition/SimpleConditionTracker.h"
|
||||
#include "src/matchers/CombinationAtomMatchingTracker.h"
|
||||
#include "src/metrics/DurationMetricProducer.h"
|
||||
#include "src/metrics/GaugeMetricProducer.h"
|
||||
#include "src/metrics/parsing_utils/metrics_manager_util.h"
|
||||
#include "tests/statsd_test_util.h"
|
||||
@@ -2212,6 +2213,352 @@ TEST_F(ConfigUpdateTest, TestUpdateGaugeMetrics) {
|
||||
EXPECT_EQ(oldMatcherWizard->getStrongCount(), 1);
|
||||
}
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestUpdateDurationMetrics) {
|
||||
StatsdConfig config;
|
||||
// Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig.
|
||||
AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
|
||||
int64_t matcher1Id = matcher1.id();
|
||||
*config.add_atom_matcher() = matcher1;
|
||||
|
||||
AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
|
||||
int64_t matcher2Id = matcher2.id();
|
||||
*config.add_atom_matcher() = matcher2;
|
||||
|
||||
AtomMatcher matcher3 = CreateAcquireWakelockAtomMatcher();
|
||||
int64_t matcher3Id = matcher3.id();
|
||||
*config.add_atom_matcher() = matcher3;
|
||||
|
||||
AtomMatcher matcher4 = CreateReleaseWakelockAtomMatcher();
|
||||
int64_t matcher4Id = matcher4.id();
|
||||
*config.add_atom_matcher() = matcher4;
|
||||
|
||||
AtomMatcher matcher5 = CreateMoveToForegroundAtomMatcher();
|
||||
int64_t matcher5Id = matcher5.id();
|
||||
*config.add_atom_matcher() = matcher5;
|
||||
|
||||
AtomMatcher matcher6 = CreateMoveToBackgroundAtomMatcher();
|
||||
int64_t matcher6Id = matcher6.id();
|
||||
*config.add_atom_matcher() = matcher6;
|
||||
|
||||
AtomMatcher matcher7 = CreateBatteryStateNoneMatcher();
|
||||
int64_t matcher7Id = matcher7.id();
|
||||
*config.add_atom_matcher() = matcher7;
|
||||
|
||||
AtomMatcher matcher8 = CreateBatteryStateUsbMatcher();
|
||||
int64_t matcher8Id = matcher8.id();
|
||||
*config.add_atom_matcher() = matcher8;
|
||||
|
||||
Predicate predicate1 = CreateScreenIsOnPredicate();
|
||||
int64_t predicate1Id = predicate1.id();
|
||||
*config.add_predicate() = predicate1;
|
||||
|
||||
Predicate predicate2 = CreateScreenIsOffPredicate();
|
||||
int64_t predicate2Id = predicate2.id();
|
||||
*config.add_predicate() = predicate2;
|
||||
|
||||
Predicate predicate3 = CreateDeviceUnpluggedPredicate();
|
||||
int64_t predicate3Id = predicate3.id();
|
||||
*config.add_predicate() = predicate3;
|
||||
|
||||
Predicate predicate4 = CreateIsInBackgroundPredicate();
|
||||
*predicate4.mutable_simple_predicate()->mutable_dimensions() =
|
||||
CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1});
|
||||
int64_t predicate4Id = predicate4.id();
|
||||
*config.add_predicate() = predicate4;
|
||||
|
||||
Predicate predicate5 = CreateHoldingWakelockPredicate();
|
||||
*predicate5.mutable_simple_predicate()->mutable_dimensions() =
|
||||
CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
|
||||
predicate5.mutable_simple_predicate()->set_stop_all(matcher7Id);
|
||||
int64_t predicate5Id = predicate5.id();
|
||||
*config.add_predicate() = predicate5;
|
||||
|
||||
State state1 = CreateScreenStateWithOnOffMap(0x123, 0x321);
|
||||
int64_t state1Id = state1.id();
|
||||
*config.add_state() = state1;
|
||||
|
||||
State state2 = CreateScreenState();
|
||||
int64_t state2Id = state2.id();
|
||||
*config.add_state() = state2;
|
||||
|
||||
// Add a few duration metrics.
|
||||
// Will be preserved.
|
||||
DurationMetric duration1 =
|
||||
createDurationMetric("DURATION1", predicate5Id, predicate4Id, {state2Id});
|
||||
*duration1.mutable_dimensions_in_what() =
|
||||
CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
|
||||
MetricConditionLink* link = duration1.add_links();
|
||||
link->set_condition(predicate4Id);
|
||||
*link->mutable_fields_in_what() =
|
||||
CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
|
||||
*link->mutable_fields_in_condition() =
|
||||
CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/);
|
||||
int64_t duration1Id = duration1.id();
|
||||
*config.add_duration_metric() = duration1;
|
||||
|
||||
// Will be replaced.
|
||||
DurationMetric duration2 = createDurationMetric("DURATION2", predicate1Id, nullopt, {});
|
||||
int64_t duration2Id = duration2.id();
|
||||
*config.add_duration_metric() = duration2;
|
||||
|
||||
// Will be replaced.
|
||||
DurationMetric duration3 = createDurationMetric("DURATION3", predicate3Id, nullopt, {state1Id});
|
||||
int64_t duration3Id = duration3.id();
|
||||
*config.add_duration_metric() = duration3;
|
||||
|
||||
// Will be replaced.
|
||||
DurationMetric duration4 = createDurationMetric("DURATION4", predicate3Id, predicate2Id, {});
|
||||
int64_t duration4Id = duration4.id();
|
||||
*config.add_duration_metric() = duration4;
|
||||
|
||||
// Will be deleted.
|
||||
DurationMetric duration5 = createDurationMetric("DURATION5", predicate2Id, nullopt, {});
|
||||
int64_t duration5Id = duration5.id();
|
||||
*config.add_duration_metric() = duration5;
|
||||
|
||||
EXPECT_TRUE(initConfig(config));
|
||||
|
||||
// Make some sliced conditions true.
|
||||
int uid1 = 10;
|
||||
int uid2 = 11;
|
||||
vector<MatchingState> matchingStates(8, MatchingState::kNotMatched);
|
||||
matchingStates[2] = kMatched;
|
||||
vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated);
|
||||
vector<bool> changedCache(5, false);
|
||||
unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(timeBaseNs + 3, {uid1}, {"tag"}, "wl1");
|
||||
oldConditionTrackers[4]->evaluateCondition(*event.get(), matchingStates, oldConditionTrackers,
|
||||
conditionCache, changedCache);
|
||||
EXPECT_TRUE(oldConditionTrackers[4]->isSliced());
|
||||
EXPECT_TRUE(changedCache[4]);
|
||||
EXPECT_EQ(conditionCache[4], ConditionState::kTrue);
|
||||
oldMetricProducers[0]->onMatchedLogEvent(2, *event.get());
|
||||
|
||||
fill(conditionCache.begin(), conditionCache.end(), ConditionState::kNotEvaluated);
|
||||
fill(changedCache.begin(), changedCache.end(), false);
|
||||
event = CreateAcquireWakelockEvent(timeBaseNs + 3, {uid2}, {"tag"}, "wl2");
|
||||
oldConditionTrackers[4]->evaluateCondition(*event.get(), matchingStates, oldConditionTrackers,
|
||||
conditionCache, changedCache);
|
||||
EXPECT_TRUE(changedCache[4]);
|
||||
EXPECT_EQ(conditionCache[4], ConditionState::kTrue);
|
||||
oldMetricProducers[0]->onMatchedLogEvent(2, *event.get());
|
||||
|
||||
// Used later to ensure the condition wizard is replaced. Get it before doing the update.
|
||||
// The duration trackers have a pointer to the wizard, and 2 trackers were created above.
|
||||
sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard;
|
||||
EXPECT_EQ(oldConditionWizard->getStrongCount(), 8);
|
||||
|
||||
// Replace predicate1, predicate3, and state1. Causes duration2/3/4 to be replaced.
|
||||
set<int64_t> replacedConditions({predicate1Id, predicate2Id});
|
||||
set<int64_t> replacedStates({state1Id});
|
||||
|
||||
// New duration metric.
|
||||
DurationMetric duration6 = createDurationMetric("DURATION6", predicate4Id, predicate5Id, {});
|
||||
*duration6.mutable_dimensions_in_what() =
|
||||
CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/);
|
||||
link = duration6.add_links();
|
||||
link->set_condition(predicate5Id);
|
||||
*link->mutable_fields_in_what() =
|
||||
CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/);
|
||||
*link->mutable_fields_in_condition() =
|
||||
CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
|
||||
int64_t duration6Id = duration6.id();
|
||||
|
||||
// Map the matchers and predicates in reverse order to force the indices to change.
|
||||
const int matcher8Index = 0, matcher7Index = 1, matcher6Index = 2, matcher5Index = 3,
|
||||
matcher4Index = 4, matcher3Index = 5, matcher2Index = 6, matcher1Index = 7;
|
||||
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap({{matcher8Id, matcher8Index},
|
||||
{matcher7Id, matcher7Index},
|
||||
{matcher6Id, matcher6Index},
|
||||
{matcher5Id, matcher5Index},
|
||||
{matcher4Id, matcher4Index},
|
||||
{matcher3Id, matcher3Index},
|
||||
{matcher2Id, matcher2Index},
|
||||
{matcher1Id, matcher1Index}});
|
||||
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
|
||||
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(8);
|
||||
reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
|
||||
newAtomMatchingTrackers.begin());
|
||||
|
||||
const int predicate5Index = 0, predicate4Index = 1, predicate3Index = 2, predicate2Index = 3,
|
||||
predicate1Index = 4;
|
||||
std::unordered_map<int64_t, int> newConditionTrackerMap({
|
||||
{predicate5Id, predicate5Index},
|
||||
{predicate4Id, predicate4Index},
|
||||
{predicate3Id, predicate3Index},
|
||||
{predicate2Id, predicate2Index},
|
||||
{predicate1Id, predicate1Index},
|
||||
});
|
||||
// Use the existing conditionTrackers and reinitialize them to get the initial condition cache.
|
||||
vector<sp<ConditionTracker>> newConditionTrackers(5);
|
||||
reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
|
||||
newConditionTrackers.begin());
|
||||
vector<Predicate> conditionProtos(5);
|
||||
reverse_copy(config.predicate().begin(), config.predicate().end(), conditionProtos.begin());
|
||||
for (int i = 0; i < newConditionTrackers.size(); i++) {
|
||||
EXPECT_TRUE(newConditionTrackers[i]->onConfigUpdated(
|
||||
conditionProtos, i, newConditionTrackers, newAtomMatchingTrackerMap,
|
||||
newConditionTrackerMap));
|
||||
}
|
||||
vector<bool> cycleTracker(5, false);
|
||||
fill(conditionCache.begin(), conditionCache.end(), ConditionState::kNotEvaluated);
|
||||
for (int i = 0; i < newConditionTrackers.size(); i++) {
|
||||
EXPECT_TRUE(newConditionTrackers[i]->init(conditionProtos, newConditionTrackers,
|
||||
newConditionTrackerMap, cycleTracker,
|
||||
conditionCache));
|
||||
}
|
||||
// Predicate5 should be true since 2 uids have wakelocks
|
||||
EXPECT_EQ(conditionCache, vector({kTrue, kUnknown, kUnknown, kUnknown, kUnknown}));
|
||||
|
||||
StatsdConfig newConfig;
|
||||
*newConfig.add_duration_metric() = duration6;
|
||||
const int duration6Index = 0;
|
||||
*newConfig.add_duration_metric() = duration3;
|
||||
const int duration3Index = 1;
|
||||
*newConfig.add_duration_metric() = duration1;
|
||||
const int duration1Index = 2;
|
||||
*newConfig.add_duration_metric() = duration4;
|
||||
const int duration4Index = 3;
|
||||
*newConfig.add_duration_metric() = duration2;
|
||||
const int duration2Index = 4;
|
||||
|
||||
for (const Predicate& predicate : conditionProtos) {
|
||||
*newConfig.add_predicate() = predicate;
|
||||
}
|
||||
*newConfig.add_state() = state1;
|
||||
*newConfig.add_state() = state2;
|
||||
unordered_map<int64_t, int> stateAtomIdMap;
|
||||
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
|
||||
map<int64_t, uint64_t> stateProtoHashes;
|
||||
EXPECT_TRUE(initStates(newConfig, stateAtomIdMap, allStateGroupMaps, stateProtoHashes));
|
||||
|
||||
// Output data structures to validate.
|
||||
unordered_map<int64_t, int> newMetricProducerMap;
|
||||
vector<sp<MetricProducer>> newMetricProducers;
|
||||
unordered_map<int, vector<int>> conditionToMetricMap;
|
||||
unordered_map<int, vector<int>> trackerToMetricMap;
|
||||
set<int64_t> noReportMetricIds;
|
||||
unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
|
||||
unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
|
||||
vector<int> metricsWithActivation;
|
||||
EXPECT_TRUE(updateMetrics(
|
||||
key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
|
||||
oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, /*replacedMatchers=*/{},
|
||||
newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
|
||||
newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
|
||||
oldMetricProducerMap, oldMetricProducers, newMetricProducerMap, newMetricProducers,
|
||||
conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
|
||||
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
|
||||
metricsWithActivation));
|
||||
|
||||
unordered_map<int64_t, int> expectedMetricProducerMap = {
|
||||
{duration1Id, duration1Index}, {duration2Id, duration2Index},
|
||||
{duration3Id, duration3Index}, {duration4Id, duration4Index},
|
||||
{duration6Id, duration6Index},
|
||||
};
|
||||
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
|
||||
|
||||
// Make sure preserved metrics are the same.
|
||||
ASSERT_EQ(newMetricProducers.size(), 5);
|
||||
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(duration1Id)],
|
||||
newMetricProducers[newMetricProducerMap.at(duration1Id)]);
|
||||
|
||||
// Make sure replaced metrics are different.
|
||||
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration2Id)],
|
||||
newMetricProducers[newMetricProducerMap.at(duration2Id)]);
|
||||
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration3Id)],
|
||||
newMetricProducers[newMetricProducerMap.at(duration3Id)]);
|
||||
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration4Id)],
|
||||
newMetricProducers[newMetricProducerMap.at(duration4Id)]);
|
||||
|
||||
// Verify the conditionToMetricMap. Note that the "what" is not in this map.
|
||||
ASSERT_EQ(conditionToMetricMap.size(), 3);
|
||||
const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
|
||||
EXPECT_THAT(condition2Metrics, UnorderedElementsAre(duration4Index));
|
||||
const vector<int>& condition4Metrics = conditionToMetricMap[predicate4Index];
|
||||
EXPECT_THAT(condition4Metrics, UnorderedElementsAre(duration1Index));
|
||||
const vector<int>& condition5Metrics = conditionToMetricMap[predicate5Index];
|
||||
EXPECT_THAT(condition5Metrics, UnorderedElementsAre(duration6Index));
|
||||
|
||||
// Verify the trackerToMetricMap. The start/stop/stopall indices from the "what" should be here.
|
||||
ASSERT_EQ(trackerToMetricMap.size(), 8);
|
||||
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
|
||||
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(duration2Index));
|
||||
const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
|
||||
EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(duration2Index));
|
||||
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
|
||||
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(duration1Index));
|
||||
const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
|
||||
EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(duration1Index));
|
||||
const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
|
||||
EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(duration6Index));
|
||||
const vector<int>& matcher6Metrics = trackerToMetricMap[matcher6Index];
|
||||
EXPECT_THAT(matcher6Metrics, UnorderedElementsAre(duration6Index));
|
||||
const vector<int>& matcher7Metrics = trackerToMetricMap[matcher7Index];
|
||||
EXPECT_THAT(matcher7Metrics,
|
||||
UnorderedElementsAre(duration1Index, duration3Index, duration4Index));
|
||||
const vector<int>& matcher8Metrics = trackerToMetricMap[matcher8Index];
|
||||
EXPECT_THAT(matcher8Metrics, UnorderedElementsAre(duration3Index, duration4Index));
|
||||
|
||||
// Verify event activation/deactivation maps.
|
||||
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
|
||||
ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
|
||||
ASSERT_EQ(metricsWithActivation.size(), 0);
|
||||
|
||||
// Verify tracker indices/ids/conditions are correct.
|
||||
DurationMetricProducer* durationProducer1 =
|
||||
static_cast<DurationMetricProducer*>(newMetricProducers[duration1Index].get());
|
||||
EXPECT_EQ(durationProducer1->getMetricId(), duration1Id);
|
||||
EXPECT_EQ(durationProducer1->mConditionTrackerIndex, predicate4Index);
|
||||
EXPECT_EQ(durationProducer1->mCondition, ConditionState::kUnknown);
|
||||
EXPECT_EQ(durationProducer1->mStartIndex, matcher3Index);
|
||||
EXPECT_EQ(durationProducer1->mStopIndex, matcher4Index);
|
||||
EXPECT_EQ(durationProducer1->mStopAllIndex, matcher7Index);
|
||||
EXPECT_EQ(durationProducer1->mCurrentSlicedDurationTrackerMap.size(), 2);
|
||||
for (const auto& durationTrackerIt : durationProducer1->mCurrentSlicedDurationTrackerMap) {
|
||||
EXPECT_EQ(durationTrackerIt.second->mConditionTrackerIndex, predicate4Index);
|
||||
}
|
||||
DurationMetricProducer* durationProducer2 =
|
||||
static_cast<DurationMetricProducer*>(newMetricProducers[duration2Index].get());
|
||||
EXPECT_EQ(durationProducer2->getMetricId(), duration2Id);
|
||||
EXPECT_EQ(durationProducer2->mConditionTrackerIndex, -1);
|
||||
EXPECT_EQ(durationProducer2->mCondition, ConditionState::kTrue);
|
||||
EXPECT_EQ(durationProducer2->mStartIndex, matcher1Index);
|
||||
EXPECT_EQ(durationProducer2->mStopIndex, matcher2Index);
|
||||
EXPECT_EQ(durationProducer2->mStopAllIndex, -1);
|
||||
DurationMetricProducer* durationProducer3 =
|
||||
static_cast<DurationMetricProducer*>(newMetricProducers[duration3Index].get());
|
||||
EXPECT_EQ(durationProducer3->getMetricId(), duration3Id);
|
||||
EXPECT_EQ(durationProducer3->mConditionTrackerIndex, -1);
|
||||
EXPECT_EQ(durationProducer3->mCondition, ConditionState::kTrue);
|
||||
EXPECT_EQ(durationProducer3->mStartIndex, matcher7Index);
|
||||
EXPECT_EQ(durationProducer3->mStopIndex, matcher8Index);
|
||||
EXPECT_EQ(durationProducer3->mStopAllIndex, -1);
|
||||
DurationMetricProducer* durationProducer4 =
|
||||
static_cast<DurationMetricProducer*>(newMetricProducers[duration4Index].get());
|
||||
EXPECT_EQ(durationProducer4->getMetricId(), duration4Id);
|
||||
EXPECT_EQ(durationProducer4->mConditionTrackerIndex, predicate2Index);
|
||||
EXPECT_EQ(durationProducer4->mCondition, ConditionState::kUnknown);
|
||||
EXPECT_EQ(durationProducer4->mStartIndex, matcher7Index);
|
||||
EXPECT_EQ(durationProducer4->mStopIndex, matcher8Index);
|
||||
EXPECT_EQ(durationProducer4->mStopAllIndex, -1);
|
||||
DurationMetricProducer* durationProducer6 =
|
||||
static_cast<DurationMetricProducer*>(newMetricProducers[duration6Index].get());
|
||||
EXPECT_EQ(durationProducer6->getMetricId(), duration6Id);
|
||||
EXPECT_EQ(durationProducer6->mConditionTrackerIndex, predicate5Index);
|
||||
// TODO(b/167491517): should this be unknown since the condition is sliced?
|
||||
EXPECT_EQ(durationProducer6->mCondition, ConditionState::kTrue);
|
||||
EXPECT_EQ(durationProducer6->mStartIndex, matcher6Index);
|
||||
EXPECT_EQ(durationProducer6->mStopIndex, matcher5Index);
|
||||
EXPECT_EQ(durationProducer6->mStopAllIndex, -1);
|
||||
|
||||
sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
|
||||
EXPECT_NE(newConditionWizard, oldConditionWizard);
|
||||
EXPECT_EQ(newConditionWizard->getStrongCount(), 8);
|
||||
oldMetricProducers.clear();
|
||||
// Only reference to the old wizard should be the one in the test.
|
||||
EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
|
||||
}
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestUpdateMetricActivations) {
|
||||
StatsdConfig config;
|
||||
// Add atom matchers
|
||||
@@ -2376,11 +2723,16 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
int64_t gaugeMetricId = gaugeMetric.id();
|
||||
*config.add_gauge_metric() = gaugeMetric;
|
||||
|
||||
// Preserved.
|
||||
DurationMetric durationMetric = createDurationMetric("DURATION1", predicate1Id, nullopt, {});
|
||||
int64_t durationMetricId = durationMetric.id();
|
||||
*config.add_duration_metric() = durationMetric;
|
||||
|
||||
EXPECT_TRUE(initConfig(config));
|
||||
|
||||
// Used later to ensure the condition wizard is replaced. Get it before doing the update.
|
||||
sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard;
|
||||
EXPECT_EQ(oldConditionWizard->getStrongCount(), 4);
|
||||
EXPECT_EQ(oldConditionWizard->getStrongCount(), 5);
|
||||
|
||||
// Mark matcher 2 as replaced. Causes eventMetric to be replaced.
|
||||
set<int64_t> replacedMatchers;
|
||||
@@ -2414,10 +2766,15 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
StatsdConfig newConfig;
|
||||
*newConfig.add_count_metric() = countMetric;
|
||||
const int countMetricIndex = 0;
|
||||
*newConfig.add_duration_metric() = durationMetric;
|
||||
const int durationMetricIndex = 1;
|
||||
*newConfig.add_event_metric() = eventMetric;
|
||||
const int eventMetricIndex = 1;
|
||||
const int eventMetricIndex = 2;
|
||||
*newConfig.add_gauge_metric() = gaugeMetric;
|
||||
const int gaugeMetricIndex = 2;
|
||||
const int gaugeMetricIndex = 3;
|
||||
|
||||
// Add the predicate since duration metric needs it.
|
||||
*newConfig.add_predicate() = predicate1;
|
||||
|
||||
// Output data structures to validate.
|
||||
unordered_map<int64_t, int> newMetricProducerMap;
|
||||
@@ -2440,15 +2797,18 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
|
||||
unordered_map<int64_t, int> expectedMetricProducerMap = {
|
||||
{countMetricId, countMetricIndex},
|
||||
{durationMetricId, durationMetricIndex},
|
||||
{eventMetricId, eventMetricIndex},
|
||||
{gaugeMetricId, gaugeMetricIndex},
|
||||
};
|
||||
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
|
||||
|
||||
// Make sure preserved metrics are the same.
|
||||
ASSERT_EQ(newMetricProducers.size(), 3);
|
||||
ASSERT_EQ(newMetricProducers.size(), 4);
|
||||
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(countMetricId)],
|
||||
newMetricProducers[newMetricProducerMap.at(countMetricId)]);
|
||||
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(durationMetricId)],
|
||||
newMetricProducers[newMetricProducerMap.at(durationMetricId)]);
|
||||
|
||||
// Make sure replaced metrics are different.
|
||||
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(eventMetricId)],
|
||||
@@ -2464,9 +2824,9 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
// Verify the trackerToMetricMap.
|
||||
ASSERT_EQ(trackerToMetricMap.size(), 3);
|
||||
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
|
||||
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(countMetricIndex));
|
||||
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(countMetricIndex, durationMetricIndex));
|
||||
const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
|
||||
EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(eventMetricIndex));
|
||||
EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(eventMetricIndex, durationMetricIndex));
|
||||
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
|
||||
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(gaugeMetricIndex));
|
||||
|
||||
@@ -2479,6 +2839,9 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
EXPECT_EQ(newMetricProducers[countMetricIndex]->getMetricId(), countMetricId);
|
||||
EXPECT_EQ(newMetricProducers[countMetricIndex]->mConditionTrackerIndex, predicate1Index);
|
||||
EXPECT_EQ(newMetricProducers[countMetricIndex]->mCondition, ConditionState::kUnknown);
|
||||
EXPECT_EQ(newMetricProducers[durationMetricIndex]->getMetricId(), durationMetricId);
|
||||
EXPECT_EQ(newMetricProducers[durationMetricIndex]->mConditionTrackerIndex, -1);
|
||||
EXPECT_EQ(newMetricProducers[durationMetricIndex]->mCondition, ConditionState::kTrue);
|
||||
EXPECT_EQ(newMetricProducers[eventMetricIndex]->getMetricId(), eventMetricId);
|
||||
EXPECT_EQ(newMetricProducers[eventMetricIndex]->mConditionTrackerIndex, -1);
|
||||
EXPECT_EQ(newMetricProducers[eventMetricIndex]->mCondition, ConditionState::kTrue);
|
||||
@@ -2488,7 +2851,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
|
||||
sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
|
||||
EXPECT_NE(newConditionWizard, oldConditionWizard);
|
||||
EXPECT_EQ(newConditionWizard->getStrongCount(), 4);
|
||||
EXPECT_EQ(newConditionWizard->getStrongCount(), 5);
|
||||
oldMetricProducers.clear();
|
||||
// Only reference to the old wizard should be the one in the test.
|
||||
EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
|
||||
|
||||
Reference in New Issue
Block a user