blob: dbb736af8e83aaa24e55d2b224719226dac49363 [file] [log] [blame]
Adam Stonef0e618d2018-01-17 19:20:41 -08001/*
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_