diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/libwebrtc/test/testsupport/perf_test.cc | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/testsupport/perf_test.cc b/third_party/libwebrtc/test/testsupport/perf_test.cc new file mode 100644 index 0000000000..bbea5f841a --- /dev/null +++ b/third_party/libwebrtc/test/testsupport/perf_test.cc @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2012 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.h" + +#include <stdio.h> + +#include <algorithm> +#include <fstream> +#include <set> +#include <sstream> +#include <vector> + +#include "absl/strings/string_view.h" +#include "api/numerics/samples_stats_counter.h" +#include "rtc_base/checks.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/synchronization/mutex.h" +#include "test/testsupport/file_utils.h" +#include "test/testsupport/perf_test_histogram_writer.h" + +namespace webrtc { +namespace test { + +namespace { + +std::string UnitWithDirection( + absl::string_view units, + webrtc::test::ImproveDirection improve_direction) { + switch (improve_direction) { + case webrtc::test::ImproveDirection::kNone: + return std::string(units); + case webrtc::test::ImproveDirection::kSmallerIsBetter: + return std::string(units) + "_smallerIsBetter"; + case webrtc::test::ImproveDirection::kBiggerIsBetter: + return std::string(units) + "_biggerIsBetter"; + } +} + +std::vector<SamplesStatsCounter::StatsSample> GetSortedSamples( + const SamplesStatsCounter& counter) { + rtc::ArrayView<const SamplesStatsCounter::StatsSample> view = + counter.GetTimedSamples(); + std::vector<SamplesStatsCounter::StatsSample> out(view.begin(), view.end()); + std::stable_sort(out.begin(), out.end(), + [](const SamplesStatsCounter::StatsSample& a, + const SamplesStatsCounter::StatsSample& b) { + return a.time < b.time; + }); + return out; +} + +template <typename Container> +void OutputListToStream(std::ostream* ostream, const Container& values) { + const char* sep = ""; + for (const auto& v : values) { + (*ostream) << sep << v; + sep = ","; + } +} + +struct PlottableCounter { + std::string graph_name; + std::string trace_name; + webrtc::SamplesStatsCounter counter; + std::string units; +}; + +class PlottableCounterPrinter { + public: + PlottableCounterPrinter() : output_(stdout) {} + + void SetOutput(FILE* output) { + MutexLock lock(&mutex_); + output_ = output; + } + + void AddCounter(absl::string_view graph_name, + absl::string_view trace_name, + const webrtc::SamplesStatsCounter& counter, + absl::string_view units) { + MutexLock lock(&mutex_); + plottable_counters_.push_back({std::string(graph_name), + std::string(trace_name), counter, + std::string(units)}); + } + + void Print(const std::vector<std::string>& desired_graphs_raw) const { + std::set<std::string> desired_graphs(desired_graphs_raw.begin(), + desired_graphs_raw.end()); + MutexLock lock(&mutex_); + for (auto& counter : plottable_counters_) { + if (!desired_graphs.empty()) { + auto it = desired_graphs.find(counter.graph_name); + if (it == desired_graphs.end()) { + continue; + } + } + + std::ostringstream value_stream; + value_stream.precision(8); + value_stream << R"({"graph_name":")" << counter.graph_name << R"(",)"; + value_stream << R"("trace_name":")" << counter.trace_name << R"(",)"; + value_stream << R"("units":")" << counter.units << R"(",)"; + if (!counter.counter.IsEmpty()) { + value_stream << R"("mean":)" << counter.counter.GetAverage() << ','; + value_stream << R"("std":)" << counter.counter.GetStandardDeviation() + << ','; + } + value_stream << R"("samples":[)"; + const char* sep = ""; + for (const auto& sample : counter.counter.GetTimedSamples()) { + value_stream << sep << R"({"time":)" << sample.time.us() << ',' + << R"("value":)" << sample.value << '}'; + sep = ","; + } + value_stream << "]}"; + + fprintf(output_, "PLOTTABLE_DATA: %s\n", value_stream.str().c_str()); + } + } + + private: + mutable Mutex mutex_; + std::vector<PlottableCounter> plottable_counters_ RTC_GUARDED_BY(&mutex_); + FILE* output_ RTC_GUARDED_BY(&mutex_); +}; + +PlottableCounterPrinter& GetPlottableCounterPrinter() { + static PlottableCounterPrinter* printer_ = new PlottableCounterPrinter(); + return *printer_; +} + +class ResultsLinePrinter { + public: + ResultsLinePrinter() : output_(stdout) {} + + void SetOutput(FILE* output) { + MutexLock lock(&mutex_); + output_ = output; + } + + void PrintResult(absl::string_view graph_name, + absl::string_view trace_name, + const double value, + absl::string_view units, + bool important, + ImproveDirection improve_direction) { + std::ostringstream value_stream; + value_stream.precision(8); + value_stream << value; + + PrintResultImpl(graph_name, trace_name, value_stream.str(), std::string(), + std::string(), UnitWithDirection(units, improve_direction), + important); + } + + void PrintResultMeanAndError(absl::string_view graph_name, + absl::string_view trace_name, + const double mean, + const double error, + absl::string_view units, + bool important, + ImproveDirection improve_direction) { + std::ostringstream value_stream; + value_stream.precision(8); + value_stream << mean << ',' << error; + PrintResultImpl(graph_name, trace_name, value_stream.str(), "{", "}", + UnitWithDirection(units, improve_direction), important); + } + + void PrintResultList(absl::string_view graph_name, + absl::string_view trace_name, + const rtc::ArrayView<const double> values, + absl::string_view units, + const bool important, + webrtc::test::ImproveDirection improve_direction) { + std::ostringstream value_stream; + value_stream.precision(8); + OutputListToStream(&value_stream, values); + PrintResultImpl(graph_name, trace_name, value_stream.str(), "[", "]", units, + important); + } + + private: + void PrintResultImpl(absl::string_view graph_name, + absl::string_view trace_name, + absl::string_view values, + absl::string_view prefix, + absl::string_view suffix, + absl::string_view units, + bool important) { + MutexLock lock(&mutex_); + rtc::StringBuilder message; + message << (important ? "*" : "") << "RESULT " << graph_name << ": " + << trace_name << "= " << prefix << values << suffix << " " << units; + // <*>RESULT <graph_name>: <trace_name>= <value> <units> + // <*>RESULT <graph_name>: <trace_name>= {<mean>, <std deviation>} <units> + // <*>RESULT <graph_name>: <trace_name>= [<value>,value,value,...,] <units> + fprintf(output_, "%s\n", message.str().c_str()); + } + + Mutex mutex_; + FILE* output_ RTC_GUARDED_BY(&mutex_); +}; + +ResultsLinePrinter& GetResultsLinePrinter() { + static ResultsLinePrinter* const printer_ = new ResultsLinePrinter(); + return *printer_; +} + +PerfTestResultWriter& GetPerfWriter() { + static PerfTestResultWriter* writer = CreateHistogramWriter(); + return *writer; +} + +} // namespace + +void ClearPerfResults() { + GetPerfWriter().ClearResults(); +} + +void SetPerfResultsOutput(FILE* output) { + GetPlottableCounterPrinter().SetOutput(output); + GetResultsLinePrinter().SetOutput(output); +} + +std::string GetPerfResults() { + return GetPerfWriter().Serialize(); +} + +void PrintPlottableResults(const std::vector<std::string>& desired_graphs) { + GetPlottableCounterPrinter().Print(desired_graphs); +} + +bool WritePerfResults(const std::string& output_path) { + std::string results = GetPerfResults(); + CreateDir(DirName(output_path)); + FILE* output = fopen(output_path.c_str(), "wb"); + if (output == NULL) { + printf("Failed to write to %s.\n", output_path.c_str()); + return false; + } + size_t written = + fwrite(results.c_str(), sizeof(char), results.size(), output); + fclose(output); + + if (written != results.size()) { + long expected = results.size(); + printf("Wrote %zu, tried to write %lu\n", written, expected); + return false; + } + + return true; +} + +void PrintResult(absl::string_view measurement, + absl::string_view modifier, + absl::string_view trace, + const double value, + absl::string_view units, + bool important, + ImproveDirection improve_direction) { + rtc::StringBuilder graph_name; + graph_name << measurement << modifier; + RTC_CHECK(std::isfinite(value)) + << "Expected finite value for graph " << graph_name.str() + << ", trace name " << trace << ", units " << units << ", got " << value; + GetPerfWriter().LogResult(graph_name.str(), trace, value, units, important, + improve_direction); + GetResultsLinePrinter().PrintResult(graph_name.str(), trace, value, units, + important, improve_direction); +} + +void PrintResult(absl::string_view measurement, + absl::string_view modifier, + absl::string_view trace, + const SamplesStatsCounter& counter, + absl::string_view units, + const bool important, + ImproveDirection improve_direction) { + rtc::StringBuilder graph_name; + graph_name << measurement << modifier; + GetPlottableCounterPrinter().AddCounter(graph_name.str(), trace, counter, + units); + + double mean = counter.IsEmpty() ? 0 : counter.GetAverage(); + double error = counter.IsEmpty() ? 0 : counter.GetStandardDeviation(); + + std::vector<SamplesStatsCounter::StatsSample> timed_samples = + GetSortedSamples(counter); + std::vector<double> samples(timed_samples.size()); + for (size_t i = 0; i < timed_samples.size(); ++i) { + samples[i] = timed_samples[i].value; + } + // If we have an empty counter, default it to 0. + if (samples.empty()) { + samples.push_back(0); + } + + GetPerfWriter().LogResultList(graph_name.str(), trace, samples, units, + important, improve_direction); + GetResultsLinePrinter().PrintResultMeanAndError(graph_name.str(), trace, mean, + error, units, important, + improve_direction); +} + +void PrintResultMeanAndError(absl::string_view measurement, + absl::string_view modifier, + absl::string_view trace, + const double mean, + const double error, + absl::string_view units, + bool important, + ImproveDirection improve_direction) { + RTC_CHECK(std::isfinite(mean)); + RTC_CHECK(std::isfinite(error)); + + rtc::StringBuilder graph_name; + graph_name << measurement << modifier; + GetPerfWriter().LogResultMeanAndError(graph_name.str(), trace, mean, error, + units, important, improve_direction); + GetResultsLinePrinter().PrintResultMeanAndError(graph_name.str(), trace, mean, + error, units, important, + improve_direction); +} + +void PrintResultList(absl::string_view measurement, + absl::string_view modifier, + absl::string_view trace, + const rtc::ArrayView<const double> values, + absl::string_view units, + bool important, + ImproveDirection improve_direction) { + for (double v : values) { + RTC_CHECK(std::isfinite(v)); + } + + rtc::StringBuilder graph_name; + graph_name << measurement << modifier; + GetPerfWriter().LogResultList(graph_name.str(), trace, values, units, + important, improve_direction); + GetResultsLinePrinter().PrintResultList(graph_name.str(), trace, values, + units, important, improve_direction); +} + +} // namespace test +} // namespace webrtc |