1 /* 2 * Copyright (C) 2021 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 #pragma once 18 19 #include <android/util/ProtoOutputStream.h> 20 #include <gtest/gtest_prod.h> 21 #include <kll.h> 22 23 #include <optional> 24 25 #include "MetricProducer.h" 26 #include "ValueMetricProducer.h" 27 #include "condition/ConditionTimer.h" 28 #include "condition/ConditionTracker.h" 29 #include "matchers/EventMatcherWizard.h" 30 #include "src/statsd_config.pb.h" 31 #include "stats_log_util.h" 32 33 using dist_proc::aggregation::KllQuantile; 34 35 namespace android { 36 namespace os { 37 namespace statsd { 38 39 // Uses KllQuantile to aggregate values within buckets. 40 // 41 // There are different events that might complete a bucket 42 // - a condition change 43 // - an app upgrade 44 // - an alarm set to the end of the bucket 45 class KllMetricProducer : public ValueMetricProducer<std::unique_ptr<KllQuantile>, Empty> { 46 public: 47 KllMetricProducer(const ConfigKey& key, const KllMetric& kllMetric, const uint64_t protoHash, 48 const PullOptions& pullOptions, const BucketOptions& bucketOptions, 49 const WhatOptions& whatOptions, const ConditionOptions& conditionOptions, 50 const StateOptions& stateOptions, const ActivationOptions& activationOptions, 51 const GuardrailOptions& guardrailOptions); 52 getMetricType()53 inline MetricType getMetricType() const override { 54 return METRIC_TYPE_KLL; 55 } 56 57 protected: 58 private: getConditionIdForMetric(const StatsdConfig & config,const int configIndex)59 inline optional<int64_t> getConditionIdForMetric(const StatsdConfig& config, 60 const int configIndex) const override { 61 const KllMetric& metric = config.kll_metric(configIndex); 62 return metric.has_condition() ? make_optional(metric.condition()) : nullopt; 63 } 64 getWhatAtomMatcherIdForMetric(const StatsdConfig & config,const int configIndex)65 inline int64_t getWhatAtomMatcherIdForMetric(const StatsdConfig& config, 66 const int configIndex) const override { 67 return config.kll_metric(configIndex).what(); 68 } 69 getConditionLinksForMetric(const StatsdConfig & config,const int configIndex)70 inline ConditionLinks getConditionLinksForMetric(const StatsdConfig& config, 71 const int configIndex) const override { 72 return config.kll_metric(configIndex).links(); 73 } 74 75 // Determine whether or not a LogEvent can be skipped. canSkipLogEventLocked(const MetricDimensionKey & eventKey,bool condition,int64_t eventTimeNs,const std::map<int,HashableDimensionKey> & statePrimaryKeys)76 inline bool canSkipLogEventLocked( 77 const MetricDimensionKey& eventKey, bool condition, int64_t eventTimeNs, 78 const std::map<int, HashableDimensionKey>& statePrimaryKeys) const override { 79 // Can only skip if the condition is false. 80 // We assume metric is pushed since KllMetric doesn't support pulled metrics. 81 return !condition; 82 } 83 84 DumpProtoFields getDumpProtoFields() const override; 85 aggregatedValueToString(const std::unique_ptr<KllQuantile> & aggregate)86 inline std::string aggregatedValueToString( 87 const std::unique_ptr<KllQuantile>& aggregate) const override { 88 return std::to_string(aggregate->num_values()) + " values"; 89 } 90 multipleBucketsSkipped(const int64_t numBucketsForward)91 inline bool multipleBucketsSkipped(const int64_t numBucketsForward) const override { 92 // Always false because we assume KllMetric is pushed only for now. 93 return false; 94 } 95 96 // The KllQuantile ptr ownership is transferred to newly created PastBuckets from Intervals. 97 PastBucket<std::unique_ptr<KllQuantile>> buildPartialBucket( 98 int64_t bucketEndTime, std::vector<Interval>& intervals) override; 99 100 void writePastBucketAggregateToProto(const int aggIndex, 101 const std::unique_ptr<KllQuantile>& kll, 102 const int sampleSize, 103 ProtoOutputStream* const protoOutput) const override; 104 105 bool aggregateFields(const int64_t eventTimeNs, const MetricDimensionKey& eventKey, 106 const LogEvent& event, std::vector<Interval>& intervals, 107 Empty& empty) override; 108 109 // Internal function to calculate the current used bytes. 110 size_t byteSizeLocked() const override; 111 112 FRIEND_TEST(KllMetricProducerTest, TestByteSize); 113 FRIEND_TEST(KllMetricProducerTest, TestPushedEventsWithoutCondition); 114 FRIEND_TEST(KllMetricProducerTest, TestPushedEventsWithCondition); 115 FRIEND_TEST(KllMetricProducerTest, TestForcedBucketSplitWhenConditionUnknownSkipsBucket); 116 117 FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown); 118 FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall); 119 FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable); 120 121 FRIEND_TEST(KllMetricProducerTest_PartialBucket, TestPushedEventsMultipleBuckets); 122 123 FRIEND_TEST(ConfigUpdateTest, TestUpdateKllMetrics); 124 }; 125 126 } // namespace statsd 127 } // namespace os 128 } // namespace android 129