Home | History | Annotate | Download | only in duration_helper
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef DURATION_TRACKER_H
     18 #define DURATION_TRACKER_H
     19 
     20 #include "anomaly/DurationAnomalyTracker.h"
     21 #include "condition/ConditionWizard.h"
     22 #include "config/ConfigKey.h"
     23 #include "stats_util.h"
     24 
     25 namespace android {
     26 namespace os {
     27 namespace statsd {
     28 
     29 enum DurationState {
     30     kStopped = 0,  // The event is stopped.
     31     kStarted = 1,  // The event is on going.
     32     kPaused = 2,   // The event is started, but condition is false, clock is paused. When condition
     33                    // turns to true, kPaused will become kStarted.
     34 };
     35 
     36 // Hold duration information for one atom level duration in current on-going bucket.
     37 struct DurationInfo {
     38     DurationState state;
     39 
     40     // the number of starts seen.
     41     int32_t startCount;
     42 
     43     // most recent start time.
     44     int64_t lastStartTime;
     45     // existing duration in current bucket.
     46     int64_t lastDuration;
     47     // TODO: Optimize the way we track sliced condition in duration metrics.
     48     // cache the HashableDimensionKeys we need to query the condition for this duration event.
     49     ConditionKey conditionKeys;
     50 
     51     DurationInfo() : state(kStopped), startCount(0), lastStartTime(0), lastDuration(0){};
     52 };
     53 
     54 struct DurationBucket {
     55     int64_t mBucketStartNs;
     56     int64_t mBucketEndNs;
     57     int64_t mDuration;
     58 };
     59 
     60 class DurationTracker {
     61 public:
     62     DurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
     63                     sp<ConditionWizard> wizard, int conditionIndex,
     64                     const std::vector<Matcher>& dimensionInCondition, bool nesting,
     65                     int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs,
     66                     int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
     67                     const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
     68         : mConfigKey(key),
     69           mTrackerId(id),
     70           mEventKey(eventKey),
     71           mWizard(wizard),
     72           mConditionTrackerIndex(conditionIndex),
     73           mBucketSizeNs(bucketSizeNs),
     74           mDimensionInCondition(dimensionInCondition),
     75           mNested(nesting),
     76           mCurrentBucketStartTimeNs(currentBucketStartNs),
     77           mDuration(0),
     78           mDurationFullBucket(0),
     79           mCurrentBucketNum(currentBucketNum),
     80           mStartTimeNs(startTimeNs),
     81           mConditionSliced(conditionSliced),
     82           mHasLinksToAllConditionDimensionsInTracker(fullLink),
     83           mAnomalyTrackers(anomalyTrackers){};
     84 
     85     virtual ~DurationTracker(){};
     86 
     87     virtual unique_ptr<DurationTracker> clone(const int64_t eventTime) = 0;
     88 
     89     virtual void noteStart(const HashableDimensionKey& key, bool condition,
     90                            const int64_t eventTime, const ConditionKey& conditionKey) = 0;
     91     virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
     92                           const bool stopAll) = 0;
     93     virtual void noteStopAll(const int64_t eventTime) = 0;
     94 
     95     virtual void onSlicedConditionMayChange(bool overallCondition, const int64_t timestamp) = 0;
     96     virtual void onConditionChanged(bool condition, const int64_t timestamp) = 0;
     97 
     98     // Flush stale buckets if needed, and return true if the tracker has no on-going duration
     99     // events, so that the owner can safely remove the tracker.
    100     virtual bool flushIfNeeded(
    101             int64_t timestampNs,
    102             std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0;
    103 
    104     // Should only be called during an app upgrade or from this tracker's flushIfNeeded. If from
    105     // an app upgrade, we assume that we're trying to form a partial bucket.
    106     virtual bool flushCurrentBucket(
    107             const int64_t& eventTimeNs,
    108             std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0;
    109 
    110     // Predict the anomaly timestamp given the current status.
    111     virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
    112                                               const int64_t currentTimestamp) const = 0;
    113     // Dump internal states for debugging
    114     virtual void dumpStates(FILE* out, bool verbose) const = 0;
    115 
    116     void setEventKey(const MetricDimensionKey& eventKey) {
    117          mEventKey = eventKey;
    118     }
    119 
    120 protected:
    121     int64_t getCurrentBucketEndTimeNs() const {
    122         return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
    123     }
    124 
    125     // Starts the anomaly alarm.
    126     void startAnomalyAlarm(const int64_t eventTime) {
    127         for (auto& anomalyTracker : mAnomalyTrackers) {
    128             if (anomalyTracker != nullptr) {
    129                 const int64_t alarmTimestampNs =
    130                     predictAnomalyTimestampNs(*anomalyTracker, eventTime);
    131                 if (alarmTimestampNs > 0) {
    132                     anomalyTracker->startAlarm(mEventKey, alarmTimestampNs);
    133                 }
    134             }
    135         }
    136     }
    137 
    138     // Stops the anomaly alarm. If it should have already fired, declare the anomaly now.
    139     void stopAnomalyAlarm(const int64_t timestamp) {
    140         for (auto& anomalyTracker : mAnomalyTrackers) {
    141             if (anomalyTracker != nullptr) {
    142                 anomalyTracker->stopAlarm(mEventKey, timestamp);
    143             }
    144         }
    145     }
    146 
    147     void addPastBucketToAnomalyTrackers(const int64_t& bucketValue, const int64_t& bucketNum) {
    148         for (auto& anomalyTracker : mAnomalyTrackers) {
    149             if (anomalyTracker != nullptr) {
    150                 anomalyTracker->addPastBucket(mEventKey, bucketValue, bucketNum);
    151             }
    152         }
    153     }
    154 
    155     void detectAndDeclareAnomaly(const int64_t& timestamp, const int64_t& currBucketNum,
    156                                  const int64_t& currentBucketValue) {
    157         for (auto& anomalyTracker : mAnomalyTrackers) {
    158             if (anomalyTracker != nullptr) {
    159                 anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mEventKey,
    160                                                         currentBucketValue);
    161             }
    162         }
    163     }
    164 
    165     // Convenience to compute the current bucket's end time, which is always aligned with the
    166     // start time of the metric.
    167     int64_t getCurrentBucketEndTimeNs() {
    168         return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
    169     }
    170 
    171     // A reference to the DurationMetricProducer's config key.
    172     const ConfigKey& mConfigKey;
    173 
    174     const int64_t mTrackerId;
    175 
    176     MetricDimensionKey mEventKey;
    177 
    178     sp<ConditionWizard> mWizard;
    179 
    180     const int mConditionTrackerIndex;
    181 
    182     const int64_t mBucketSizeNs;
    183 
    184     const std::vector<Matcher>& mDimensionInCondition;
    185 
    186     const bool mNested;
    187 
    188     int64_t mCurrentBucketStartTimeNs;
    189 
    190     int64_t mDuration;  // current recorded duration result (for partial bucket)
    191 
    192     int64_t mDurationFullBucket;  // Sum of past partial buckets in current full bucket.
    193 
    194     int64_t mCurrentBucketNum;
    195 
    196     const int64_t mStartTimeNs;
    197 
    198     const bool mConditionSliced;
    199 
    200     bool mSameConditionDimensionsInTracker;
    201     bool mHasLinksToAllConditionDimensionsInTracker;
    202 
    203     std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
    204 
    205     FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
    206     FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
    207     FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
    208 };
    209 
    210 }  // namespace statsd
    211 }  // namespace os
    212 }  // namespace android
    213 
    214 #endif  // DURATION_TRACKER_H
    215