Index: testing/perf/scoped_histogram_result_printer.cc |
diff --git a/testing/perf/scoped_histogram_result_printer.cc b/testing/perf/scoped_histogram_result_printer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f39d47063f0b8e3f3ff60681866c0af339c41257 |
--- /dev/null |
+++ b/testing/perf/scoped_histogram_result_printer.cc |
@@ -0,0 +1,157 @@ |
+// Copyright (c) 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "testing/perf/scoped_histogram_result_printer.h" |
+ |
+#include <cmath> |
+#include <memory> |
+ |
+#include "base/memory/ptr_util.h" |
+#include "base/metrics/histogram_samples.h" |
+#include "base/metrics/statistics_recorder.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "testing/perf/perf_test.h" |
+ |
+namespace { |
+ |
+class TestBasedPrinter { |
+ public: |
+ TestBasedPrinter(const ::testing::UnitTest* test, std::string units) |
+ : units_(std::move(units)) { |
+ DCHECK(test); |
+ test_info_ = test->current_test_info(); |
+ DCHECK(test_info_); |
+ } |
+ |
+ void PrintHistogram(const base::HistogramSamples& samples, |
+ const std::string& measurement) { |
+ std::int64_t total_sum = samples.sum(); |
+ base::HistogramBase::Count total_count = |
+ static_cast<double>(samples.redundant_count()); |
+ double mean = static_cast<double>(total_sum) / total_count; |
+ |
+ double standard_deviation = 0; |
+ for (auto sample_iter = samples.Iterator(); !sample_iter->Done(); |
+ sample_iter->Next()) { |
+ base::HistogramBase::Sample min, max; |
+ base::HistogramBase::Count count; |
+ sample_iter->Get(&min, &max, &count); |
+ |
+ double bucket_mean = (static_cast<double>(min) + max) / 2; |
+ |
+ standard_deviation += |
+ (bucket_mean - mean) * (bucket_mean - mean) * |
+ (static_cast<double>(count) / // we do division on every iteration |
+ total_count); // to get better precision |
+ } |
+ standard_deviation = std::sqrt(standard_deviation); |
+ |
+ perf_test::PrintResultMeanAndError( |
+ test_info_->test_case_name(), test_info_->name(), measurement, |
+ std::to_string(mean) + ", " + std::to_string(standard_deviation), |
+ units_, true); |
+ } |
+ |
+ private: |
+ const ::testing::TestInfo* test_info_ = nullptr; |
+ std::string units_; |
+}; |
+ |
+} // namespace |
+ |
+namespace perf_test { |
+ |
+HistogramPrinter TestBasedPerfTestPrinter(const ::testing::UnitTest* test, |
+ std::string units) { |
+ auto printer = base::WrapUnique(new TestBasedPrinter(test, std::move(units))); |
+ return base::Bind(&TestBasedPrinter::PrintHistogram, |
+ base::Owned(printer.release())); |
+} |
+ |
+// ScopedHistogramResultPrinter::HistogramInfo--------------------------------- |
+ |
+class ScopedHistogramResultPrinter::HistogramInfo { |
+ public: |
+ HistogramInfo(std::string name, |
+ std::string measurement, |
+ bool is_nice, |
+ std::unique_ptr<base::HistogramSamples> before_samples) |
+ : name_(std::move(name)), |
+ measurement_(std::move(measurement)), |
+ is_nice_(is_nice), |
+ before_samples_(std::move(before_samples)) {} |
+ |
+ const std::string& name() const { return name_; } |
+ const std::string& measurement() const { return measurement_; } |
+ bool is_nice() const { return is_nice_; } |
+ const base::HistogramSamples* before_samples() const { |
+ return before_samples_.get(); |
+ } |
+ |
+ private: |
+ std::string name_; |
+ std::string measurement_; |
+ bool is_nice_; |
+ std::unique_ptr<base::HistogramSamples> before_samples_; |
+}; |
+ |
+// ScopedHistogramResultPrinter------------------------------------------------ |
+ |
+ScopedHistogramResultPrinter::ScopedHistogramResultPrinter( |
+ HistogramPrinter printer) |
+ : printer_(printer) {} |
+ |
+void ScopedHistogramResultPrinter::AddHistogramStrict(std::string name, |
+ std::string measurement) { |
+ const bool is_nice = false; |
+ AddHistogram(std::move(name), std::move(measurement), is_nice); |
+} |
+ |
+void ScopedHistogramResultPrinter::AddHistogramNice(std::string name, |
+ std::string measurement) { |
+ const bool is_nice = true; |
+ AddHistogram(std::move(name), std::move(measurement), is_nice); |
+} |
+ |
+void ScopedHistogramResultPrinter::AddHistogram(std::string name, |
+ std::string measurement, |
+ const bool is_nice) { |
+ std::unique_ptr<base::HistogramSamples> samples_before; |
+ |
+ base::HistogramBase* histogram = |
+ base::StatisticsRecorder::FindHistogram(name); |
+ |
+ if (histogram) |
+ samples_before = histogram->SnapshotSamples(); |
+ |
+ histograms_.emplace_back(std::move(name), std::move(measurement), is_nice, |
+ std::move(samples_before)); |
+} |
+ |
+ScopedHistogramResultPrinter::~ScopedHistogramResultPrinter() { |
+ for (const HistogramInfo& histogram_info : histograms_) { |
+ base::HistogramBase* histogram = |
+ base::StatisticsRecorder::FindHistogram(histogram_info.name()); |
+ |
+ if (histogram) { |
+ std::unique_ptr<base::HistogramSamples> samples_after( |
+ histogram->SnapshotSamples()); |
+ DCHECK(samples_after); |
+ |
+ if (histogram_info.before_samples()) |
+ samples_after->Subtract(*histogram_info.before_samples()); |
+ |
+ if (samples_after->redundant_count()) |
+ printer_.Run(*samples_after, histogram_info.measurement()); |
+ else |
+ EXPECT_TRUE(histogram_info.is_nice()) << "Nothing was added in " |
+ << histogram_info.name(); |
+ } else { |
+ EXPECT_TRUE(histogram_info.is_nice()) |
+ << "Expected histogram " << histogram_info.name() << " wasn't found"; |
+ } |
+ } |
+} |
+ |
+} // namespace perf_test |