Implement histogram perf results writer.
This will be used by WebRTC tests. It converts results exactly the
same as our downstream implementation (histogram_util).
This implementation should be pretty feature complete, or at least
enough to start testing the end-to-end flow. I will set up some
experimental recipe code and see if this actually makes it into the
dashboard.
Note: needs some catapult changes to land first and be rolled
into Chromium, and then WebRTC.
Bug: chromium:1029452
Change-Id: I939046929652fc27b8fcb18af54bde22886d9228
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/166172
Commit-Queue: Patrik Höglund <phoglund@webrtc.org>
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30436}
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 464f44f..4617dd0 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -226,7 +226,6 @@
"testsupport/perf_test.h",
"testsupport/perf_test_graphjson_writer.cc",
"testsupport/perf_test_graphjson_writer.h",
- "testsupport/perf_test_histogram_writer.cc",
"testsupport/perf_test_histogram_writer.h",
"testsupport/perf_test_result_writer.h",
]
@@ -234,9 +233,19 @@
"../api:array_view",
"../rtc_base:checks",
"../rtc_base:criticalsection",
+ "../rtc_base:logging",
"../rtc_base:rtc_numerics",
"//third_party/abseil-cpp/absl/flags:flag",
]
+ if (rtc_enable_protobuf) {
+ sources += [ "testsupport/perf_test_histogram_writer.cc" ]
+ deps += [
+ "//third_party/catapult/tracing/tracing:histogram",
+ "//third_party/catapult/tracing/tracing:reserved_infos",
+ ]
+ } else {
+ sources += [ "testsupport/perf_test_histogram_writer_no_protobuf.cc" ]
+ }
}
if (is_ios) {
@@ -502,6 +511,11 @@
"testsupport/yuv_frame_writer_unittest.cc",
]
+ if (rtc_enable_protobuf) {
+ sources += [ "testsupport/perf_test_histogram_writer_unittest.cc" ]
+ deps += [ "//third_party/catapult/tracing/tracing:histogram" ]
+ }
+
data = test_support_unittests_resources
if (is_android) {
deps += [ "//testing/android/native_test:native_test_support" ]
diff --git a/test/testsupport/DEPS b/test/testsupport/DEPS
new file mode 100644
index 0000000..6f6150a
--- /dev/null
+++ b/test/testsupport/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ # Histogram C++ API, used by perf tests.
+ "+third_party/catapult/tracing/tracing/value"
+]
diff --git a/test/testsupport/perf_test.cc b/test/testsupport/perf_test.cc
index eedb0c8..ae9ce6e 100644
--- a/test/testsupport/perf_test.cc
+++ b/test/testsupport/perf_test.cc
@@ -17,7 +17,6 @@
#include <sstream>
#include <vector>
-#include "absl/flags/flag.h"
#include "rtc_base/checks.h"
#include "rtc_base/critical_section.h"
#include "test/testsupport/perf_test_graphjson_writer.h"
@@ -213,8 +212,8 @@
GetResultsLinePrinter().SetOutput(output);
}
-std::string GetPerfResultsJSON() {
- return GetPerfWriter().ToJSON();
+std::string GetPerfResults() {
+ return GetPerfWriter().Serialize();
}
void PrintPlottableResults(const std::vector<std::string>& desired_graphs) {
@@ -222,10 +221,10 @@
}
void WritePerfResults(const std::string& output_path) {
- std::string json_results = GetPerfResultsJSON();
- std::fstream json_file(output_path, std::fstream::out);
- json_file << json_results;
- json_file.close();
+ std::string results = GetPerfResults();
+ std::fstream output(output_path, std::fstream::out);
+ output << results;
+ output.close();
}
void PrintResult(const std::string& measurement,
diff --git a/test/testsupport/perf_test.h b/test/testsupport/perf_test.h
index 0550e44..53de669 100644
--- a/test/testsupport/perf_test.h
+++ b/test/testsupport/perf_test.h
@@ -15,6 +15,7 @@
#include <string>
#include <vector>
+#include "absl/flags/flag.h"
#include "api/array_view.h"
#include "rtc_base/numerics/samples_stats_counter.h"
@@ -88,9 +89,13 @@
const bool important,
ImproveDirection improve_direction = ImproveDirection::kNone);
-// Returns all perf results to date in a JSON string formatted as described in
-// https://github.com/catapult-project/catapult/blob/master/dashboard/docs/data-format.md
-std::string GetPerfResultsJSON();
+// If --write_histogram_proto_json=false, this returns all perf results to date
+// in a JSON string formatted as described in dashboard/docs/data-format.md
+// in https://github.com/catapult-project/catapult/blob/master/. If
+// --write_histogram_proto_json=true, returns a string-encoded proto as
+// described in tracing/tracing/proto/histogram.proto in
+// https://github.com/catapult-project/catapult/blob/master/.
+std::string GetPerfResults();
// Print into stdout plottable metrics for further post processing.
// |desired_graphs| - list of metrics, that should be plotted. If empty - all
@@ -98,18 +103,20 @@
// they will be skipped.
void PrintPlottableResults(const std::vector<std::string>& desired_graphs);
-// Writes the JSON representation of the perf results returned by
-// GetPerfResultsJSON() to the file in output_path.
+// Call GetPerfResults() and write its output to a file.
void WritePerfResults(const std::string& output_path);
// By default, perf results are printed to stdout. Set the FILE* to where they
// should be printing instead.
void SetPerfResultsOutput(FILE* output);
-// You shouldn't use this function. It's only used to test the functions above.
+// Only for use by tests.
void ClearPerfResults();
} // namespace test
} // namespace webrtc
+// Only for use by tests.
+ABSL_DECLARE_FLAG(bool, write_histogram_proto_json);
+
#endif // TEST_TESTSUPPORT_PERF_TEST_H_
diff --git a/test/testsupport/perf_test_graphjson_writer.cc b/test/testsupport/perf_test_graphjson_writer.cc
index 5a8ee64..cf49b29 100644
--- a/test/testsupport/perf_test_graphjson_writer.cc
+++ b/test/testsupport/perf_test_graphjson_writer.cc
@@ -110,7 +110,7 @@
graphs_[graph_name].push_back(json_stream.str());
}
- std::string ToJSON() const {
+ std::string Serialize() const {
std::ostringstream json_stream;
json_stream << R"({"format_version":"1.0",)";
json_stream << R"("charts":{)";
diff --git a/test/testsupport/perf_test_histogram_writer.cc b/test/testsupport/perf_test_histogram_writer.cc
index d82294b..523834b 100644
--- a/test/testsupport/perf_test_histogram_writer.cc
+++ b/test/testsupport/perf_test_histogram_writer.cc
@@ -13,15 +13,180 @@
#include <stdlib.h>
#include <map>
+#include <memory>
+
+#include "rtc_base/critical_section.h"
+#include "rtc_base/logging.h"
+#include "third_party/catapult/tracing/tracing/value/diagnostics/reserved_infos.h"
+#include "third_party/catapult/tracing/tracing/value/histogram.h"
namespace webrtc {
namespace test {
-namespace {} // namespace
+namespace {
+
+namespace proto = catapult::tracing::tracing::proto;
+
+std::string AsJsonString(const std::string string) {
+ return "\"" + string + "\"";
+}
+
+class PerfTestHistogramWriter : public PerfTestResultWriter {
+ public:
+ PerfTestHistogramWriter() : crit_() {}
+ void ClearResults() override {
+ rtc::CritScope lock(&crit_);
+ histograms_.clear();
+ }
+
+ void LogResult(const std::string& graph_name,
+ const std::string& trace_name,
+ const double value,
+ const std::string& units,
+ const bool important,
+ ImproveDirection improve_direction) override {
+ (void)important;
+ AddSample(graph_name, trace_name, value, units, improve_direction);
+ }
+ void LogResultMeanAndError(const std::string& graph_name,
+ const std::string& trace_name,
+ const double mean,
+ const double error,
+ const std::string& units,
+ const bool important,
+ ImproveDirection improve_direction) override {
+ RTC_LOG(LS_WARNING) << "Discarding stddev, not supported by histograms";
+ (void)error;
+ (void)important;
+
+ AddSample(graph_name, trace_name, mean, units, improve_direction);
+ }
+ void LogResultList(const std::string& graph_name,
+ const std::string& trace_name,
+ const rtc::ArrayView<const double> values,
+ const std::string& units,
+ const bool important,
+ ImproveDirection improve_direction) override {
+ (void)important;
+ for (double value : values) {
+ AddSample(graph_name, trace_name, value, units, improve_direction);
+ }
+ }
+ std::string Serialize() const override {
+ proto::HistogramSet histogram_set;
+
+ rtc::CritScope lock(&crit_);
+ for (const auto& histogram : histograms_) {
+ std::unique_ptr<proto::Histogram> proto = histogram.second->toProto();
+ histogram_set.mutable_histograms()->AddAllocated(proto.release());
+ }
+
+ std::string output;
+ bool ok = histogram_set.SerializeToString(&output);
+ RTC_DCHECK(ok) << "Failed to serialize histogram set to string";
+ return output;
+ }
+
+ private:
+ void AddSample(const std::string& original_graph_name,
+ const std::string& trace_name,
+ const double value,
+ const std::string& units,
+ ImproveDirection improve_direction) {
+ // WebRTC annotates the units into the metric name when they are not
+ // supported by the Histogram API.
+ std::string graph_name = original_graph_name;
+ if (units == "dB") {
+ graph_name += "_dB";
+ } else if (units == "fps") {
+ graph_name += "_fps";
+ } else if (units == "%") {
+ graph_name += "_%";
+ }
+
+ // Lookup on graph name + trace name (or measurement + story in catapult
+ // parlance). There should be several histograms with the same measurement
+ // if they're for different stories.
+ std::string measurement_and_story = graph_name + trace_name;
+ rtc::CritScope lock(&crit_);
+ if (histograms_.count(measurement_and_story) == 0) {
+ proto::UnitAndDirection unit = ParseUnit(units, improve_direction);
+ std::unique_ptr<catapult::HistogramBuilder> builder =
+ std::make_unique<catapult::HistogramBuilder>(graph_name, unit);
+ histograms_[measurement_and_story] = std::move(builder);
+
+ proto::Diagnostic stories;
+ proto::GenericSet* generic_set = stories.mutable_generic_set();
+ generic_set->add_values(AsJsonString(trace_name));
+ histograms_[measurement_and_story]->AddDiagnostic(
+ catapult::kStoriesDiagnostic, stories);
+ }
+
+ if (units == "bps") {
+ // Bps has been interpreted as bits per second in WebRTC tests.
+ histograms_[measurement_and_story]->AddSample(value / 8);
+ } else {
+ histograms_[measurement_and_story]->AddSample(value);
+ }
+ }
+
+ proto::UnitAndDirection ParseUnit(const std::string& units,
+ ImproveDirection improve_direction) {
+ RTC_DCHECK(units.find('_') == std::string::npos)
+ << "The unit_bigger|smallerIsBetter syntax isn't supported in WebRTC, "
+ "use the enum instead.";
+
+ proto::UnitAndDirection result;
+ result.set_improvement_direction(ParseDirection(improve_direction));
+ if (units == "bps") {
+ result.set_unit(proto::BYTES_PER_SECOND);
+ } else if (units == "dB") {
+ result.set_unit(proto::UNITLESS);
+ } else if (units == "fps") {
+ result.set_unit(proto::HERTZ);
+ } else if (units == "frames") {
+ result.set_unit(proto::COUNT);
+ } else if (units == "ms") {
+ result.set_unit(proto::MS_BEST_FIT_FORMAT);
+ } else if (units == "%") {
+ result.set_unit(proto::UNITLESS);
+ } else {
+ proto::Unit unit = catapult::UnitFromJsonUnit(units);
+
+ // UnitFromJsonUnit returns UNITLESS if it doesn't recognize the unit.
+ if (unit == proto::UNITLESS && units != "unitless") {
+ RTC_LOG(LS_WARNING) << "Unit " << units << " is unsupported.";
+ }
+
+ result.set_unit(unit);
+ }
+ return result;
+ }
+
+ proto::ImprovementDirection ParseDirection(
+ ImproveDirection improve_direction) {
+ switch (improve_direction) {
+ case ImproveDirection::kNone:
+ return proto::NOT_SPECIFIED;
+ case ImproveDirection::kSmallerIsBetter:
+ return proto::SMALLER_IS_BETTER;
+ case ImproveDirection::kBiggerIsBetter:
+ return proto::BIGGER_IS_BETTER;
+ default:
+ RTC_NOTREACHED() << "Invalid enum value " << improve_direction;
+ }
+ }
+
+ private:
+ rtc::CriticalSection crit_;
+ std::map<std::string, std::unique_ptr<catapult::HistogramBuilder>> histograms_
+ RTC_GUARDED_BY(&crit_);
+};
+
+} // namespace
PerfTestResultWriter* CreateHistogramWriter() {
- RTC_CHECK(false) << "Not implemented";
- return nullptr;
+ return new PerfTestHistogramWriter();
}
} // namespace test
diff --git a/test/testsupport/perf_test_histogram_writer_no_protobuf.cc b/test/testsupport/perf_test_histogram_writer_no_protobuf.cc
new file mode 100644
index 0000000..17685cc
--- /dev/null
+++ b/test/testsupport/perf_test_histogram_writer_no_protobuf.cc
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020 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 "test/testsupport/perf_test_histogram_writer.h"
+
+namespace webrtc {
+namespace test {
+
+PerfTestResultWriter* CreateHistogramWriter() {
+ RTC_NOTREACHED() << "Cannot run perf tests with rtc_enable_protobuf = false. "
+ "Perf write results as protobufs.";
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/test/testsupport/perf_test_histogram_writer_unittest.cc b/test/testsupport/perf_test_histogram_writer_unittest.cc
new file mode 100644
index 0000000..6b083d6
--- /dev/null
+++ b/test/testsupport/perf_test_histogram_writer_unittest.cc
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2020 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 "test/testsupport/perf_test_histogram_writer.h"
+
+#include <memory>
+#include <string>
+
+#include "test/gtest.h"
+#include "third_party/catapult/tracing/tracing/value/histogram.h"
+
+namespace webrtc {
+namespace test {
+
+namespace proto = catapult::tracing::tracing::proto;
+
+TEST(PerfHistogramWriterUnittest, TestSimpleHistogram) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ std::unique_ptr<PerfTestResultWriter>(CreateHistogramWriter());
+
+ writer->LogResult("-", "-", 0, "ms", false, ImproveDirection::kNone);
+
+ proto::HistogramSet histogram_set;
+ EXPECT_TRUE(histogram_set.ParseFromString(writer->Serialize()))
+ << "Expected valid histogram set";
+
+ ASSERT_EQ(histogram_set.histograms_size(), 1);
+}
+
+TEST(PerfHistogramWriterUnittest, WritesSamplesAndUserStory) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ std::unique_ptr<PerfTestResultWriter>(CreateHistogramWriter());
+
+ writer->LogResult("measurement", "user_story", 15e7, "Hz", false,
+ ImproveDirection::kBiggerIsBetter);
+
+ proto::HistogramSet histogram_set;
+ histogram_set.ParseFromString(writer->Serialize());
+ const proto::Histogram& hist1 = histogram_set.histograms(0);
+
+ EXPECT_EQ(hist1.name(), "measurement");
+
+ EXPECT_EQ(hist1.unit().unit(), proto::HERTZ);
+ EXPECT_EQ(hist1.unit().improvement_direction(), proto::BIGGER_IS_BETTER);
+
+ EXPECT_EQ(hist1.sample_values_size(), 1);
+ EXPECT_EQ(hist1.sample_values(0), 15e7);
+
+ EXPECT_EQ(hist1.diagnostics().diagnostic_map().count("stories"), 1u);
+ const proto::Diagnostic& stories =
+ hist1.diagnostics().diagnostic_map().at("stories");
+ ASSERT_EQ(stories.generic_set().values_size(), 1);
+ EXPECT_EQ(stories.generic_set().values(0), "\"user_story\"");
+}
+
+TEST(PerfHistogramWriterUnittest, WritesOneHistogramPerMeasurementAndStory) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ std::unique_ptr<PerfTestResultWriter>(CreateHistogramWriter());
+
+ writer->LogResult("measurement", "story1", 1, "ms", false,
+ ImproveDirection::kNone);
+ writer->LogResult("measurement", "story1", 2, "ms", false,
+ ImproveDirection::kNone);
+ writer->LogResult("measurement", "story2", 2, "ms", false,
+ ImproveDirection::kNone);
+
+ proto::HistogramSet histogram_set;
+ histogram_set.ParseFromString(writer->Serialize());
+ ASSERT_EQ(histogram_set.histograms_size(), 2);
+
+ const proto::Histogram& hist1 = histogram_set.histograms(0);
+ const proto::Histogram& hist2 = histogram_set.histograms(1);
+
+ EXPECT_EQ(hist1.name(), "measurement");
+ EXPECT_EQ(hist2.name(), "measurement");
+
+ const proto::Diagnostic& stories1 =
+ hist1.diagnostics().diagnostic_map().at("stories");
+ EXPECT_EQ(stories1.generic_set().values(0), "\"story1\"");
+ EXPECT_EQ(hist1.sample_values_size(), 2);
+
+ const proto::Diagnostic& stories2 =
+ hist2.diagnostics().diagnostic_map().at("stories");
+ EXPECT_EQ(stories2.generic_set().values(0), "\"story2\"");
+ EXPECT_EQ(hist2.sample_values_size(), 1);
+}
+
+TEST(PerfHistogramWriterUnittest, IgnoresError) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ std::unique_ptr<PerfTestResultWriter>(CreateHistogramWriter());
+
+ writer->LogResultMeanAndError("-", "-", 17, 12345, "ms", false,
+ ImproveDirection::kNone);
+
+ proto::HistogramSet histogram_set;
+ histogram_set.ParseFromString(writer->Serialize());
+ const proto::Histogram& hist1 = histogram_set.histograms(0);
+
+ EXPECT_EQ(hist1.running().mean(), 17);
+ EXPECT_EQ(hist1.running().variance(), 0) << "The error should be ignored.";
+}
+
+TEST(PerfHistogramWriterUnittest, WritesDecibelIntoMeasurementName) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ std::unique_ptr<PerfTestResultWriter>(CreateHistogramWriter());
+
+ writer->LogResult("measurement", "-", 0, "dB", false,
+ ImproveDirection::kNone);
+
+ proto::HistogramSet histogram_set;
+ histogram_set.ParseFromString(writer->Serialize());
+ const proto::Histogram& hist1 = histogram_set.histograms(0);
+
+ EXPECT_EQ(hist1.unit().unit(), proto::UNITLESS)
+ << "dB should map to unitless";
+ EXPECT_EQ(hist1.name(), "measurement_dB") << "measurement should be renamed";
+}
+
+TEST(PerfHistogramWriterUnittest, WritesFpsIntoMeasurementName) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ std::unique_ptr<PerfTestResultWriter>(CreateHistogramWriter());
+
+ writer->LogResult("measurement", "-", 0, "fps", false,
+ ImproveDirection::kNone);
+
+ proto::HistogramSet histogram_set;
+ histogram_set.ParseFromString(writer->Serialize());
+ const proto::Histogram& hist1 = histogram_set.histograms(0);
+
+ EXPECT_EQ(hist1.unit().unit(), proto::HERTZ) << "fps should map to hertz";
+ EXPECT_EQ(hist1.name(), "measurement_fps") << "measurement should be renamed";
+}
+
+TEST(PerfHistogramWriterUnittest, WritesPercentIntoMeasurementName) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ std::unique_ptr<PerfTestResultWriter>(CreateHistogramWriter());
+
+ writer->LogResult("measurement", "-", 0, "%", false, ImproveDirection::kNone);
+
+ proto::HistogramSet histogram_set;
+ histogram_set.ParseFromString(writer->Serialize());
+ const proto::Histogram& hist1 = histogram_set.histograms(0);
+
+ EXPECT_EQ(hist1.unit().unit(), proto::UNITLESS)
+ << "percent should map to hertz";
+ EXPECT_EQ(hist1.name(), "measurement_%") << "measurement should be renamed";
+}
+
+TEST(PerfHistogramWriterUnittest, BitsPerSecondIsConvertedToBytes) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ std::unique_ptr<PerfTestResultWriter>(CreateHistogramWriter());
+
+ writer->LogResult("-", "-", 1024, "bps", false, ImproveDirection::kNone);
+
+ proto::HistogramSet histogram_set;
+ histogram_set.ParseFromString(writer->Serialize());
+ const proto::Histogram& hist1 = histogram_set.histograms(0);
+
+ EXPECT_EQ(hist1.sample_values(0), 128) << "1024 bits = 128 bytes";
+}
+
+TEST(PerfHistogramWriterUnittest, ParsesDirection) {
+ std::unique_ptr<PerfTestResultWriter> writer =
+ std::unique_ptr<PerfTestResultWriter>(CreateHistogramWriter());
+
+ writer->LogResult("measurement1", "-", 0, "bps", false,
+ ImproveDirection::kBiggerIsBetter);
+ writer->LogResult("measurement2", "-", 0, "frames", false,
+ ImproveDirection::kSmallerIsBetter);
+ writer->LogResult("measurement3", "-", 0, "sigma", false,
+ ImproveDirection::kNone);
+
+ proto::HistogramSet histogram_set;
+ histogram_set.ParseFromString(writer->Serialize());
+ const proto::Histogram& hist1 = histogram_set.histograms(0);
+ const proto::Histogram& hist2 = histogram_set.histograms(1);
+ const proto::Histogram& hist3 = histogram_set.histograms(2);
+
+ EXPECT_EQ(hist1.unit().unit(), proto::BYTES_PER_SECOND);
+ EXPECT_EQ(hist1.unit().improvement_direction(), proto::BIGGER_IS_BETTER);
+
+ EXPECT_EQ(hist2.unit().unit(), proto::COUNT);
+ EXPECT_EQ(hist2.unit().improvement_direction(), proto::SMALLER_IS_BETTER);
+
+ EXPECT_EQ(hist3.unit().unit(), proto::SIGMA);
+ EXPECT_EQ(hist3.unit().improvement_direction(), proto::NOT_SPECIFIED);
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/test/testsupport/perf_test_result_writer.h b/test/testsupport/perf_test_result_writer.h
index 5e932ba..d5d7011 100644
--- a/test/testsupport/perf_test_result_writer.h
+++ b/test/testsupport/perf_test_result_writer.h
@@ -47,7 +47,7 @@
const bool important,
webrtc::test::ImproveDirection improve_direction) = 0;
- virtual std::string ToJSON() const = 0;
+ virtual std::string Serialize() const = 0;
};
} // namespace test
diff --git a/test/testsupport/perf_test_unittest.cc b/test/testsupport/perf_test_unittest.cc
index 8202471..1004c64 100644
--- a/test/testsupport/perf_test_unittest.cc
+++ b/test/testsupport/perf_test_unittest.cc
@@ -17,6 +17,11 @@
#include "test/gtest.h"
#include "test/testsupport/rtc_expect_death.h"
+#if WEBRTC_ENABLE_PROTOBUF
+#include "third_party/catapult/tracing/tracing/value/histogram.h"
+namespace proto = catapult::tracing::tracing::proto;
+#endif
+
namespace {
const char* kJsonExpected = R"({
@@ -98,15 +103,72 @@
const double kListOfScalars[] = {1, 2, 3};
PrintResultList("foo", "bar", "baz_vl", kListOfScalars, "units", false);
- EXPECT_EQ(RemoveSpaces(kJsonExpected), GetPerfResultsJSON());
+ EXPECT_EQ(RemoveSpaces(kJsonExpected), GetPerfResults());
}
TEST_F(PerfTest, TestClearPerfResults) {
PrintResult("measurement", "modifier", "trace", 42, "units", false);
ClearPerfResults();
- EXPECT_EQ(R"({"format_version":"1.0","charts":{}})", GetPerfResultsJSON());
+ EXPECT_EQ(R"({"format_version":"1.0","charts":{}})", GetPerfResults());
}
+#if WEBRTC_ENABLE_PROTOBUF
+
+TEST_F(PerfTest, TestGetPerfResultsHistograms) {
+ bool original_flag = absl::GetFlag(FLAGS_write_histogram_proto_json);
+ absl::SetFlag(&FLAGS_write_histogram_proto_json, true);
+ PrintResult("measurement", "_modifier", "story_1", 42, "ms", false);
+ PrintResult("foo", "bar", "story_1", 7, "sigma", true);
+ // Note: the error will be ignored, not supported by histograms.
+ PrintResultMeanAndError("foo", "bar", "story_1", 1, 2000, "sigma", false);
+ const double kListOfScalars[] = {1, 2, 3};
+ PrintResultList("foo", "bar", "story_1", kListOfScalars, "sigma", false);
+
+ proto::HistogramSet histogram_set;
+ EXPECT_TRUE(histogram_set.ParseFromString(GetPerfResults()))
+ << "Expected valid histogram set";
+
+ ASSERT_EQ(histogram_set.histograms_size(), 2)
+ << "Should be two histograms: foobar and measurement_modifier";
+ const proto::Histogram& hist1 = histogram_set.histograms(0);
+ const proto::Histogram& hist2 = histogram_set.histograms(1);
+
+ EXPECT_EQ(hist1.name(), "foobar");
+
+ // Spot check some things in here (there's a more thorough test on the
+ // histogram writer itself).
+ EXPECT_EQ(hist1.unit().unit(), proto::SIGMA);
+ EXPECT_EQ(hist1.sample_values_size(), 5);
+ EXPECT_EQ(hist1.sample_values(0), 7);
+ EXPECT_EQ(hist1.sample_values(1), 1);
+ EXPECT_EQ(hist1.sample_values(2), 1);
+ EXPECT_EQ(hist1.sample_values(3), 2);
+ EXPECT_EQ(hist1.sample_values(4), 3);
+
+ EXPECT_EQ(hist1.diagnostics().diagnostic_map().count("stories"), 1u);
+ const proto::Diagnostic& stories =
+ hist1.diagnostics().diagnostic_map().at("stories");
+ ASSERT_EQ(stories.generic_set().values_size(), 1);
+ EXPECT_EQ(stories.generic_set().values(0), "\"story_1\"");
+
+ EXPECT_EQ(hist2.name(), "measurement_modifier");
+ EXPECT_EQ(hist2.unit().unit(), proto::MS_BEST_FIT_FORMAT);
+
+ absl::SetFlag(&FLAGS_write_histogram_proto_json, original_flag);
+}
+
+TEST_F(PerfTest, TestClearPerfResultsHistograms) {
+ bool original_flag = absl::GetFlag(FLAGS_write_histogram_proto_json);
+ absl::SetFlag(&FLAGS_write_histogram_proto_json, true);
+ PrintResult("measurement", "modifier", "trace", 42, "ms", false);
+ ClearPerfResults();
+ EXPECT_EQ("", GetPerfResults());
+
+ absl::SetFlag(&FLAGS_write_histogram_proto_json, original_flag);
+}
+
+#endif // WEBRTC_ENABLE_PROTOBUF
+
#if GTEST_HAS_DEATH_TEST
using PerfDeathTest = PerfTest;