Commit 6e66eeb7 authored by Annie Su's avatar Annie Su Committed by Commit Bot

Implement interactive UI test to measure paint perf of the browser UI

This is a native UI performance test that reports the average CPU time
of each step in the pipeline reporter (e.g.
SingleThreadedCompositorLatency.SendBeginMainFrameToCommit), in
microseconds. Note that SendBeginMainFrameToCommit is of particular
interest because the metric contains View::Paint times. In the test,
we hover over each tab in a browser by mousing slowly over the
tab strip from left to right. Hover cards and tooltips are disabled.

Note that the test currently only builds for chromeos. This is because
the DragEventGenerator has the option to use touch events, and these
touch events are only compatible with chromeos currently. If you
want to run the test on Linux or Windows, move the test file and
DragEventGenerator files in the BUILD file such that they build for
the desired platform, and comment out the SendTouchEvent() and
SendTouchEventNotifyWhenDone() from the DragEventGenerator file.

Bug: 974349

Change-Id: Iaf7c5975cca158eb79175927a60ca50ca82d1ba8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1662970
Commit-Queue: Annie Su <anniesu@google.com>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: default avatarDana Fried <dfried@chromium.org>
Reviewed-by: default avatarCollin Baker <collinbaker@chromium.org>
Reviewed-by: default avatarMalay Keshav <malaykeshav@chromium.org>
Cr-Commit-Position: refs/heads/master@{#685292}
parent 8525b6e8
// 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 "base/macros.h"
#include "base/metrics/histogram_samples.h"
#include "base/metrics/statistics_recorder.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/perf/drag_event_generator.h"
#include "chrome/test/base/perf/performance_test.h"
#include "chrome/test/base/ui_test_utils.h"
#if defined(USE_AURA)
#include "ui/aura/env.h"
#include "ui/wm/public/scoped_tooltip_disabler.h"
#endif
using views::Widget;
static const int kNumTabs = 8;
// TODO(crbug.com/991000): Enable this test for Windows and Linux once
// DragEventGenerator works for those platforms as well.
class TabHoverTest : public UIPerformanceTest {
public:
TabHoverTest() {
// Disable hover cards.
scoped_feature_list_.InitAndDisableFeature(features::kTabHoverCards);
}
~TabHoverTest() override = default;
void SetUpOnMainThread() override {
// Disable tooltips. Note that this only works if we are using Aura.
BrowserView* browser_view =
BrowserView::GetBrowserViewForBrowser(browser());
#if defined(USE_AURA)
aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow();
tooltip_disabler_ =
std::make_unique<wm::ScopedTooltipDisabler>(browser_window);
#endif
// Open up the tabs first so we only trace after they're open.
const GURL ntp_url("about:blank");
for (int i = 1; i < kNumTabs; ++i) {
ui_test_utils::NavigateToURLWithDisposition(
browser(), ntp_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
}
// Now start the trace.
UIPerformanceTest::SetUpOnMainThread();
}
void IgnorePriorHistogramSamples() {
// Take the snapshot delta; so that the samples created so far will be
// eliminated from the samples.
for (const auto& name : GetUMAHistogramNames()) {
auto* histogram = base::StatisticsRecorder::FindHistogram(name);
if (!histogram)
continue;
histogram->SnapshotDelta();
}
}
private:
std::vector<std::string> GetUMAHistogramNames() const override {
// Report each step in the Pipeline Reporter. Note that the UMA mean
// will only be printed if the following command line flag is provided:
// --perf-test-print-uma-means. Each measurement is in microseconds.
return {
"SingleThreadedCompositorLatency.BeginImplFrameToSendBeginMainFrame",
"SingleThreadedCompositorLatency.SendBeginMainFrameToCommit",
"SingleThreadedCompositorLatency.Commit",
"SingleThreadedCompositorLatency.EndCommitToActivation",
"SingleThreadedCompositorLatency.EndActivateToSubmitCompositorFrame"};
}
base::test::ScopedFeatureList scoped_feature_list_;
#if defined(USE_AURA)
std::unique_ptr<wm::ScopedTooltipDisabler> tooltip_disabler_;
#endif
DISALLOW_COPY_AND_ASSIGN(TabHoverTest);
};
IN_PROC_BROWSER_TEST_F(TabHoverTest, HoverOverMultipleTabs) {
// This test is intended to gauge performance of the tab strip during
// tab hovering by mousing over each tab in the window, from left to right.
// This is meant to mimic a user looking at each tab in order to locate
// a specific one.
IgnorePriorHistogramSamples();
TabStrip* tab_strip =
BrowserView::GetBrowserViewForBrowser(browser())->tabstrip();
// Start at the center of the first tab.
const gfx::Point start_position =
ui_test_utils::GetCenterInScreenCoordinates(tab_strip->tab_at(0));
// End at the center of the last tab.
const gfx::Point end_position = ui_test_utils::GetCenterInScreenCoordinates(
tab_strip->tab_at(kNumTabs - 1));
// Slowly mouse from the start to end positions across the tab strip. Tick
// this mousemove at a high frequency (120fps) to avoid having the timer fire
// at the wrong time due to having frames without any input event.
ui_test_utils::DragEventGenerator generator(
std::make_unique<ui_test_utils::InterpolatedProducer>(
start_position, end_position,
base::TimeDelta::FromMilliseconds(5000)),
/*touch=*/false, /*hover=*/true, /*high frequency=*/true);
generator.Wait();
#if defined(USE_AURA)
const gfx::Point& last_mouse_loc =
aura::Env::GetInstance()->last_mouse_location();
ASSERT_EQ(end_position, last_mouse_loc);
#endif
}
......@@ -5539,6 +5539,7 @@ if (!is_android) {
"../browser/ui/ash/split_view_interactive_uitest.cc",
"../browser/ui/ash/tablet_mode_transition_interactive_uitest.cc",
"../browser/ui/ash/window_resize_interactive_uitest.cc",
"../browser/ui/views/tabs/tab_hover_interactive_uitest.cc",
"base/perf/drag_event_generator.cc",
"base/perf/drag_event_generator.h",
]
......
......@@ -13,23 +13,20 @@
#include "ui/base/test/ui_controls.h"
namespace ui_test_utils {
namespace {
// The frame duration for 60fps.
constexpr base::TimeDelta kFrameDuration =
base::TimeDelta::FromMicroseconds(16666);
} // namespace
////////////////////////////////////////////////////////////////////////////////
// DragEventGenerator
DragEventGenerator::DragEventGenerator(std::unique_ptr<PointProducer> producer,
bool touch)
bool touch,
bool hover,
bool use_120fps)
: producer_(std::move(producer)),
use_120fps_(use_120fps),
start_(base::TimeTicks::Now()),
expected_next_time_(start_ + kFrameDuration),
touch_(touch) {
expected_next_time_(start_ + GetNextFrameDuration()),
touch_(touch),
hover_(hover) {
gfx::Point initial_position = producer_->GetPosition(0.f);
if (touch_) {
ui_controls::SendTouchEvents(ui_controls::PRESS, 0, initial_position.x(),
......@@ -39,12 +36,13 @@ DragEventGenerator::DragEventGenerator(std::unique_ptr<PointProducer> producer,
ui_controls::SendMouseMoveNotifyWhenDone(
initial_position.x(), initial_position.y(), run_loop.QuitClosure());
run_loop.Run();
if (!hover_)
ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::DOWN);
}
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&DragEventGenerator::GenerateNext, base::Unretained(this)),
kFrameDuration);
GetNextFrameDuration());
}
DragEventGenerator::~DragEventGenerator() {
......@@ -60,7 +58,7 @@ void DragEventGenerator::GenerateNext() {
auto now = base::TimeTicks::Now();
auto elapsed = now - start_;
expected_next_time_ += kFrameDuration;
expected_next_time_ += GetNextFrameDuration();
count_++;
const base::TimeDelta duration = producer_->GetDuration();
if (elapsed >= duration) {
......@@ -114,6 +112,10 @@ void DragEventGenerator::Done(const gfx::Point position) {
}
}
base::TimeDelta DragEventGenerator::GetNextFrameDuration() const {
return base::TimeDelta::FromMicroseconds(use_120fps_ ? 8333 : 16666);
}
////////////////////////////////////////////////////////////////////////////////
// DragEventGenerator::PointProducer
......
......@@ -30,7 +30,9 @@ class DragEventGenerator {
};
DragEventGenerator(std::unique_ptr<PointProducer> producer,
bool touch = false);
bool touch = false,
bool hover = false,
bool use_120fps = false);
~DragEventGenerator();
void Wait();
......@@ -38,13 +40,18 @@ class DragEventGenerator {
private:
void Done(const gfx::Point position);
void GenerateNext();
base::TimeDelta GetNextFrameDuration() const;
std::unique_ptr<PointProducer> producer_;
int count_ = 0;
// Whether the frame duration corresponds to 120fps (as opposed to 60fps).
const bool use_120fps_;
const base::TimeTicks start_;
base::TimeTicks expected_next_time_;
const bool touch_;
const bool hover_;
base::RunLoop run_loop_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment