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