Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7dd9e171 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "metric activation and TTL."

parents e730fd64 849dfdc2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -218,6 +218,7 @@ LOCAL_SRC_FILES := \
    tests/metrics/metrics_test_helper.cpp \
    tests/statsd_test_util.cpp \
    tests/e2e/WakelockDuration_e2e_test.cpp \
    tests/e2e/MetricActivation_e2e_test.cpp \
    tests/e2e/MetricConditionLink_e2e_test.cpp \
    tests/e2e/Alarm_e2e_test.cpp \
    tests/e2e/Attribution_e2e_test.cpp \
+1 −0
Original line number Diff line number Diff line
@@ -219,6 +219,7 @@ private:

    FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
    FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
    FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
};

}  // namespace statsd
+47 −1
Original line number Diff line number Diff line
@@ -64,9 +64,55 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
        onMatchedLogEventInternalLocked(
                matcherIndex, metricKey, conditionKey, condition, event);
    }
}

bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
    bool isActive = mEventActivationMap.empty();
    for (auto& it : mEventActivationMap) {
        if (it.second.state == ActivationState::kActive &&
            elapsedTimestampNs > it.second.ttl_ns + it.second.activation_ns) {
            it.second.state = ActivationState::kNotActive;
        }
        if (it.second.state == ActivationState::kActive) {
            isActive = true;
        }
    }
    return isActive;
}

void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
    std::lock_guard<std::mutex> lock(mMutex);
    if (!mIsActive) {
        return;
    }
    mIsActive = evaluateActiveStateLocked(elapsedTimestampNs);
    if (!mIsActive) {
        flushLocked(elapsedTimestampNs);
    }
}

void MetricProducer::addActivation(int activationTrackerIndex, int64_t ttl_seconds) {
    std::lock_guard<std::mutex> lock(mMutex);
    // When a metric producer does not depend on any activation, its mIsActive is true.
    // Therefor, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
    // change.
    if  (mEventActivationMap.empty()) {
        mIsActive = false;
    }
    mEventActivationMap[activationTrackerIndex].ttl_ns = ttl_seconds * NS_PER_SEC;
}

void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
    auto it = mEventActivationMap.find(activationTrackerIndex);
    if (it == mEventActivationMap.end()) {
        return;
    }
    it->second.activation_ns = elapsedTimestampNs;
    it->second.state = ActivationState::kActive;
    mIsActive = true;
}


}  // namespace statsd
}  // namespace os
}  // namespace android
+53 −7
Original line number Diff line number Diff line
@@ -34,6 +34,17 @@ namespace android {
namespace os {
namespace statsd {

// If the metric has no activation requirement, it will be active once the metric producer is
// created.
// If the metric needs to be activated by atoms, the metric producer will start
// with kNotActive state, turn to kActive when the activation event arrives, become kNotActive
// when it reaches the duration limit (timebomb). If the activation event arrives again before
// or after it expires, the event producer will be re-activated and ttl will be reset.
enum ActivationState {
    kNotActive = 0,
    kActive = 1,
};

// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
// writing the report to dropbox. MetricProducers should respond to package changes as required in
// PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
@@ -54,7 +65,8 @@ public:
          mContainANYPositionInDimensionsInWhat(false),
          mSliceByPositionALL(false),
          mSameConditionDimensionsInTracker(false),
          mHasLinksToAllConditionDimensionsInTracker(false) {
          mHasLinksToAllConditionDimensionsInTracker(false),
          mIsActive(true) {
    }

    virtual ~MetricProducer(){};
@@ -93,18 +105,24 @@ public:
    // Consume the parsed stats log entry that already matched the "what" of the metric.
    void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
        std::lock_guard<std::mutex> lock(mMutex);
        if (mIsActive) {
            onMatchedLogEventLocked(matcherIndex, event);
        }
    }

    void onConditionChanged(const bool condition, const int64_t eventTime) {
        std::lock_guard<std::mutex> lock(mMutex);
        if (mIsActive) {
            onConditionChangedLocked(condition, eventTime);
        }
    }

    void onSlicedConditionMayChange(bool overallCondition, const int64_t eventTime) {
        std::lock_guard<std::mutex> lock(mMutex);
        if (mIsActive) {
            onSlicedConditionMayChangeLocked(overallCondition, eventTime);
        }
    }

    bool isConditionSliced() const {
        std::lock_guard<std::mutex> lock(mMutex);
@@ -177,6 +195,15 @@ public:
        return mCurrentBucketNum;
    }

    void activate(int activationTrackerIndex, int64_t elapsedTimestampNs) {
        std::lock_guard<std::mutex> lock(mMutex);
        activateLocked(activationTrackerIndex, elapsedTimestampNs);
    }

    void addActivation(int activationTrackerIndex, int64_t ttl_seconds);

    void flushIfExpire(int64_t elapsedTimestampNs);

protected:
    virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
    virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
@@ -189,6 +216,10 @@ protected:
    virtual size_t byteSizeLocked() const = 0;
    virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;

    bool evaluateActiveStateLocked(int64_t elapsedTimestampNs);

    void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);

    /**
     * Flushes the current bucket if the eventTime is after the current bucket's end time. This will
       also flush the current partial bucket in memory.
@@ -198,9 +229,9 @@ protected:
    /**
     * Flushes all the data including the current partial bucket.
     */
    virtual void flushLocked(const int64_t& eventTime) {
        flushIfNeededLocked(eventTime);
        flushCurrentBucketLocked(eventTime);
    virtual void flushLocked(const int64_t& eventTimeNs) {
        flushIfNeededLocked(eventTimeNs);
        flushCurrentBucketLocked(eventTimeNs);
    };

    /**
@@ -295,6 +326,21 @@ protected:
    virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);

    mutable std::mutex mMutex;

    struct Activation {
        Activation() : ttl_ns(0), activation_ns(0), state(ActivationState::kNotActive)  {}

        int64_t ttl_ns;
        int64_t activation_ns;
        ActivationState state;
    };
    // When the metric producer has multiple activations, these activations are ORed to determine
    // whether the metric producer is ready to generate metrics.
    std::unordered_map<int, Activation> mEventActivationMap;

    bool mIsActive;

    FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
};

}  // namespace statsd
+18 −4
Original line number Diff line number Diff line
@@ -73,7 +73,8 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
            key, config, *uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
            timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
            mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers,
            mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds);
            mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
            mActivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, mNoReportMetricIds);

    mHashStringsInReport = config.hash_strings_in_metric_report();

@@ -298,7 +299,12 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
    }

    int tagId = event.GetTagId();
    int64_t eventTime = event.GetElapsedTimestampNs();
    int64_t eventTimeNs = event.GetElapsedTimestampNs();

    for (int metric : mMetricIndexesWithActivation) {
        mAllMetricProducers[metric]->flushIfExpire(eventTimeNs);
    }

    if (mTagIds.find(tagId) == mTagIds.end()) {
        // not interesting...
        return;
@@ -310,6 +316,14 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
        matcher->onLogEvent(event, mAllAtomMatchers, matcherCache);
    }

    for (const auto& it : mActivationAtomTrackerToMetricMap) {
        if (matcherCache[it.first] == MatchingState::kMatched) {
            for (int metricIndex : it.second) {
                mAllMetricProducers[metricIndex]->activate(it.first, eventTimeNs);
            }
        }
    }

    // A bitmap to see which ConditionTracker needs to be re-evaluated.
    vector<bool> conditionToBeEvaluated(mAllConditionTrackers.size(), false);

@@ -347,13 +361,13 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
                // Push the new condition to it directly.
                if (!mAllMetricProducers[metricIndex]->isConditionSliced()) {
                    mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i],
                                                                         eventTime);
                                                                         eventTimeNs);
                    // metric cares about sliced conditions, and it may have changed. Send
                    // notification, and the metric can query the sliced conditions that are
                    // interesting to it.
                } else {
                    mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(conditionCache[i],
                                                                                 eventTime);
                                                                                 eventTimeNs);
                }
            }
        }
Loading