Home | History | Annotate | Download | only in media
      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.
     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 //
    146 template<typename AttributeType>
    147 class 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