Files
android/libwvdrmengine/tools/metrics_dump/src/mediadrm_metrics.cpp
Rahul Frias 8723859570 Add metrics_dump, a tool to format drm metrics
[ Merge of http://go/wvgerrit/59022 ]

Android metrics are output by the adb shell command
|dumpsys media.metrics|. They appear in bugreports
and can also be requested interactively. Both the
widevine and framework mediadrm metrics are base64
encoded protobufs detailing each of the metrics
items. This tool prints them in a readable format.

Test: wv android unit/integration tests
Change-Id: Id1bc05b34693a3ca44dd3872a28a2337b3ce4d79
2019-11-21 15:39:30 -08:00

174 lines
5.8 KiB
C++

// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Format mediadrm framework protobuf metrics
#include <fstream>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include "mediadrm_metrics.pb.h"
namespace mediadrm_metrics {
using namespace android::drm_metrics;
using std::string;
using std::to_string;
const string kIndentPerLine = " ";
string FormatAttributes(const DrmFrameworkMetrics::Attributes& attributes) {
string result;
if (attributes.has_error_code()) {
result.append("error_code:");
result.append(to_string(attributes.error_code()));
}
if (attributes.has_key_status_type()) {
if (result.size()) result.append(",");
result.append("key_status_type:");
result.append(to_string(attributes.key_status_type()));
}
if (attributes.has_event_type()) {
if (result.size()) result.append(",");
result.append("event_type:");
result.append(to_string(attributes.event_type()));
}
if (result.size()) {
return string(" {") + result + "}";
} else {
return "";
}
}
string FormatCounter(const DrmFrameworkMetrics::Counter& cm) {
string result;
if (cm.has_count()) {
result = string("count=") + to_string(cm.count());
if (cm.has_attributes()) {
result.append(FormatAttributes(cm.attributes()));
}
}
return result;
}
string FormatDistributionMetric(
const DrmFrameworkMetrics::DistributionMetric& dm) {
string result;
if (dm.has_operation_count()) {
if (dm.operation_count() == 1) {
if (dm.has_mean()) {
std::ostringstream buffer;
buffer << dm.mean();
result += string("mean=") + buffer.str();
}
} else {
if (dm.has_min()) {
std::ostringstream buffer;
buffer << dm.min();
result = string("min=") + buffer.str();
}
if (dm.has_max()) {
std::ostringstream buffer;
buffer << dm.max();
if (result.size()) result.append(" ");
result += string("max=") + buffer.str();
}
if (dm.has_mean()) {
std::ostringstream buffer;
buffer << dm.mean();
if (result.size()) result.append(" ");
result += string("mean=") + buffer.str();
}
if (dm.has_variance()) {
std::ostringstream buffer;
buffer << dm.variance();
if (result.size()) result.append(" ");
result += string("variance=") + buffer.str();
}
if (dm.has_operation_count()) {
if (result.size()) result.append(" ");
result += string("count=") + to_string(dm.operation_count());
}
}
if (dm.has_attributes()) {
result.append(FormatAttributes(dm.attributes()));
}
}
return result;
}
#define FORMAT_REPEATED_DISTRIBUTION(NAME, INDENT) \
if (metrics.NAME##_size() == 1) { \
result.append(INDENT + #NAME + ": "); \
result.append(FormatDistributionMetric(metrics.NAME(0)) + "\n"); \
} else { \
for (int i = 0; i < metrics.NAME##_size(); i++) { \
result.append(INDENT + #NAME "[" + to_string(i) + "]: "); \
result.append(FormatDistributionMetric(metrics.NAME(i)) + "\n"); \
} \
}
#define FORMAT_REPEATED_COUNTER(NAME, INDENT) \
if (metrics.NAME##_size() == 1) { \
result.append(INDENT + #NAME ": "); \
result.append(FormatCounter(metrics.NAME(0)) + "\n"); \
} else { \
for (int i = 0; i < metrics.NAME##_size(); i++) { \
result.append(INDENT + #NAME "[" + to_string(i) + "]: "); \
result.append(FormatCounter(metrics.NAME(i)) + "\n"); \
} \
}
uint8_t hex2bin(char c) { return isdigit(c) ? c - '0' : tolower(c) - 'a' + 10; }
string hexdecode(string encoded) {
string result;
for (size_t i = 0; i < encoded.size(); i += 2) {
char c = hex2bin(encoded[i]) << 4 | hex2bin(encoded[i + 1]);
result += c;
}
return result;
}
string ms_to_seconds(uint64_t time_ms) {
uint64_t time_s = time_ms / 1000;
uint64_t ms = time_ms - time_s * 1000;
return to_string(time_s) + "." + to_string(ms);
}
void FormatDrmFrameworkMetrics(const DrmFrameworkMetrics& metrics,
string& result) {
string indent = kIndentPerLine;
result.append("mediadrm_metrics\n");
FORMAT_REPEATED_COUNTER(open_session_counter, indent);
FORMAT_REPEATED_COUNTER(close_session_counter, indent);
FORMAT_REPEATED_DISTRIBUTION(get_key_request_time_us, indent);
FORMAT_REPEATED_DISTRIBUTION(provide_key_response_time_us, indent);
FORMAT_REPEATED_COUNTER(get_provisioning_request_counter, indent);
FORMAT_REPEATED_COUNTER(provide_provisioning_response_counter, indent);
FORMAT_REPEATED_COUNTER(key_status_change_counter, indent);
FORMAT_REPEATED_COUNTER(event_callback_counter, indent);
FORMAT_REPEATED_COUNTER(get_device_unique_id_counter, indent);
size_t i = 0;
for (auto const& entry : metrics.session_lifetimes()) {
DrmFrameworkMetrics_SessionLifetime lifetime = entry.second;
if (lifetime.has_start_time_ms() && lifetime.has_end_time_ms()) {
result += indent + "session[" + to_string(++i) + "]: \"" +
hexdecode(entry.first) + "\"";
result +=
string(" start: ") + ms_to_seconds(lifetime.start_time_ms()) + " sec";
result += string(" duration: ") +
to_string(lifetime.end_time_ms() - lifetime.start_time_ms()) +
" ms\n";
}
}
}
}; // namespace mediadrm_metrics