blob: 018d110b12b6154e80c6ae36d3ee2fc4d76f17fe [file] [log] [blame]
* Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
#include "api/test/metrics/chrome_perf_dashboard_metrics_exporter.h"
#include <stdio.h>
#include <memory>
#include <string>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "api/test/metrics/metric.h"
#include "test/testsupport/file_utils.h"
#include "test/testsupport/perf_test_histogram_writer.h"
#include "test/testsupport/perf_test_result_writer.h"
namespace webrtc {
namespace test {
namespace {
std::string ToChromePerfDashboardUnit(Unit unit) {
switch (unit) {
case Unit::kMilliseconds:
return "msBestFitFormat";
case Unit::kPercent:
return "n%";
case Unit::kBytes:
return "sizeInBytes";
case Unit::kKilobitsPerSecond:
// Chrome Perf Dashboard doesn't have kpbs units, so we change the unit
// and value accordingly.
return "bytesPerSecond";
case Unit::kHertz:
return "Hz";
case Unit::kUnitless:
return "unitless";
case Unit::kCount:
return "count";
double ToChromePerfDashboardValue(double value, Unit unit) {
switch (unit) {
case Unit::kKilobitsPerSecond:
// Chrome Perf Dashboard doesn't have kpbs units, so we change the unit
// and value accordingly.
return value * 1000 / 8;
return value;
ImproveDirection ToChromePerfDashboardImproveDirection(
ImprovementDirection direction) {
switch (direction) {
case ImprovementDirection::kBiggerIsBetter:
return ImproveDirection::kBiggerIsBetter;
case ImprovementDirection::kNeitherIsBetter:
return ImproveDirection::kNone;
case ImprovementDirection::kSmallerIsBetter:
return ImproveDirection::kSmallerIsBetter;
bool WriteMetricsToFile(const std::string& path, const std::string& data) {
FILE* output = fopen(path.c_str(), "wb");
if (output == NULL) {
printf("Failed to write to %s.\n", path.c_str());
return false;
size_t written = fwrite(data.c_str(), sizeof(char), data.size(), output);
if (written != data.size()) {
size_t expected = data.size();
printf("Wrote %zu, tried to write %zu\n", written, expected);
return false;
return true;
bool IsEmpty(const Metric::Stats& stats) {
return !stats.mean.has_value() && !stats.stddev.has_value() &&
!stats.min.has_value() && !stats.max.has_value();
} // namespace
absl::string_view export_file_path)
: export_file_path_(export_file_path) {}
bool ChromePerfDashboardMetricsExporter::Export(
rtc::ArrayView<const Metric> metrics) {
std::unique_ptr<PerfTestResultWriter> writer =
for (const Metric& metric : metrics) {
if (metric.time_series.samples.empty() && IsEmpty(metric.stats)) {
// If there were no data collected for the metric it is expected that 0
// will be exported, so add 0 to the samples.
writer->LogResult(, metric.test_case,
ToChromePerfDashboardValue(0, metric.unit),
if (metric.time_series.samples.empty()) {
writer->LogResultMeanAndError(, metric.test_case,
ToChromePerfDashboardValue(*metric.stats.mean, metric.unit),
ToChromePerfDashboardValue(*metric.stats.stddev, metric.unit),
std::vector<double> samples(metric.time_series.samples.size());
for (size_t i = 0; i < metric.time_series.samples.size(); ++i) {
samples[i] = ToChromePerfDashboardValue(
metric.time_series.samples[i].value, metric.unit);
writer->LogResultList(, metric.test_case, samples,
return WriteMetricsToFile(export_file_path_, writer->Serialize());
} // namespace test
} // namespace webrtc