Adds an EventMetric class, associated unit tests, and an instance of the EventMetric to DrmHal. Also added a unit test for CounterMetric and created a class to hold all of the future metric instances. BUG: 64001676 Test: Added and ran unit tests. Also added a CTS test case. Change-Id: Ic94bedd5f8293a58a939613a4ae69ce656a772begugelfrei
parent
38428ce1b3
commit
f0e618d0ee
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <media/DrmMetrics.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void ExportCounterMetric(const android::CounterMetric<T>& counter,
|
||||||
|
android::MediaAnalyticsItem* item) {
|
||||||
|
std::string success_count_name = counter.metric_name() + "/ok/count";
|
||||||
|
std::string error_count_name = counter.metric_name() + "/error/count";
|
||||||
|
counter.ExportValues(
|
||||||
|
[&] (const android::status_t status, const int64_t value) {
|
||||||
|
if (status == android::OK) {
|
||||||
|
item->setInt64(success_count_name.c_str(), value);
|
||||||
|
} else {
|
||||||
|
int64_t total_errors(0);
|
||||||
|
item->getInt64(error_count_name.c_str(), &total_errors);
|
||||||
|
item->setInt64(error_count_name.c_str(), total_errors + value);
|
||||||
|
// TODO: Add support for exporting the list of error values.
|
||||||
|
// This probably needs to be added to MediaAnalyticsItem.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void ExportEventMetric(const android::EventMetric<T>& event,
|
||||||
|
android::MediaAnalyticsItem* item) {
|
||||||
|
std::string success_count_name = event.metric_name() + "/ok/count";
|
||||||
|
std::string error_count_name = event.metric_name() + "/error/count";
|
||||||
|
std::string timing_name = event.metric_name() + "/average_time_micros";
|
||||||
|
event.ExportValues(
|
||||||
|
[&] (const android::status_t& status,
|
||||||
|
const android::EventStatistics& value) {
|
||||||
|
if (status == android::OK) {
|
||||||
|
item->setInt64(success_count_name.c_str(), value.count);
|
||||||
|
item->setInt64(timing_name.c_str(), value.mean);
|
||||||
|
} else {
|
||||||
|
int64_t total_errors(0);
|
||||||
|
item->getInt64(error_count_name.c_str(), &total_errors);
|
||||||
|
item->setInt64(error_count_name.c_str(),
|
||||||
|
total_errors + value.count);
|
||||||
|
// TODO: Add support for exporting the list of error values.
|
||||||
|
// This probably needs to be added to MediaAnalyticsItem.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace anonymous
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
MediaDrmMetrics::MediaDrmMetrics()
|
||||||
|
: mOpenSessionCounter("/drm/mediadrm/open_session", "status"),
|
||||||
|
mGetKeyRequestTiming("/drm/mediadrm/get_key_request", "status") {
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaDrmMetrics::Export(MediaAnalyticsItem* item) {
|
||||||
|
ExportCounterMetric(mOpenSessionCounter, item);
|
||||||
|
ExportEventMetric(mGetKeyRequestTiming, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace android
|
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "EventMetric.h"
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the EventMetric class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST(EventMetricTest, IntDataTypeEmpty) {
|
||||||
|
EventMetric<int> metric("MyMetricName", "MetricAttributeName");
|
||||||
|
|
||||||
|
std::map<int, EventStatistics> values;
|
||||||
|
|
||||||
|
metric.ExportValues(
|
||||||
|
[&] (int attribute_value, const EventStatistics& value) {
|
||||||
|
values[attribute_value] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_TRUE(values.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EventMetricTest, IntDataType) {
|
||||||
|
EventMetric<int> metric("MyMetricName", "MetricAttributeName");
|
||||||
|
|
||||||
|
std::map<int, EventStatistics> values;
|
||||||
|
|
||||||
|
metric.Record(4, 7);
|
||||||
|
metric.Record(5, 8);
|
||||||
|
metric.Record(5, 8);
|
||||||
|
metric.Record(5, 8);
|
||||||
|
metric.Record(6, 8);
|
||||||
|
metric.Record(6, 8);
|
||||||
|
metric.Record(6, 8);
|
||||||
|
|
||||||
|
metric.ExportValues(
|
||||||
|
[&] (int attribute_value, const EventStatistics& value) {
|
||||||
|
values[attribute_value] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_EQ(2u, values.size());
|
||||||
|
EXPECT_EQ(4, values[7].min);
|
||||||
|
EXPECT_EQ(4, values[7].max);
|
||||||
|
EXPECT_EQ(4, values[7].mean);
|
||||||
|
EXPECT_EQ(1, values[7].count);
|
||||||
|
|
||||||
|
EXPECT_EQ(5, values[8].min);
|
||||||
|
EXPECT_EQ(6, values[8].max);
|
||||||
|
// This is an approximate value because of the technique we're using.
|
||||||
|
EXPECT_NEAR(5.5, values[8].mean, 0.2);
|
||||||
|
EXPECT_EQ(6, values[8].count);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EventMetricTest, StringDataType) {
|
||||||
|
EventMetric<std::string> metric("MyMetricName", "MetricAttributeName");
|
||||||
|
|
||||||
|
std::map<std::string, EventStatistics> values;
|
||||||
|
|
||||||
|
metric.Record(1, "a");
|
||||||
|
metric.Record(2, "b");
|
||||||
|
metric.Record(2, "b");
|
||||||
|
metric.Record(3, "b");
|
||||||
|
metric.Record(3, "b");
|
||||||
|
|
||||||
|
metric.ExportValues(
|
||||||
|
[&] (std::string attribute_value, const EventStatistics& value) {
|
||||||
|
values[attribute_value] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_EQ(2u, values.size());
|
||||||
|
EXPECT_EQ(1, values["a"].min);
|
||||||
|
EXPECT_EQ(1, values["a"].max);
|
||||||
|
EXPECT_EQ(1, values["a"].mean);
|
||||||
|
EXPECT_EQ(1, values["a"].count);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, values["b"].min);
|
||||||
|
EXPECT_EQ(3, values["b"].max);
|
||||||
|
EXPECT_NEAR(2.5, values["b"].mean, 0.2);
|
||||||
|
EXPECT_EQ(4, values["b"].count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper class that allows us to mock the clock.
|
||||||
|
template<typename AttributeType>
|
||||||
|
class MockEventTimer : public EventTimer<AttributeType> {
|
||||||
|
public:
|
||||||
|
explicit MockEventTimer(nsecs_t time_delta_ns,
|
||||||
|
EventMetric<AttributeType>* metric)
|
||||||
|
: EventTimer<AttributeType>(metric) {
|
||||||
|
// Pretend the event started earlier.
|
||||||
|
this->start_time_ = systemTime() - time_delta_ns;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(EventTimerTest, IntDataType) {
|
||||||
|
EventMetric<int> metric("MyMetricName", "MetricAttributeName");
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
{
|
||||||
|
// Add a mock time delta.
|
||||||
|
MockEventTimer<int> metric_timer(i * 1000000, &metric);
|
||||||
|
metric_timer.SetAttribute(i % 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<int, EventStatistics> values;
|
||||||
|
metric.ExportValues(
|
||||||
|
[&] (int attribute_value, const EventStatistics& value) {
|
||||||
|
values[attribute_value] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_EQ(2u, values.size());
|
||||||
|
EXPECT_LT(values[0].min, values[0].max);
|
||||||
|
EXPECT_GE(4000, values[0].max);
|
||||||
|
EXPECT_GT(values[0].mean, values[0].min);
|
||||||
|
EXPECT_LE(values[0].mean, values[0].max);
|
||||||
|
EXPECT_EQ(3, values[0].count);
|
||||||
|
|
||||||
|
EXPECT_LT(values[1].min, values[1].max);
|
||||||
|
EXPECT_GE(3000, values[1].max);
|
||||||
|
EXPECT_GT(values[1].mean, values[1].min);
|
||||||
|
EXPECT_LE(values[1].mean, values[1].max);
|
||||||
|
EXPECT_EQ(2, values[1].count);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace android
|
@ -0,0 +1 @@
|
|||||||
|
../../media/libmedia/include/media/DrmMetrics.h
|
@ -0,0 +1 @@
|
|||||||
|
../../media/libmedia/include/media/EventMetric.h
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DRM_METRICS_H_
|
||||||
|
#define DRM_METRICS_H_
|
||||||
|
|
||||||
|
#include <media/CounterMetric.h>
|
||||||
|
#include <media/EventMetric.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class contains the definition of metrics captured within MediaDrm.
|
||||||
|
* It also contains a method for exporting all of the metrics to a
|
||||||
|
* MediaAnalyticsItem instance.
|
||||||
|
*/
|
||||||
|
class MediaDrmMetrics {
|
||||||
|
public:
|
||||||
|
explicit MediaDrmMetrics();
|
||||||
|
// Counter of times openSession was called.
|
||||||
|
CounterMetric<status_t> mOpenSessionCounter;
|
||||||
|
// Counter and timing of the getKeyRequest call.
|
||||||
|
EventMetric<status_t> mGetKeyRequestTiming;
|
||||||
|
|
||||||
|
// TODO: Add the full set of metrics to be captured.
|
||||||
|
|
||||||
|
// Export the metrics to a MediaAnalyticsItem.
|
||||||
|
void Export(MediaAnalyticsItem* item);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
#endif // DRM_METRICS_H_
|
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#ifndef ANDROID_EVENT_METRIC_H_
|
||||||
|
#define ANDROID_EVENT_METRIC_H_
|
||||||
|
|
||||||
|
#include <media/MediaAnalyticsItem.h>
|
||||||
|
#include <utils/Timers.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
// This is a simple holder for the statistics recorded in EventMetric.
|
||||||
|
struct EventStatistics {
|
||||||
|
// The count of times the event occurred.
|
||||||
|
int64_t count;
|
||||||
|
|
||||||
|
// The minimum and maximum values recorded in the Record method.
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
|
||||||
|
// The average (mean) of all values recorded.
|
||||||
|
double mean;
|
||||||
|
// The sum of squared devation. Variance can be calculated from
|
||||||
|
// this value.
|
||||||
|
// var = sum_squared_deviation / count;
|
||||||
|
double sum_squared_deviation;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The EventMetric class is used to accumulate stats about an event over time.
|
||||||
|
// A common use case is to track clock timings for a method call or operation.
|
||||||
|
// An EventMetric can break down stats by a dimension specified by the
|
||||||
|
// application. E.g. an application may want to track counts broken out by
|
||||||
|
// error code or the size of some parameter.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// struct C {
|
||||||
|
// status_t DoWork() {
|
||||||
|
// unsigned long start_time = now();
|
||||||
|
// status_t result;
|
||||||
|
//
|
||||||
|
// // DO WORK and determine result;
|
||||||
|
//
|
||||||
|
// work_event_.Record(now() - start_time, result);
|
||||||
|
//
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
// EventMetric<status_t> work_event_;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// C c;
|
||||||
|
// c.DoWork();
|
||||||
|
//
|
||||||
|
// std::map<int, int64_t> values;
|
||||||
|
// metric.ExportValues(
|
||||||
|
// [&] (int attribute_value, int64_t value) {
|
||||||
|
// values[attribute_value] = value;
|
||||||
|
// });
|
||||||
|
// // Do something with the exported stat.
|
||||||
|
//
|
||||||
|
template<typename AttributeType>
|
||||||
|
class EventMetric {
|
||||||
|
public:
|
||||||
|
// Instantiate the counter with the given metric name and
|
||||||
|
// attribute names. |attribute_names| must not be null.
|
||||||
|
EventMetric(
|
||||||
|
const std::string& metric_name,
|
||||||
|
const std::string& attribute_name)
|
||||||
|
: metric_name_(metric_name),
|
||||||
|
attribute_name_(attribute_name) {}
|
||||||
|
|
||||||
|
// Increment the count of times the operation occurred with this
|
||||||
|
// combination of attributes.
|
||||||
|
void Record(double value, AttributeType attribute) {
|
||||||
|
if (values_.find(attribute) != values_.end()) {
|
||||||
|
EventStatistics* stats = values_[attribute].get();
|
||||||
|
// Using method of provisional means.
|
||||||
|
double deviation = value - stats->mean;
|
||||||
|
stats->mean = stats->mean + (deviation / stats->count);
|
||||||
|
stats->sum_squared_deviation =
|
||||||
|
stats->sum_squared_deviation + (deviation * (value - stats->mean));
|
||||||
|
stats->count++;
|
||||||
|
|
||||||
|
stats->min = stats->min < value ? stats->min : value;
|
||||||
|
stats->max = stats->max > value ? stats->max : value;
|
||||||
|
} else {
|
||||||
|
std::unique_ptr<EventStatistics> stats =
|
||||||
|
std::make_unique<EventStatistics>();
|
||||||
|
stats->count = 1;
|
||||||
|
stats->min = value;
|
||||||
|
stats->max = value;
|
||||||
|
stats->mean = value;
|
||||||
|
stats->sum_squared_deviation = 0;
|
||||||
|
values_[attribute] = std::move(stats);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export the metrics to the provided |function|. Each value for Attribute
|
||||||
|
// has a separate set of stats. As such, |function| will be called once per
|
||||||
|
// value of Attribute.
|
||||||
|
void ExportValues(
|
||||||
|
std::function<void (const AttributeType&,
|
||||||
|
const EventStatistics&)> function) const {
|
||||||
|
for (auto it = values_.begin(); it != values_.end(); it++) {
|
||||||
|
function(it->first, *(it->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& metric_name() const { return metric_name_; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string metric_name_;
|
||||||
|
const std::string attribute_name_;
|
||||||
|
std::map<AttributeType, std::unique_ptr<struct EventStatistics>> values_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The EventTimer is a supporting class for EventMetric instances that are used
|
||||||
|
// to time methods. The EventTimer starts a timer when first in scope, and
|
||||||
|
// records the timing when exiting scope.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// EventMetric<int> my_metric;
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// EventTimer<int> my_timer(&my_metric);
|
||||||
|
// // Set the attribute to associate with this timing.
|
||||||
|
// my_timer.SetAttribtue(42);
|
||||||
|
//
|
||||||
|
// // Do some work that you want to time.
|
||||||
|
//
|
||||||
|
// } // The EventTimer destructor will record the the timing in my_metric;
|
||||||
|
//
|
||||||
|
template<typename AttributeType>
|
||||||
|
class EventTimer {
|
||||||
|
public:
|
||||||
|
explicit EventTimer(EventMetric<AttributeType>* metric)
|
||||||
|
:start_time_(systemTime()), metric_(metric) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~EventTimer() {
|
||||||
|
if (metric_) {
|
||||||
|
metric_->Record(ns2us(systemTime() - start_time_), attribute_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the attribute to associate with this timing. E.g. this can be used to
|
||||||
|
// record the return code from the work that was timed.
|
||||||
|
void SetAttribute(const AttributeType& attribute) {
|
||||||
|
attribute_ = attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Visible for testing only.
|
||||||
|
nsecs_t start_time_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EventMetric<AttributeType>* metric_;
|
||||||
|
AttributeType attribute_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
#endif // ANDROID_EVENT_METRIC_H_
|
Loading…
Reference in new issue