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

Commit 53928880 authored by Yangster-mac's avatar Yangster-mac
Browse files

Duration tracker optimization.

* Avoid querying sliced condition for stop/stopAll events for duration metric.
* Avoid extracting the internal dimension key when it is identical to the what dimension.

Test: statsd test
Change-Id: I664e8d3b1a68960d05c9ce4789caefb60b1ab502
parent 15739d30
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -217,6 +217,14 @@ struct Matcher {
    const Field mMatcher;
    const Field mMatcher;
    const int32_t mMask;
    const int32_t mMask;


    inline const Field& getMatcher() const {
        return mMatcher;
    }

    inline int32_t getMask() const {
        return mMask;
    }

    bool hasAnyPositionMatcher(int* prefix) const {
    bool hasAnyPositionMatcher(int* prefix) const {
        if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(2) == 0) {
        if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(2) == 0) {
            (*prefix) = mMatcher.getPrefix(2);
            (*prefix) = mMatcher.getPrefix(2);
@@ -224,6 +232,10 @@ struct Matcher {
        }
        }
        return false;
        return false;
    }
    }

    inline bool operator!=(const Matcher& that) const {
        return mMatcher != that.getMatcher() || mMask != that.getMask();
    };
};
};


/**
/**
+3 −2
Original line number Original line Diff line number Diff line
@@ -166,10 +166,11 @@ void filterGaugeValues(const std::vector<Matcher>& matcherFields,
    }
    }
}
}


void getDimensionForCondition(const LogEvent& event, Metric2Condition links,
void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
                              const Metric2Condition& links,
                              vector<HashableDimensionKey>* conditionDimension) {
                              vector<HashableDimensionKey>* conditionDimension) {
    // Get the dimension first by using dimension from what.
    // Get the dimension first by using dimension from what.
    filterValues(links.metricFields, event.getValues(), conditionDimension);
    filterValues(links.metricFields, eventValues, conditionDimension);


    // Then replace the field with the dimension from condition.
    // Then replace the field with the dimension from condition.
    for (auto& dim : *conditionDimension) {
    for (auto& dim : *conditionDimension) {
+2 −1
Original line number Original line Diff line number Diff line
@@ -144,7 +144,8 @@ bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<F
void filterGaugeValues(const std::vector<Matcher>& matchers, const std::vector<FieldValue>& values,
void filterGaugeValues(const std::vector<Matcher>& matchers, const std::vector<FieldValue>& values,
                       std::vector<FieldValue>* output);
                       std::vector<FieldValue>* output);


void getDimensionForCondition(const LogEvent& event, Metric2Condition links,
void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
                              const Metric2Condition& links,
                              std::vector<HashableDimensionKey>* conditionDimension);
                              std::vector<HashableDimensionKey>* conditionDimension);


}  // namespace statsd
}  // namespace statsd
+226 −60
Original line number Original line Diff line number Diff line
@@ -101,6 +101,18 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
    }
    }
    mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
    mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);


    if (mDimensionsInWhat.size() == mInternalDimensions.size()) {
        bool mUseWhatDimensionAsInternalDimension = true;
        for (size_t i = 0; mUseWhatDimensionAsInternalDimension &&
            i < mDimensionsInWhat.size(); ++i) {
            if (mDimensionsInWhat[i] != mInternalDimensions[i]) {
                mUseWhatDimensionAsInternalDimension = false;
            }
        }
    } else {
        mUseWhatDimensionAsInternalDimension = false;
    }

    VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
    VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
         (long long)mBucketSizeNs, (long long)mStartTimeNs);
         (long long)mBucketSizeNs, (long long)mStartTimeNs);
}
}
@@ -141,29 +153,56 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eve
    flushIfNeededLocked(eventTime);
    flushIfNeededLocked(eventTime);


    // Now for each of the on-going event, check if the condition has changed for them.
    // Now for each of the on-going event, check if the condition has changed for them.
    for (auto& pair : mCurrentSlicedDurationTrackerMap) {
    for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
        for (auto& pair : whatIt.second) {
            pair.second->onSlicedConditionMayChange(eventTime);
            pair.second->onSlicedConditionMayChange(eventTime);
        }
        }
    }


    if (mDimensionsInCondition.empty()) {
        return;
    }


    if (mMetric2ConditionLinks.empty()) {
        std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
        std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
        mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
        mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
                                          &conditionDimensionsKeySet);
                                          &conditionDimensionsKeySet);
        for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
            for (const auto& pair : whatIt.second) {
                conditionDimensionsKeySet.erase(pair.first);
            }
        }
        for (const auto& conditionDimension : conditionDimensionsKeySet) {
            for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
                if (!whatIt.second.empty()) {
                    unique_ptr<DurationTracker> newTracker =
                        whatIt.second.begin()->second->clone(eventTime);
                    newTracker->setEventKey(MetricDimensionKey(whatIt.first, conditionDimension));
                    newTracker->onSlicedConditionMayChange(eventTime);
                    whatIt.second[conditionDimension] = std::move(newTracker);
                }
            }
        }
    } else {
        for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
            ConditionKey conditionKey;
            for (const auto& link : mMetric2ConditionLinks) {
                getDimensionForCondition(whatIt.first.getValues(), link,
                                         &conditionKey[link.conditionId]);
            }
            std::unordered_set<HashableDimensionKey> conditionDimensionsKeys;
            mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
                           &conditionDimensionsKeys);


    for (auto& pair : mCurrentSlicedDurationTrackerMap) {
            for (const auto& conditionDimension : conditionDimensionsKeys) {
        conditionDimensionsKeySet.erase(pair.first.getDimensionKeyInCondition());
                if (!whatIt.second.empty() &&
                    whatIt.second.find(conditionDimension) == whatIt.second.end()) {
                    auto newTracker = whatIt.second.begin()->second->clone(eventTime);
                    newTracker->setEventKey(MetricDimensionKey(whatIt.first, conditionDimension));
                    newTracker->onSlicedConditionMayChange(eventTime);
                    whatIt.second[conditionDimension] = std::move(newTracker);
                }
                }
    std::unordered_set<MetricDimensionKey> newKeys;
    for (const auto& conditionDimensionsKey : conditionDimensionsKeySet) {
        for (auto& pair : mCurrentSlicedDurationTrackerMap) {
            auto newKey =
                MetricDimensionKey(pair.first.getDimensionKeyInWhat(), conditionDimensionsKey);
            if (newKeys.find(newKey) == newKeys.end()) {
                mCurrentSlicedDurationTrackerMap[newKey] = pair.second->clone(eventTime);
                mCurrentSlicedDurationTrackerMap[newKey]->setEventKey(newKey);
                mCurrentSlicedDurationTrackerMap[newKey]->onSlicedConditionMayChange(eventTime);
            }
            }
            newKeys.insert(newKey);
        }
        }
    }
    }
}
}
@@ -175,10 +214,12 @@ void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
    flushIfNeededLocked(eventTime);
    flushIfNeededLocked(eventTime);
    // TODO: need to populate the condition change time from the event which triggers the condition
    // TODO: need to populate the condition change time from the event which triggers the condition
    // change, instead of using current time.
    // change, instead of using current time.
    for (auto& pair : mCurrentSlicedDurationTrackerMap) {
    for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
        for (auto& pair : whatIt.second) {
            pair.second->onConditionChanged(conditionMet, eventTime);
            pair.second->onConditionChanged(conditionMet, eventTime);
        }
        }
    }
    }
}


void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
                                                ProtoOutputStream* protoOutput) {
                                                ProtoOutputStream* protoOutput) {
@@ -241,15 +282,22 @@ void DurationMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
        return;
        return;
    }
    }
    VLOG("flushing...........");
    VLOG("flushing...........");
    for (auto it = mCurrentSlicedDurationTrackerMap.begin();
    for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
            it != mCurrentSlicedDurationTrackerMap.end();) {
            whatIt != mCurrentSlicedDurationTrackerMap.end();) {
        for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
            if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) {
            if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) {
            VLOG("erase bucket for key %s", it->first.c_str());
                VLOG("erase bucket for key %s %s", whatIt->first.c_str(), it->first.c_str());
            it = mCurrentSlicedDurationTrackerMap.erase(it);
                it = whatIt->second.erase(it);
            } else {
            } else {
                ++it;
                ++it;
            }
            }
        }
        }
        if (whatIt->second.empty()) {
            whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
        } else {
            whatIt++;
        }
    }


    int numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
    int numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
@@ -257,15 +305,22 @@ void DurationMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
}
}


void DurationMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) {
void DurationMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) {
    for (auto it = mCurrentSlicedDurationTrackerMap.begin();
    for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
         it != mCurrentSlicedDurationTrackerMap.end();) {
            whatIt != mCurrentSlicedDurationTrackerMap.end();) {
        for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
            if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
            if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
            VLOG("erase bucket for key %s", it->first.c_str());
                VLOG("erase bucket for key %s %s", whatIt->first.c_str(), it->first.c_str());
            it = mCurrentSlicedDurationTrackerMap.erase(it);
                it = whatIt->second.erase(it);
            } else {
            } else {
                ++it;
                ++it;
            }
            }
        }
        }
        if (whatIt->second.empty()) {
            whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
        } else {
            whatIt++;
        }
    }
}
}


void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
@@ -276,18 +331,16 @@ void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
    fprintf(out, "DurationMetric %lld dimension size %lu\n", (long long)mMetricId,
    fprintf(out, "DurationMetric %lld dimension size %lu\n", (long long)mMetricId,
            (unsigned long)mCurrentSlicedDurationTrackerMap.size());
            (unsigned long)mCurrentSlicedDurationTrackerMap.size());
    if (verbose) {
    if (verbose) {
        for (const auto& slice : mCurrentSlicedDurationTrackerMap) {
        for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
            fprintf(out, "\t%s\n", slice.first.c_str());
            for (const auto& slice : whatIt.second) {
                fprintf(out, "\t%s\t%s\n", whatIt.first.c_str(), slice.first.c_str());
                slice.second->dumpStates(out, verbose);
                slice.second->dumpStates(out, verbose);
            }
            }
        }
        }
    }
    }
}


bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
    // the key is not new, we are good.
    if (mCurrentSlicedDurationTrackerMap.find(newKey) != mCurrentSlicedDurationTrackerMap.end()) {
        return false;
    }
    // 1. Report the tuple count if the tuple count > soft limit
    // 1. Report the tuple count if the tuple count > soft limit
    if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
    if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
        size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
        size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
@@ -302,48 +355,161 @@ bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey
    return false;
    return false;
}
}


void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey,
                                              const ConditionKey& conditionKeys,
                                              bool condition, const LogEvent& event) {
    const auto& whatKey = eventKey.getDimensionKeyInWhat();
    const auto& condKey = eventKey.getDimensionKeyInCondition();

    auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
    if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
        if (hitGuardRailLocked(eventKey)) {
            return;
        }
        mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey);
    } else {
        if (whatIt->second.find(condKey) == whatIt->second.end()) {
            if (hitGuardRailLocked(eventKey)) {
                return;
            }
            mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey);
        }
    }

    auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(condKey);
    if (mUseWhatDimensionAsInternalDimension) {
        it->second->noteStart(whatKey, condition,
                              event.GetElapsedTimestampNs(), conditionKeys);
        return;
    }

    std::vector<HashableDimensionKey> values;
    filterValues(mInternalDimensions, event.getValues(), &values);
    if (values.empty()) {
        it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
                              event.GetElapsedTimestampNs(), conditionKeys);
    } else {
        for (const auto& value : values) {
            it->second->noteStart(value, condition, event.GetElapsedTimestampNs(), conditionKeys);
        }
    }

}

void DurationMetricProducer::onMatchedLogEventInternalLocked(
void DurationMetricProducer::onMatchedLogEventInternalLocked(
        const size_t matcherIndex, const MetricDimensionKey& eventKey,
        const size_t matcherIndex, const MetricDimensionKey& eventKey,
        const ConditionKey& conditionKeys, bool condition,
        const ConditionKey& conditionKeys, bool condition,
        const LogEvent& event) {
        const LogEvent& event) {
    ALOGW("Not used in duration tracker.");
}

void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
                                                     const LogEvent& event) {
    uint64_t eventTimeNs = event.GetElapsedTimestampNs();
    if (eventTimeNs < mStartTimeNs) {
        return;
    }

    flushIfNeededLocked(event.GetElapsedTimestampNs());
    flushIfNeededLocked(event.GetElapsedTimestampNs());


    // Handles Stopall events.
    if (matcherIndex == mStopAllIndex) {
    if (matcherIndex == mStopAllIndex) {
        for (auto& pair : mCurrentSlicedDurationTrackerMap) {
        for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
            for (auto& pair : whatIt.second) {
                pair.second->noteStopAll(event.GetElapsedTimestampNs());
                pair.second->noteStopAll(event.GetElapsedTimestampNs());
            }
            }
        }
        return;
        return;
    }
    }


    if (mCurrentSlicedDurationTrackerMap.find(eventKey) == mCurrentSlicedDurationTrackerMap.end()) {
    vector<HashableDimensionKey> dimensionInWhatValues;
        if (hitGuardRailLocked(eventKey)) {
    if (!mDimensionsInWhat.empty()) {
        filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
    } else {
        dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY);
    }

    // Handles Stop events.
    if (matcherIndex == mStopIndex) {
        if (mUseWhatDimensionAsInternalDimension) {
            for (const HashableDimensionKey& whatKey : dimensionInWhatValues) {
                auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
                if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
                    for (const auto& condIt : whatIt->second) {
                        condIt.second->noteStop(whatKey, event.GetElapsedTimestampNs(), false);
                    }
                }
            }
            return;
            return;
        }
        }
        mCurrentSlicedDurationTrackerMap[eventKey] = createDurationTracker(eventKey);

        std::vector<HashableDimensionKey> internalDimensionKeys;
        filterValues(mInternalDimensions, event.getValues(), &internalDimensionKeys);
        if (internalDimensionKeys.empty()) {
            internalDimensionKeys.push_back(DEFAULT_DIMENSION_KEY);
        }
        for (const HashableDimensionKey& whatDimension : dimensionInWhatValues) {
            auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
            if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
                for (const auto& condIt : whatIt->second) {
                    for (const auto& internalDimensionKey : internalDimensionKeys) {
                        condIt.second->noteStop(
                            internalDimensionKey, event.GetElapsedTimestampNs(), false);
                    }
                }
            }
        }
        return;
    }
    }


    auto it = mCurrentSlicedDurationTrackerMap.find(eventKey);
    bool condition;
    ConditionKey conditionKey;
    std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
    if (mConditionSliced) {
        for (const auto& link : mMetric2ConditionLinks) {
            getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
        }


    std::vector<HashableDimensionKey> values;
        auto conditionState =
    filterValues(mInternalDimensions, event.getValues(), &values);
            mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
    if (values.empty()) {
                           &dimensionKeysInCondition);
        if (matcherIndex == mStartIndex) {
        condition = (conditionState == ConditionState::kTrue);
            it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
        if (mDimensionsInCondition.empty() && condition) {
                                  event.GetElapsedTimestampNs(), conditionKeys);
            dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
        } else if (matcherIndex == mStopIndex) {
            it->second->noteStop(DEFAULT_DIMENSION_KEY, event.GetElapsedTimestampNs(), false);
        }
        }
    } else {
    } else {
        for (const auto& value : values) {
        condition = mCondition;
            if (matcherIndex == mStartIndex) {
        if (condition) {
                it->second->noteStart(value, condition, event.GetElapsedTimestampNs(), conditionKeys);
            dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
            } else if (matcherIndex == mStopIndex) {
                it->second->noteStop(value, event.GetElapsedTimestampNs(), false);
            }
        }
        }
    }
    }


    for (const auto& whatDimension : dimensionInWhatValues) {
        auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
        // If the what dimension is already there, we should update all the trackers even
        // the condition is false.
        if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
            for (const auto& condIt : whatIt->second) {
                const bool cond = dimensionKeysInCondition.find(condIt.first) !=
                        dimensionKeysInCondition.end();
                handleStartEvent(MetricDimensionKey(whatDimension, condIt.first),
                                 conditionKey, cond, event);
            }
        } else {
            // If it is a new what dimension key, we need to handle the start events for all current
            // condition dimensions.
            for (const auto& conditionDimension : dimensionKeysInCondition) {
                handleStartEvent(MetricDimensionKey(whatDimension, conditionDimension),
                                 conditionKey, condition, event);
            }
            }
        }
        if (dimensionKeysInCondition.empty()) {
            handleStartEvent(MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
                             conditionKey, condition, event);
        }
    }
}



size_t DurationMetricProducer::byteSizeLocked() const {
size_t DurationMetricProducer::byteSizeLocked() const {
    size_t totalSize = 0;
    size_t totalSize = 0;
+10 −2
Original line number Original line Diff line number Diff line
@@ -50,12 +50,16 @@ public:
                                         const sp<AlarmMonitor>& anomalyAlarmMonitor) override;
                                         const sp<AlarmMonitor>& anomalyAlarmMonitor) override;


protected:
protected:
    void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override;
    void onMatchedLogEventInternalLocked(
    void onMatchedLogEventInternalLocked(
            const size_t matcherIndex, const MetricDimensionKey& eventKey,
            const size_t matcherIndex, const MetricDimensionKey& eventKey,
            const ConditionKey& conditionKeys, bool condition,
            const ConditionKey& conditionKeys, bool condition,
            const LogEvent& event) override;
            const LogEvent& event) override;


private:
private:
    void handleStartEvent(const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys,
                          bool condition, const LogEvent& event);

    void onDumpReportLocked(const uint64_t dumpTimeNs,
    void onDumpReportLocked(const uint64_t dumpTimeNs,
                            android::util::ProtoOutputStream* protoOutput) override;
                            android::util::ProtoOutputStream* protoOutput) override;


@@ -92,12 +96,16 @@ private:
    // The dimension from the atom predicate. e.g., uid, wakelock name.
    // The dimension from the atom predicate. e.g., uid, wakelock name.
    vector<Matcher> mInternalDimensions;
    vector<Matcher> mInternalDimensions;


    // This boolean is true iff When mInternalDimensions == mDimensionsInWhat
    bool mUseWhatDimensionAsInternalDimension;

    // Save the past buckets and we can clear when the StatsLogReport is dumped.
    // Save the past buckets and we can clear when the StatsLogReport is dumped.
    // TODO: Add a lock to mPastBuckets.
    // TODO: Add a lock to mPastBuckets.
    std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>> mPastBuckets;
    std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>> mPastBuckets;


    // The current bucket.
    // The duration trackers in the current bucket.
    std::unordered_map<MetricDimensionKey, std::unique_ptr<DurationTracker>>
    std::unordered_map<HashableDimensionKey,
        std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>>
            mCurrentSlicedDurationTrackerMap;
            mCurrentSlicedDurationTrackerMap;


    // Helper function to create a duration tracker given the metric aggregation type.
    // Helper function to create a duration tracker given the metric aggregation type.
Loading