blob: 8c999c95e5427c75168b0a17a5b1d8c6543d6d9c [file] [log] [blame]
// Copyright 2019 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 "chrome/test/base/perf/performance_test.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_samples.h"
#include "base/metrics/statistics_recorder.h"
#include "base/trace_event/trace_event.h"
#include "chrome/test/base/test_switches.h"
#include "content/public/browser/tracing_controller.h"
#include "services/tracing/public/cpp/trace_event_agent.h"
#include "testing/perf/luci_test_result.h"
#include "ui/compositor/compositor_switches.h"
#include "ui/gl/gl_switches.h"
#if defined(OS_CHROMEOS)
#include "ash/public/cpp/wallpaper_controller_observer.h"
#include "ash/public/cpp/wallpaper_types.h"
#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
#include "components/user_manager/user_names.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/image/image_skia.h"
#endif // OS_CHROMEOS
namespace {
constexpr char kTraceDir[] = "trace-dir";
#if defined(OS_CHROMEOS)
// Watches if the wallpaper has been changed and runs a passed callback if so.
class TestWallpaperObserver : public ash::WallpaperControllerObserver {
public:
explicit TestWallpaperObserver(base::OnceClosure closure)
: closure_(std::move(closure)) {
WallpaperControllerClient::Get()->AddObserver(this);
}
~TestWallpaperObserver() override {
WallpaperControllerClient::Get()->RemoveObserver(this);
}
// ash::WallpaperControllerObserver:
void OnWallpaperChanged() override { std::move(closure_).Run(); }
private:
base::OnceClosure closure_;
DISALLOW_COPY_AND_ASSIGN(TestWallpaperObserver);
};
// Creates a high resolution wallpaper and sets it as the current wallpaper as
// the wallpaper affects many UI tests.
void CreateAndSetWallpaper() {
gfx::Size display_size =
display::Screen::GetScreen()->GetPrimaryDisplay().GetSizeInPixel();
SkBitmap bitmap;
bitmap.allocN32Pixels(display_size.width(), display_size.height(),
/*isOpaque=*/true);
SkCanvas canvas(bitmap);
canvas.drawColor(SK_ColorGREEN);
gfx::ImageSkia image(gfx::ImageSkiaRep(std::move(bitmap), 1.f));
base::RunLoop run_loop;
TestWallpaperObserver observer(run_loop.QuitClosure());
WallpaperControllerClient::Get()->SetCustomWallpaper(
user_manager::StubAccountId(), /*wallpaper_files_id=*/"dummyid",
/*file_name=*/"dummyfilename", ash::WALLPAPER_LAYOUT_CENTER_CROPPED,
image, /*preview_mode=*/false);
run_loop.Run();
}
#endif // OS_CHROMEOS
perf_test::LuciTestResult CreateTestResult(
const base::FilePath& trace_file,
const std::vector<std::string>& tbm_metrics) {
perf_test::LuciTestResult result =
perf_test::LuciTestResult::CreateForGTest();
result.AddOutputArtifactFile("trace/1", trace_file, "application/json");
for (auto& metric : tbm_metrics)
result.AddTag("tbmv2", metric);
return result;
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// PerformanceTest
PerformanceTest::PerformanceTest()
: should_start_trace_(
base::CommandLine::ForCurrentProcess()->HasSwitch(kTraceDir)) {
if (should_start_trace_) {
auto* cmd = base::CommandLine::ForCurrentProcess();
cmd->AppendSwitch(switches::kUseGpuInTests);
cmd->AppendSwitch(switches::kEnablePixelOutputInTests);
}
}
PerformanceTest::~PerformanceTest() {
DCHECK(setup_called_);
}
std::vector<std::string> PerformanceTest::GetUMAHistogramNames() const {
return {};
}
const std::string PerformanceTest::GetTracingCategories() const {
return std::string();
}
std::vector<std::string> PerformanceTest::GetTimelineBasedMetrics() const {
return {};
}
void PerformanceTest::SetUpOnMainThread() {
setup_called_ = true;
InProcessBrowserTest::SetUpOnMainThread();
if (!should_start_trace_)
return;
auto* controller = content::TracingController::GetInstance();
base::trace_event::TraceConfig config(GetTracingCategories(),
base::trace_event::RECORD_CONTINUOUSLY);
for (const auto& histogram : GetUMAHistogramNames())
config.EnableHistogram(histogram);
base::RunLoop runloop;
bool result = controller->StartTracing(config, runloop.QuitClosure());
runloop.Run();
CHECK(result);
}
void PerformanceTest::TearDownOnMainThread() {
auto* command_line = base::CommandLine::ForCurrentProcess();
if (should_start_trace_) {
auto* controller = content::TracingController::GetInstance();
ASSERT_TRUE(controller->IsTracing())
<< "Did you forget to call PerformanceTest::SetUpOnMainThread?";
base::RunLoop runloop;
base::FilePath dir = command_line->GetSwitchValuePath(kTraceDir);
base::FilePath trace_file;
CHECK(base::CreateTemporaryFileInDir(dir, &trace_file));
LOG(INFO) << "Created the trace file: " << trace_file;
auto trace_data_endpoint = content::TracingController::CreateFileEndpoint(
trace_file, runloop.QuitClosure());
bool result = controller->StopTracing(trace_data_endpoint);
runloop.Run();
CHECK(result);
base::FilePath report_file =
trace_file.AddExtension(FILE_PATH_LITERAL("test_result.json"));
CreateTestResult(trace_file, GetTimelineBasedMetrics())
.WriteToFile(report_file);
}
bool print = command_line->HasSwitch(switches::kPerfTestPrintUmaMeans);
LOG_IF(INFO, print) << "=== Histogram Means ===";
for (auto name : GetUMAHistogramNames()) {
EXPECT_TRUE(HasHistogram(name)) << "missing histogram:" << name;
LOG_IF(INFO, print) << name << ": " << GetHistogramMean(name);
}
LOG_IF(INFO, print) << "=== End Histogram Means ===";
InProcessBrowserTest::TearDownOnMainThread();
}
float PerformanceTest::GetHistogramMean(const std::string& name) {
auto* histogram = base::StatisticsRecorder::FindHistogram(name);
if (!histogram)
return 0;
// Use SnapshotFinalDelta() so that it won't contain the samples before the
// subclass invokes SnapshotDelta() during the test.
auto samples = histogram->SnapshotFinalDelta();
DCHECK_NE(0, samples->TotalCount());
return static_cast<float>(samples->sum()) / samples->TotalCount();
}
bool PerformanceTest::HasHistogram(const std::string& name) {
return !!base::StatisticsRecorder::FindHistogram(name);
}
////////////////////////////////////////////////////////////////////////////////
// UIPerformanceTest
void UIPerformanceTest::SetUpOnMainThread() {
PerformanceTest::SetUpOnMainThread();
#if defined(OS_CHROMEOS)
CreateAndSetWallpaper();
#endif // OS_CHROMEOS
}
const std::string UIPerformanceTest::GetTracingCategories() const {
return "benchmark,cc,viz,input,latency,gpu,rail,toplevel,ui,views,viz";
}
std::vector<std::string> UIPerformanceTest::GetTimelineBasedMetrics() const {
return {"renderingMetric", "umaMetric"};
}