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