Add a function to report perf results in JSON format.
Add support to report perf results in the JSON format specified in [1].
[1] https://github.com/catapult-project/catapult/blob/master/dashboard/docs/data-format.md
Bug: webrtc:8566
Change-Id: I25f829a4b012b3e2a3d56d61582a674f780148d0
Reviewed-on: https://webrtc-review.googlesource.com/26031
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Edward Lemur <ehmaldonado@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20950}
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 9a50e1c..7eb896d 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -148,6 +148,7 @@
deps = [
"..:webrtc_common",
+ "../api:array_view",
"../common_video",
"../rtc_base:gtest_prod",
"../rtc_base:rtc_base_approved",
diff --git a/test/testsupport/perf_test.cc b/test/testsupport/perf_test.cc
index b7578d1..affd458 100644
--- a/test/testsupport/perf_test.cc
+++ b/test/testsupport/perf_test.cc
@@ -8,14 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-// A stripped-down version of Chromium's chrome/test/perf/perf_test.cc.
-// ResultsToString(), PrintResult(size_t value) and AppendResult(size_t value)
-// have been modified. The remainder are identical to the Chromium version.
-
#include "test/testsupport/perf_test.h"
+#include "rtc_base/criticalsection.h"
-#include <sstream>
#include <stdio.h>
+#include <map>
+#include <sstream>
#include <vector>
namespace {
@@ -36,21 +34,131 @@
values.c_str(), units.c_str());
}
+template <typename Container>
+void OutputListToStream(std::ostream* ostream, const Container& values) {
+ const char* sep = "";
+ for (const auto& v : values) {
+ (*ostream) << sep << v;
+ sep = ",";
+ }
+}
+
+class PerfResultsLogger {
+ public:
+ void ClearResults() {
+ rtc::CritScope lock(&crit_);
+ graphs_.clear();
+ }
+ void LogResult(const std::string& graph_name,
+ const std::string& trace_name,
+ const double value,
+ const std::string& units,
+ const bool important) {
+ std::ostringstream value_stream;
+ value_stream << value;
+ PrintResultsImpl(graph_name, trace_name, value_stream.str(), units,
+ important);
+
+ std::ostringstream json_stream;
+ json_stream << '"' << trace_name << R"(":{)";
+ json_stream << R"("type":"scalar",)";
+ json_stream << R"("value":)" << value << ',';
+ json_stream << R"("units":")" << units << R"("})";
+ rtc::CritScope lock(&crit_);
+ graphs_[graph_name].push_back(json_stream.str());
+ }
+ 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) {
+ std::ostringstream value_stream;
+ value_stream << '{' << mean << ',' << error << '}';
+ PrintResultsImpl(graph_name, trace_name, value_stream.str(), units,
+ important);
+
+ std::ostringstream json_stream;
+ json_stream << '"' << trace_name << R"(":{)";
+ json_stream << R"("type":"list_of_scalars",)";
+ json_stream << R"("values":[)" << mean << "],";
+ json_stream << R"("std":)" << error << ',';
+ json_stream << R"("units":")" << units << R"("})";
+ rtc::CritScope lock(&crit_);
+ graphs_[graph_name].push_back(json_stream.str());
+ }
+ 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) {
+ std::ostringstream value_stream;
+ value_stream << '[';
+ OutputListToStream(&value_stream, values);
+ value_stream << ']';
+ PrintResultsImpl(graph_name, trace_name, value_stream.str(), units,
+ important);
+
+ std::ostringstream json_stream;
+ json_stream << '"' << trace_name << R"(":{)";
+ json_stream << R"("type":"list_of_scalars",)";
+ json_stream << R"("values":)" << value_stream.str() << ',';
+ json_stream << R"("units":")" << units << R"("})";
+ rtc::CritScope lock(&crit_);
+ graphs_[graph_name].push_back(json_stream.str());
+ }
+ std::string ToJSON() const;
+
+ private:
+ rtc::CriticalSection crit_;
+ std::map<std::string, std::vector<std::string>> graphs_
+ RTC_GUARDED_BY(&crit_);
+};
+
+std::string PerfResultsLogger::ToJSON() const {
+ std::ostringstream json_stream;
+ json_stream << R"({"format_version":"1.0",)";
+ json_stream << R"("charts":{)";
+ rtc::CritScope lock(&crit_);
+ for (auto graphs_it = graphs_.begin(); graphs_it != graphs_.end();
+ ++graphs_it) {
+ if (graphs_it != graphs_.begin())
+ json_stream << ',';
+ json_stream << '"' << graphs_it->first << "\":";
+ json_stream << '{';
+ OutputListToStream(&json_stream, graphs_it->second);
+ json_stream << '}';
+ }
+ json_stream << "}}";
+ return json_stream.str();
+}
+
+PerfResultsLogger& GetPerfResultsLogger() {
+ static PerfResultsLogger* const logger_ = new PerfResultsLogger();
+ return *logger_;
+}
+
} // namespace
namespace webrtc {
namespace test {
+void ClearPerfResults() {
+ GetPerfResultsLogger().ClearResults();
+}
+
+std::string GetPerfResultsJSON() {
+ return GetPerfResultsLogger().ToJSON();
+}
+
void PrintResult(const std::string& measurement,
const std::string& modifier,
const std::string& trace,
const double value,
const std::string& units,
bool important) {
- std::ostringstream value_stream;
- value_stream << value;
- PrintResultsImpl(measurement + modifier, trace, value_stream.str(), units,
- important);
+ GetPerfResultsLogger().LogResult(measurement + modifier, trace, value, units,
+ important);
}
void PrintResultMeanAndError(const std::string& measurement,
@@ -60,32 +168,18 @@
const double error,
const std::string& units,
bool important) {
- std::ostringstream value_stream;
- value_stream << '{' << mean << ',' << error << '}';
- PrintResultsImpl(measurement + modifier, trace, value_stream.str(), units,
- important);
+ GetPerfResultsLogger().LogResultMeanAndError(measurement + modifier, trace,
+ mean, error, units, important);
}
void PrintResultList(const std::string& measurement,
const std::string& modifier,
const std::string& trace,
- const std::vector<double>& values,
+ const rtc::ArrayView<const double> values,
const std::string& units,
bool important) {
- std::ostringstream value_stream;
- value_stream << '[';
- if (!values.empty()) {
- auto it = values.begin();
- while (true) {
- value_stream << *it;
- if (++it == values.end())
- break;
- value_stream << ',';
- }
- }
- value_stream << ']';
- PrintResultsImpl(measurement + modifier, trace, value_stream.str(), units,
- important);
+ GetPerfResultsLogger().LogResultList(measurement + modifier, trace, values,
+ units, important);
}
} // namespace test
diff --git a/test/testsupport/perf_test.h b/test/testsupport/perf_test.h
index 31b7b13..1a72c04 100644
--- a/test/testsupport/perf_test.h
+++ b/test/testsupport/perf_test.h
@@ -8,16 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-// A stripped-down version of Chromium's chrome/test/perf/perf_test.h.
-// Several functions have been removed; the prototypes of the remainder have
-// not been changed.
-
#ifndef TEST_TESTSUPPORT_PERF_TEST_H_
#define TEST_TESTSUPPORT_PERF_TEST_H_
+#include "api/array_view.h"
+
#include <sstream>
#include <string>
-#include <vector>
namespace webrtc {
namespace test {
@@ -53,7 +50,6 @@
const std::string& units,
bool important);
-
// Like PrintResult(), but prints an entire list of results. The |values|
// will generally be a list of comma-separated numbers. A typical
// post-processing step might produce plots of their mean and standard
@@ -61,10 +57,17 @@
void PrintResultList(const std::string& measurement,
const std::string& modifier,
const std::string& trace,
- const std::vector<double>& values,
+ rtc::ArrayView<const double> values,
const std::string& units,
bool important);
+// Get all perf results to date in a JSON format as described in
+// https://github.com/catapult-project/catapult/blob/master/dashboard/docs/data-format.md
+std::string GetPerfResultsJSON();
+
+// You shouldn't use this function. It's only used to test the functions above.
+void ClearPerfResults();
+
} // namespace test
} // namespace webrtc
diff --git a/test/testsupport/perf_test_unittest.cc b/test/testsupport/perf_test_unittest.cc
index 5c0f543..f80bcf8 100644
--- a/test/testsupport/perf_test_unittest.cc
+++ b/test/testsupport/perf_test_unittest.cc
@@ -14,30 +14,97 @@
#include "test/gtest.h"
+namespace {
+
+const char* kJsonExpected = R"({
+ "format_version":"1.0",
+ "charts":{
+ "foobar":{
+ "baz_v":{
+ "type":"scalar",
+ "value":7,
+ "units":"widgets"
+ },
+ "baz_me":{
+ "type":"list_of_scalars",
+ "values":[1],
+ "std":2,
+ "units":"lemurs"
+ },
+ "baz_vl":{
+ "type":"list_of_scalars",
+ "values":[1,2,3],
+ "units":"units"
+ }
+ },
+ "measurementmodifier":{
+ "trace":{
+ "type":"scalar",
+ "value":42,
+ "units":"units"
+ }
+ }
+ }
+})";
+
+std::string RemoveSpaces(std::string s) {
+ s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
+ s.erase(std::remove(s.begin(), s.end(), '\n'), s.end());
+ return s;
+}
+
+} // namespace
+
namespace webrtc {
namespace test {
+class PerfTest : public ::testing::Test {
+ protected:
+ void TearDown() override {
+ ClearPerfResults();
+ }
+};
+
+
#if defined(WEBRTC_IOS)
-#define MAYBE_AppendResult DISABLED_AppendResult
+#define MAYBE_TestPrintResult DISABLED_TestPrintResult
#else
-#define MAYBE_AppendResult AppendResult
+#define MAYBE_TestPrintResult TestPrintResult
#endif
-TEST(PerfTest, MAYBE_AppendResult) {
+TEST_F(PerfTest, MAYBE_TestPrintResult) {
testing::internal::CaptureStdout();
- std::string expected = "RESULT measurementmodifier: trace= 42 units\n";
+ std::string expected;
+
+ expected += "RESULT measurementmodifier: trace= 42 units\n";
PrintResult("measurement", "modifier", "trace", 42, "units", false);
- expected += "*RESULT foobar: baz= 7 widgets\n";
- PrintResult("foo", "bar", "baz", 7, "widgets", true);
+ expected += "*RESULT foobar: baz_v= 7 widgets\n";
+ PrintResult("foo", "bar", "baz_v", 7, "widgets", true);
- expected += "RESULT foobar: baz= {1,2} lemurs\n";
- PrintResultMeanAndError("foo", "bar", "baz", 1, 2, "lemurs", false);
+ expected += "RESULT foobar: baz_me= {1,2} lemurs\n";
+ PrintResultMeanAndError("foo", "bar", "baz_me", 1, 2, "lemurs", false);
- expected += "RESULT foobar: baz= [1,2,3] units\n";
- PrintResultList("foo", "bar", "baz", {1, 2, 3}, "units", false);
+ const double kListOfScalars[] = {1, 2, 3};
+ expected += "RESULT foobar: baz_vl= [1,2,3] units\n";
+ PrintResultList("foo", "bar", "baz_vl", kListOfScalars, "units", false);
- std::string output = testing::internal::GetCapturedStdout();
- EXPECT_EQ(expected, output);
+ EXPECT_EQ(expected, testing::internal::GetCapturedStdout());
+}
+
+TEST_F(PerfTest, TestGetPerfResultsJSON) {
+ PrintResult("measurement", "modifier", "trace", 42, "units", false);
+ PrintResult("foo", "bar", "baz_v", 7, "widgets", true);
+ PrintResultMeanAndError("foo", "bar", "baz_me", 1, 2, "lemurs", false);
+ const double kListOfScalars[] = {1, 2, 3};
+ PrintResultList("foo", "bar", "baz_vl", kListOfScalars, "units", false);
+
+ EXPECT_EQ(RemoveSpaces(kJsonExpected), GetPerfResultsJSON());
+}
+
+TEST_F(PerfTest, TestClearPerfResults) {
+ PrintResult("measurement", "modifier", "trace", 42, "units", false);
+ ClearPerfResults();
+ EXPECT_EQ(R"({"format_version":"1.0","charts":{}})", GetPerfResultsJSON());
}
} // namespace test