Perform update for value metric
Like other metrics, preserved metrics have indices and maps updated. New/replaced metrics get recreated as if it was a brand new metric. Test: atest statsd_test Bug: 162321957 Change-Id: Ia3896d47d861f7193bf81fc7c7bb10db3103fc40
This commit is contained in:
@@ -18,12 +18,14 @@
|
||||
#include "Log.h"
|
||||
|
||||
#include "ValueMetricProducer.h"
|
||||
#include "../guardrail/StatsdStats.h"
|
||||
#include "../stats_log_util.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../guardrail/StatsdStats.h"
|
||||
#include "../stats_log_util.h"
|
||||
#include "metrics/parsing_utils/metrics_manager_util.h"
|
||||
|
||||
using android::util::FIELD_COUNT_REPEATED;
|
||||
using android::util::FIELD_TYPE_BOOL;
|
||||
using android::util::FIELD_TYPE_DOUBLE;
|
||||
@@ -184,6 +186,48 @@ ValueMetricProducer::~ValueMetricProducer() {
|
||||
}
|
||||
}
|
||||
|
||||
bool ValueMetricProducer::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 ValueMetric& metric = config.value_metric(configIndex);
|
||||
// Update appropriate indices: mWhatMatcherIndex, mConditionIndex and MetricsManager maps.
|
||||
if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, /*enforceOneAtom=*/false,
|
||||
allAtomMatchingTrackers, newAtomMatchingTrackerMap,
|
||||
trackerToMetricMap, mWhatMatcherIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (metric.has_condition() &&
|
||||
!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
|
||||
metric.links(), allConditionTrackers, mConditionTrackerIndex,
|
||||
conditionToMetricMap)) {
|
||||
return false;
|
||||
}
|
||||
sp<EventMatcherWizard> tmpEventWizard = mEventMatcherWizard;
|
||||
mEventMatcherWizard = matcherWizard;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ValueMetricProducer::onStateChanged(int64_t eventTimeNs, int32_t atomId,
|
||||
const HashableDimensionKey& primaryKey,
|
||||
const FieldValue& oldState, const FieldValue& newState) {
|
||||
|
||||
@@ -47,7 +47,7 @@ struct PastValueBucket {
|
||||
// - a condition change
|
||||
// - an app upgrade
|
||||
// - an alarm set to the end of the bucket
|
||||
class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
|
||||
class ValueMetricProducer : public MetricProducer, public virtual PullDataReceiver {
|
||||
public:
|
||||
ValueMetricProducer(
|
||||
const ConfigKey& key, const ValueMetric& valueMetric, const int conditionIndex,
|
||||
@@ -155,7 +155,23 @@ private:
|
||||
// causes the bucket to be invalidated will not notify StatsdStats.
|
||||
void skipCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason);
|
||||
|
||||
const int mWhatMatcherIndex;
|
||||
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;
|
||||
|
||||
int mWhatMatcherIndex;
|
||||
|
||||
sp<EventMatcherWizard> mEventMatcherWizard;
|
||||
|
||||
@@ -370,6 +386,8 @@ private:
|
||||
FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPulledValue);
|
||||
FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse);
|
||||
|
||||
FRIEND_TEST(ConfigUpdateTest, TestUpdateValueMetrics);
|
||||
|
||||
friend class ValueMetricProducerTestHelper;
|
||||
};
|
||||
|
||||
|
||||
@@ -580,7 +580,6 @@ bool determineAllMetricUpdateStatuses(const StatsdConfig& config,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// TODO: determine update status for value metrics.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -749,8 +748,8 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
|
||||
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);
|
||||
newMetricProducerMap[metric.id()] = metricIndex;
|
||||
optional<sp<MetricProducer>> producer;
|
||||
switch (metricsToUpdate[metricIndex]) {
|
||||
case UPDATE_PRESERVE: {
|
||||
@@ -784,6 +783,45 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
|
||||
}
|
||||
newMetricProducers.push_back(producer.value());
|
||||
}
|
||||
|
||||
for (int i = 0; i < config.value_metric_size(); i++, metricIndex++) {
|
||||
const ValueMetric& metric = config.value_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 = createValueMetricProducerAndUpdateMetadata(
|
||||
key, config, timeBaseNs, currentTimeNs, pullerManager, metric, metricIndex,
|
||||
allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers,
|
||||
conditionTrackerMap, initialConditionCache, wizard, matcherWizard,
|
||||
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.gauge_metric_size(); i++, metricIndex++) {
|
||||
const GaugeMetric& metric = config.gauge_metric(i);
|
||||
newMetricProducerMap[metric.id()] = metricIndex;
|
||||
|
||||
@@ -599,6 +599,108 @@ optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
|
||||
eventDeactivationMap)};
|
||||
}
|
||||
|
||||
optional<sp<MetricProducer>> createValueMetricProducerAndUpdateMetadata(
|
||||
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
|
||||
const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
|
||||
const ValueMetric& 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 sp<EventMatcherWizard>& matcherWizard,
|
||||
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 ValueMetric \"%lld\"", (long long)metric.id());
|
||||
return nullopt;
|
||||
}
|
||||
if (!metric.has_value_field()) {
|
||||
ALOGE("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
|
||||
return nullopt;
|
||||
}
|
||||
std::vector<Matcher> fieldMatchers;
|
||||
translateFieldMatcher(metric.value_field(), &fieldMatchers);
|
||||
if (fieldMatchers.size() < 1) {
|
||||
ALOGE("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
int trackerIndex;
|
||||
if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
|
||||
metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap,
|
||||
trackerToMetricMap, trackerIndex)) {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
|
||||
// If it is pulled atom, it should be simple matcher with one tagId.
|
||||
if (atomMatcher->getAtomIds().size() != 1) {
|
||||
return nullopt;
|
||||
}
|
||||
int atomTagId = *(atomMatcher->getAtomIds().begin());
|
||||
int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
|
||||
|
||||
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) {
|
||||
ALOGE("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 (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
|
||||
allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
|
||||
return nullopt;
|
||||
}
|
||||
} else if (metric.state_link_size() > 0) {
|
||||
ALOGE("ValueMetric 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 ValueMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
|
||||
metricHash, trackerIndex, matcherWizard, pullTagId, timeBaseNs,
|
||||
currentTimeNs, pullerManager, eventActivationMap,
|
||||
eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
|
||||
}
|
||||
|
||||
optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata(
|
||||
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
|
||||
const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
|
||||
@@ -911,97 +1013,20 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
|
||||
|
||||
// build ValueMetricProducer
|
||||
for (int i = 0; i < config.value_metric_size(); i++) {
|
||||
const ValueMetric& metric = config.value_metric(i);
|
||||
if (!metric.has_what()) {
|
||||
ALOGW("cannot find \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
|
||||
return false;
|
||||
}
|
||||
if (!metric.has_value_field()) {
|
||||
ALOGW("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
|
||||
return false;
|
||||
}
|
||||
std::vector<Matcher> fieldMatchers;
|
||||
translateFieldMatcher(metric.value_field(), &fieldMatchers);
|
||||
if (fieldMatchers.size() < 1) {
|
||||
ALOGW("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
|
||||
return false;
|
||||
}
|
||||
|
||||
int metricIndex = allMetricProducers.size();
|
||||
const ValueMetric& metric = config.value_metric(i);
|
||||
metricMap.insert({metric.id(), metricIndex});
|
||||
int trackerIndex;
|
||||
if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
|
||||
metric.has_dimensions_in_what(),
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap,
|
||||
trackerToMetricMap, trackerIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
|
||||
// If it is pulled atom, it should be simple matcher with one tagId.
|
||||
if (atomMatcher->getAtomIds().size() != 1) {
|
||||
return false;
|
||||
}
|
||||
int atomTagId = *(atomMatcher->getAtomIds().begin());
|
||||
int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
|
||||
|
||||
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 (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
|
||||
allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (metric.state_link_size() > 0) {
|
||||
ALOGW("ValueMetric 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 = createValueMetricProducerAndUpdateMetadata(
|
||||
key, config, timeBaseTimeNs, currentTimeNs, pullerManager, metric, metricIndex,
|
||||
allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
|
||||
conditionTrackerMap, initialConditionCache, wizard, matcherWizard, 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> valueProducer = new ValueMetricProducer(
|
||||
key, metric, conditionIndex, initialConditionCache, wizard, metricHash,
|
||||
trackerIndex, matcherWizard, pullTagId, timeBaseTimeNs, currentTimeNs,
|
||||
pullerManager, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
|
||||
stateGroupMap);
|
||||
allMetricProducers.push_back(valueProducer);
|
||||
allMetricProducers.push_back(producer.value());
|
||||
}
|
||||
|
||||
// Gauge metrics.
|
||||
|
||||
@@ -148,6 +148,27 @@ optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
|
||||
std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
|
||||
std::vector<int>& metricsWithActivation);
|
||||
|
||||
// Creates a CountMetricProducer 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>> createValueMetricProducerAndUpdateMetadata(
|
||||
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
|
||||
const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
|
||||
const ValueMetric& 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 sp<EventMatcherWizard>& matcherWizard,
|
||||
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 a GaugeMetricProducer 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>> createGaugeMetricProducerAndUpdateMetadata(
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "src/matchers/CombinationAtomMatchingTracker.h"
|
||||
#include "src/metrics/DurationMetricProducer.h"
|
||||
#include "src/metrics/GaugeMetricProducer.h"
|
||||
#include "src/metrics/ValueMetricProducer.h"
|
||||
#include "src/metrics/parsing_utils/metrics_manager_util.h"
|
||||
#include "tests/statsd_test_util.h"
|
||||
|
||||
@@ -2685,6 +2686,243 @@ TEST_F(ConfigUpdateTest, TestUpdateDurationMetrics) {
|
||||
EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
|
||||
}
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestUpdateValueMetrics) {
|
||||
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 = CreateStartScheduledJobAtomMatcher();
|
||||
int64_t matcher3Id = matcher3.id();
|
||||
*config.add_atom_matcher() = matcher3;
|
||||
|
||||
AtomMatcher matcher4 = CreateTemperatureAtomMatcher();
|
||||
int64_t matcher4Id = matcher4.id();
|
||||
*config.add_atom_matcher() = matcher4;
|
||||
|
||||
AtomMatcher matcher5 = CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
|
||||
int64_t matcher5Id = matcher5.id();
|
||||
*config.add_atom_matcher() = matcher5;
|
||||
|
||||
Predicate predicate1 = CreateScreenIsOnPredicate();
|
||||
int64_t predicate1Id = predicate1.id();
|
||||
*config.add_predicate() = predicate1;
|
||||
|
||||
Predicate predicate2 = CreateScreenIsOffPredicate();
|
||||
int64_t predicate2Id = predicate2.id();
|
||||
*config.add_predicate() = predicate2;
|
||||
|
||||
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 value metrics.
|
||||
// Note that these will not work as "real" metrics since the value field is always 2.
|
||||
// Will be preserved.
|
||||
ValueMetric value1 = createValueMetric("VALUE1", matcher4, predicate1Id, {state1Id});
|
||||
int64_t value1Id = value1.id();
|
||||
*config.add_value_metric() = value1;
|
||||
|
||||
// Will be replaced - definition change.
|
||||
ValueMetric value2 = createValueMetric("VALUE2", matcher1, nullopt, {});
|
||||
int64_t value2Id = value2.id();
|
||||
*config.add_value_metric() = value2;
|
||||
|
||||
// Will be replaced - condition change.
|
||||
ValueMetric value3 = createValueMetric("VALUE3", matcher5, predicate2Id, {});
|
||||
int64_t value3Id = value3.id();
|
||||
*config.add_value_metric() = value3;
|
||||
|
||||
// Will be replaced - state change.
|
||||
ValueMetric value4 = createValueMetric("VALUE4", matcher3, nullopt, {state2Id});
|
||||
int64_t value4Id = value4.id();
|
||||
*config.add_value_metric() = value4;
|
||||
|
||||
// Will be deleted.
|
||||
ValueMetric value5 = createValueMetric("VALUE5", matcher2, nullopt, {});
|
||||
int64_t value5Id = value5.id();
|
||||
*config.add_value_metric() = value5;
|
||||
|
||||
EXPECT_TRUE(initConfig(config));
|
||||
|
||||
// Used later to ensure the condition wizard is replaced. Get it before doing the update.
|
||||
sp<EventMatcherWizard> oldMatcherWizard =
|
||||
static_cast<ValueMetricProducer*>(oldMetricProducers[0].get())->mEventMatcherWizard;
|
||||
EXPECT_EQ(oldMatcherWizard->getStrongCount(), 6);
|
||||
|
||||
// Change value2, causing it to be replaced.
|
||||
value2.set_aggregation_type(ValueMetric::AVG);
|
||||
|
||||
// Mark predicate 2 as replaced. Causes value3 to be replaced.
|
||||
set<int64_t> replacedConditions = {predicate2Id};
|
||||
|
||||
// Mark state 2 as replaced. Causes value4 to be replaced.
|
||||
set<int64_t> replacedStates = {state2Id};
|
||||
|
||||
// New value metric.
|
||||
ValueMetric value6 = createValueMetric("VALUE6", matcher5, predicate1Id, {state1Id});
|
||||
int64_t value6Id = value6.id();
|
||||
|
||||
// Map the matchers and predicates in reverse order to force the indices to change.
|
||||
std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
|
||||
const int matcher5Index = 0;
|
||||
newAtomMatchingTrackerMap[matcher5Id] = 0;
|
||||
const int matcher4Index = 1;
|
||||
newAtomMatchingTrackerMap[matcher4Id] = 1;
|
||||
const int matcher3Index = 2;
|
||||
newAtomMatchingTrackerMap[matcher3Id] = 2;
|
||||
const int matcher2Index = 3;
|
||||
newAtomMatchingTrackerMap[matcher2Id] = 3;
|
||||
const int matcher1Index = 4;
|
||||
newAtomMatchingTrackerMap[matcher1Id] = 4;
|
||||
// Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
|
||||
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
|
||||
std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
|
||||
newAtomMatchingTrackers.begin());
|
||||
|
||||
std::unordered_map<int64_t, int> newConditionTrackerMap;
|
||||
const int predicate2Index = 0;
|
||||
newConditionTrackerMap[predicate2Id] = 0;
|
||||
const int predicate1Index = 1;
|
||||
newConditionTrackerMap[predicate1Id] = 1;
|
||||
// Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
|
||||
vector<sp<ConditionTracker>> newConditionTrackers(2);
|
||||
std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
|
||||
newConditionTrackers.begin());
|
||||
// Say that predicate1 & predicate2 is unknown since the initial condition never changed.
|
||||
vector<ConditionState> conditionCache = {ConditionState::kUnknown, ConditionState::kUnknown};
|
||||
|
||||
StatsdConfig newConfig;
|
||||
*newConfig.add_value_metric() = value6;
|
||||
const int value6Index = 0;
|
||||
*newConfig.add_value_metric() = value3;
|
||||
const int value3Index = 1;
|
||||
*newConfig.add_value_metric() = value1;
|
||||
const int value1Index = 2;
|
||||
*newConfig.add_value_metric() = value4;
|
||||
const int value4Index = 3;
|
||||
*newConfig.add_value_metric() = value2;
|
||||
const int value2Index = 4;
|
||||
|
||||
*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 = {
|
||||
{value1Id, value1Index}, {value2Id, value2Index}, {value3Id, value3Index},
|
||||
{value4Id, value4Index}, {value6Id, value6Index},
|
||||
};
|
||||
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
|
||||
|
||||
// Make sure preserved metrics are the same.
|
||||
ASSERT_EQ(newMetricProducers.size(), 5);
|
||||
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(value1Id)],
|
||||
newMetricProducers[newMetricProducerMap.at(value1Id)]);
|
||||
|
||||
// Make sure replaced metrics are different.
|
||||
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value2Id)],
|
||||
newMetricProducers[newMetricProducerMap.at(value2Id)]);
|
||||
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value3Id)],
|
||||
newMetricProducers[newMetricProducerMap.at(value3Id)]);
|
||||
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value4Id)],
|
||||
newMetricProducers[newMetricProducerMap.at(value4Id)]);
|
||||
|
||||
// Verify the conditionToMetricMap.
|
||||
ASSERT_EQ(conditionToMetricMap.size(), 2);
|
||||
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
|
||||
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(value1Index, value6Index));
|
||||
const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
|
||||
EXPECT_THAT(condition2Metrics, UnorderedElementsAre(value3Index));
|
||||
|
||||
// Verify the trackerToMetricMap.
|
||||
ASSERT_EQ(trackerToMetricMap.size(), 4);
|
||||
const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
|
||||
EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(value2Index));
|
||||
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
|
||||
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(value4Index));
|
||||
const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
|
||||
EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(value1Index));
|
||||
const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
|
||||
EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(value3Index, value6Index));
|
||||
|
||||
// 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/states are correct.
|
||||
ValueMetricProducer* valueProducer1 =
|
||||
static_cast<ValueMetricProducer*>(newMetricProducers[value1Index].get());
|
||||
EXPECT_EQ(valueProducer1->getMetricId(), value1Id);
|
||||
EXPECT_EQ(valueProducer1->mConditionTrackerIndex, predicate1Index);
|
||||
EXPECT_EQ(valueProducer1->mCondition, ConditionState::kUnknown);
|
||||
EXPECT_EQ(valueProducer1->mWhatMatcherIndex, matcher4Index);
|
||||
ValueMetricProducer* valueProducer2 =
|
||||
static_cast<ValueMetricProducer*>(newMetricProducers[value2Index].get());
|
||||
EXPECT_EQ(valueProducer2->getMetricId(), value2Id);
|
||||
EXPECT_EQ(valueProducer2->mConditionTrackerIndex, -1);
|
||||
EXPECT_EQ(valueProducer2->mCondition, ConditionState::kTrue);
|
||||
EXPECT_EQ(valueProducer2->mWhatMatcherIndex, matcher1Index);
|
||||
ValueMetricProducer* valueProducer3 =
|
||||
static_cast<ValueMetricProducer*>(newMetricProducers[value3Index].get());
|
||||
EXPECT_EQ(valueProducer3->getMetricId(), value3Id);
|
||||
EXPECT_EQ(valueProducer3->mConditionTrackerIndex, predicate2Index);
|
||||
EXPECT_EQ(valueProducer3->mCondition, ConditionState::kUnknown);
|
||||
EXPECT_EQ(valueProducer3->mWhatMatcherIndex, matcher5Index);
|
||||
ValueMetricProducer* valueProducer4 =
|
||||
static_cast<ValueMetricProducer*>(newMetricProducers[value4Index].get());
|
||||
EXPECT_EQ(valueProducer4->getMetricId(), value4Id);
|
||||
EXPECT_EQ(valueProducer4->mConditionTrackerIndex, -1);
|
||||
EXPECT_EQ(valueProducer4->mCondition, ConditionState::kTrue);
|
||||
EXPECT_EQ(valueProducer4->mWhatMatcherIndex, matcher3Index);
|
||||
ValueMetricProducer* valueProducer6 =
|
||||
static_cast<ValueMetricProducer*>(newMetricProducers[value6Index].get());
|
||||
EXPECT_EQ(valueProducer6->getMetricId(), value6Id);
|
||||
EXPECT_EQ(valueProducer6->mConditionTrackerIndex, predicate1Index);
|
||||
EXPECT_EQ(valueProducer6->mCondition, ConditionState::kUnknown);
|
||||
EXPECT_EQ(valueProducer6->mWhatMatcherIndex, matcher5Index);
|
||||
|
||||
sp<EventMatcherWizard> newMatcherWizard = valueProducer1->mEventMatcherWizard;
|
||||
EXPECT_NE(newMatcherWizard, oldMatcherWizard);
|
||||
EXPECT_EQ(newMatcherWizard->getStrongCount(), 6);
|
||||
oldMetricProducers.clear();
|
||||
// Only reference to the old wizard should be the one in the test.
|
||||
EXPECT_EQ(oldMatcherWizard->getStrongCount(), 1);
|
||||
}
|
||||
|
||||
TEST_F(ConfigUpdateTest, TestUpdateMetricActivations) {
|
||||
StatsdConfig config;
|
||||
// Add atom matchers
|
||||
@@ -2849,6 +3087,11 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
int64_t gaugeMetricId = gaugeMetric.id();
|
||||
*config.add_gauge_metric() = gaugeMetric;
|
||||
|
||||
// Preserved.
|
||||
ValueMetric valueMetric = createValueMetric("VALUE1", matcher3, predicate1Id, {});
|
||||
int64_t valueMetricId = valueMetric.id();
|
||||
*config.add_value_metric() = valueMetric;
|
||||
|
||||
// Preserved.
|
||||
DurationMetric durationMetric = createDurationMetric("DURATION1", predicate1Id, nullopt, {});
|
||||
int64_t durationMetricId = durationMetric.id();
|
||||
@@ -2858,7 +3101,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
|
||||
// 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(), 5);
|
||||
EXPECT_EQ(oldConditionWizard->getStrongCount(), 6);
|
||||
|
||||
// Mark matcher 2 as replaced. Causes eventMetric to be replaced.
|
||||
set<int64_t> replacedMatchers;
|
||||
@@ -2889,6 +3132,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
newConditionTrackers.begin());
|
||||
vector<ConditionState> conditionCache = {ConditionState::kUnknown};
|
||||
|
||||
// The order matters. we parse in the order of: count, duration, event, value, gauge.
|
||||
StatsdConfig newConfig;
|
||||
*newConfig.add_count_metric() = countMetric;
|
||||
const int countMetricIndex = 0;
|
||||
@@ -2896,8 +3140,10 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
const int durationMetricIndex = 1;
|
||||
*newConfig.add_event_metric() = eventMetric;
|
||||
const int eventMetricIndex = 2;
|
||||
*newConfig.add_value_metric() = valueMetric;
|
||||
const int valueMetricIndex = 3;
|
||||
*newConfig.add_gauge_metric() = gaugeMetric;
|
||||
const int gaugeMetricIndex = 3;
|
||||
const int gaugeMetricIndex = 4;
|
||||
|
||||
// Add the predicate since duration metric needs it.
|
||||
*newConfig.add_predicate() = predicate1;
|
||||
@@ -2922,19 +3168,20 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
metricsWithActivation));
|
||||
|
||||
unordered_map<int64_t, int> expectedMetricProducerMap = {
|
||||
{countMetricId, countMetricIndex},
|
||||
{durationMetricId, durationMetricIndex},
|
||||
{eventMetricId, eventMetricIndex},
|
||||
{countMetricId, countMetricIndex}, {durationMetricId, durationMetricIndex},
|
||||
{eventMetricId, eventMetricIndex}, {valueMetricId, valueMetricIndex},
|
||||
{gaugeMetricId, gaugeMetricIndex},
|
||||
};
|
||||
EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
|
||||
|
||||
// Make sure preserved metrics are the same.
|
||||
ASSERT_EQ(newMetricProducers.size(), 4);
|
||||
ASSERT_EQ(newMetricProducers.size(), 5);
|
||||
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(countMetricId)],
|
||||
newMetricProducers[newMetricProducerMap.at(countMetricId)]);
|
||||
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(durationMetricId)],
|
||||
newMetricProducers[newMetricProducerMap.at(durationMetricId)]);
|
||||
EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(valueMetricId)],
|
||||
newMetricProducers[newMetricProducerMap.at(valueMetricId)]);
|
||||
|
||||
// Make sure replaced metrics are different.
|
||||
EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(eventMetricId)],
|
||||
@@ -2945,7 +3192,8 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
// Verify the conditionToMetricMap.
|
||||
ASSERT_EQ(conditionToMetricMap.size(), 1);
|
||||
const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
|
||||
EXPECT_THAT(condition1Metrics, UnorderedElementsAre(countMetricIndex, gaugeMetricIndex));
|
||||
EXPECT_THAT(condition1Metrics,
|
||||
UnorderedElementsAre(countMetricIndex, gaugeMetricIndex, valueMetricIndex));
|
||||
|
||||
// Verify the trackerToMetricMap.
|
||||
ASSERT_EQ(trackerToMetricMap.size(), 3);
|
||||
@@ -2954,7 +3202,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
|
||||
EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(eventMetricIndex, durationMetricIndex));
|
||||
const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
|
||||
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(gaugeMetricIndex));
|
||||
EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(gaugeMetricIndex, valueMetricIndex));
|
||||
|
||||
// Verify event activation/deactivation maps.
|
||||
ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
|
||||
@@ -2977,7 +3225,7 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
|
||||
|
||||
sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
|
||||
EXPECT_NE(newConditionWizard, oldConditionWizard);
|
||||
EXPECT_EQ(newConditionWizard->getStrongCount(), 5);
|
||||
EXPECT_EQ(newConditionWizard->getStrongCount(), 6);
|
||||
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