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 22namespace android { 23 24// This is a simple holder for the statistics recorded in EventMetric. 25struct 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// 73template<typename AttributeType> 74class EventMetric { 75 public: 76 // Instantiate the counter with the given metric name and 77 // attribute names. |attribute_names| must not be null. 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. 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. 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 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// 146template<typename AttributeType> 147class EventTimer { 148 public: 149 explicit EventTimer(EventMetric<AttributeType>* metric) 150 :start_time_(systemTime()), metric_(metric) { 151 } 152 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. 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