1 /* 2 * Copyright (C) 2018 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 #ifndef ANDROID_EVENT_METRIC_H_ 17 #define ANDROID_EVENT_METRIC_H_ 18 19 #include <media/MediaAnalyticsItem.h> 20 #include <utils/Timers.h> 21 22 namespace android { 23 24 // This is a simple holder for the statistics recorded in EventMetric. 25 struct EventStatistics { 26 // The count of times the event occurred. 27 int64_t count; 28 29 // The minimum and maximum values recorded in the Record method. 30 double min; 31 double max; 32 33 // The average (mean) of all values recorded. 34 double mean; 35 // The sum of squared devation. Variance can be calculated from 36 // this value. 37 // var = sum_squared_deviation / count; 38 double sum_squared_deviation; 39 }; 40 41 // The EventMetric class is used to accumulate stats about an event over time. 42 // A common use case is to track clock timings for a method call or operation. 43 // An EventMetric can break down stats by a dimension specified by the 44 // application. E.g. an application may want to track counts broken out by 45 // error code or the size of some parameter. 46 // 47 // Example: 48 // 49 // struct C { 50 // status_t DoWork() { 51 // unsigned long start_time = now(); 52 // status_t result; 53 // 54 // // DO WORK and determine result; 55 // 56 // work_event_.Record(now() - start_time, result); 57 // 58 // return result; 59 // } 60 // EventMetric<status_t> work_event_; 61 // }; 62 // 63 // C c; 64 // c.DoWork(); 65 // 66 // std::map<int, int64_t> values; 67 // metric.ExportValues( 68 // [&] (int attribute_value, int64_t value) { 69 // values[attribute_value] = value; 70 // }); 71 // // Do something with the exported stat. 72 // 73 template<typename AttributeType> 74 class EventMetric { 75 public: 76 // Instantiate the counter with the given metric name and 77 // attribute names. |attribute_names| must not be null. EventMetric(const std::string & metric_name,const std::string & attribute_name)78 EventMetric( 79 const std::string& metric_name, 80 const std::string& attribute_name) 81 : metric_name_(metric_name), 82 attribute_name_(attribute_name) {} 83 84 // Increment the count of times the operation occurred with this 85 // combination of attributes. Record(double value,AttributeType attribute)86 void Record(double value, AttributeType attribute) { 87 if (values_.find(attribute) != values_.end()) { 88 EventStatistics* stats = values_[attribute].get(); 89 // Using method of provisional means. 90 double deviation = value - stats->mean; 91 stats->mean = stats->mean + (deviation / stats->count); 92 stats->sum_squared_deviation = 93 stats->sum_squared_deviation + (deviation * (value - stats->mean)); 94 stats->count++; 95 96 stats->min = stats->min < value ? stats->min : value; 97 stats->max = stats->max > value ? stats->max : value; 98 } else { 99 std::unique_ptr<EventStatistics> stats = 100 std::make_unique<EventStatistics>(); 101 stats->count = 1; 102 stats->min = value; 103 stats->max = value; 104 stats->mean = value; 105 stats->sum_squared_deviation = 0; 106 values_[attribute] = std::move(stats); 107 } 108 }; 109 110 // Export the metrics to the provided |function|. Each value for Attribute 111 // has a separate set of stats. As such, |function| will be called once per 112 // value of Attribute. ExportValues(std::function<void (const AttributeType &,const EventStatistics &)> function)113 void ExportValues( 114 std::function<void (const AttributeType&, 115 const EventStatistics&)> function) const { 116 for (auto it = values_.begin(); it != values_.end(); it++) { 117 function(it->first, *(it->second)); 118 } 119 } 120 metric_name()121 const std::string& metric_name() const { return metric_name_; }; 122 123 private: 124 const std::string metric_name_; 125 const std::string attribute_name_; 126 std::map<AttributeType, std::unique_ptr<struct EventStatistics>> values_; 127 }; 128 129 // The EventTimer is a supporting class for EventMetric instances that are used 130 // to time methods. The EventTimer starts a timer when first in scope, and 131 // records the timing when exiting scope. 132 // 133 // Example: 134 // 135 // EventMetric<int> my_metric; 136 // 137 // { 138 // EventTimer<int> my_timer(&my_metric); 139 // // Set the attribute to associate with this timing. 140 // my_timer.SetAttribtue(42); 141 // 142 // // Do some work that you want to time. 143 // 144 // } // The EventTimer destructor will record the the timing in my_metric; 145 // 146 template<typename AttributeType> 147 class EventTimer { 148 public: EventTimer(EventMetric<AttributeType> * metric)149 explicit EventTimer(EventMetric<AttributeType>* metric) 150 :start_time_(systemTime()), metric_(metric) { 151 } 152 ~EventTimer()153 virtual ~EventTimer() { 154 if (metric_) { 155 metric_->Record(ns2us(systemTime() - start_time_), attribute_); 156 } 157 } 158 159 // Set the attribute to associate with this timing. E.g. this can be used to 160 // record the return code from the work that was timed. SetAttribute(const AttributeType & attribute)161 void SetAttribute(const AttributeType& attribute) { 162 attribute_ = attribute; 163 } 164 165 protected: 166 // Visible for testing only. 167 nsecs_t start_time_; 168 169 private: 170 EventMetric<AttributeType>* metric_; 171 AttributeType attribute_; 172 }; 173 174 } // namespace android 175 176 #endif // ANDROID_EVENT_METRIC_H_ 177