blob: d615b825c10653093c6133f4538da46b3397d3f8 [file] [log] [blame]
// Copyright 2014 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 "content/browser/renderer_host/input/render_widget_host_latency_tracker.h"
#include "base/metrics/metrics_hashes.h"
#include "base/test/metrics/histogram_tester.h"
#include "components/rappor/public/rappor_utils.h"
#include "components/rappor/test_rappor_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/test/test_content_browser_client.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "services/metrics/public/cpp/ukm_source.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Bucket;
using blink::WebInputEvent;
using testing::ElementsAre;
namespace content {
namespace {
// Trace ids are generated in sequence in practice, but in these tests, we don't
// care about the value, so we'll just use a constant.
const int kTraceEventId = 5;
const char kUrl[] = "http://www.foo.bar.com/subpage/1";
void AddFakeComponentsWithTimeStamp(
const RenderWidgetHostLatencyTracker& tracker,
ui::LatencyInfo* latency,
base::TimeTicks time_stamp) {
latency->AddLatencyNumberWithTimestamp(ui::INPUT_EVENT_LATENCY_UI_COMPONENT,
time_stamp, 1);
latency->AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT, time_stamp, 1);
latency->AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, time_stamp, 1);
latency->AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, time_stamp, 1);
latency->AddLatencyNumberWithTimestamp(
ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, time_stamp, 1);
}
void AddFakeComponents(const RenderWidgetHostLatencyTracker& tracker,
ui::LatencyInfo* latency) {
base::TimeTicks now = base::TimeTicks::Now();
latency->AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, now, 1);
latency->AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT, now, 1);
AddFakeComponentsWithTimeStamp(tracker, latency, base::TimeTicks::Now());
}
void AddRenderingScheduledComponent(ui::LatencyInfo* latency,
bool main,
base::TimeTicks time_stamp) {
if (main) {
latency->AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT, time_stamp,
1);
} else {
latency->AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT, time_stamp,
1);
}
}
} // namespace
class RenderWidgetHostLatencyTrackerTestBrowserClient
: public TestContentBrowserClient {
public:
RenderWidgetHostLatencyTrackerTestBrowserClient() {}
~RenderWidgetHostLatencyTrackerTestBrowserClient() override {}
ukm::TestUkmRecorder* GetTestUkmRecorder() { return &test_ukm_recorder_; }
private:
ukm::TestAutoSetUkmRecorder test_ukm_recorder_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostLatencyTrackerTestBrowserClient);
};
class RenderWidgetHostLatencyTrackerTest
: public RenderViewHostImplTestHarness {
public:
RenderWidgetHostLatencyTrackerTest() : old_browser_client_(nullptr) {
ResetHistograms();
}
void ExpectUkmReported(ukm::SourceId source_id,
const char* event_name,
const std::vector<std::string>& metric_names,
size_t expected_count) {
const ukm::TestUkmRecorder* ukm_recoder =
test_browser_client_.GetTestUkmRecorder();
auto entries = ukm_recoder->GetEntriesByName(event_name);
EXPECT_EQ(expected_count, entries.size());
for (const auto* const entry : entries) {
EXPECT_EQ(source_id, entry->source_id);
for (const auto& metric_name : metric_names) {
EXPECT_TRUE(ukm_recoder->EntryHasMetric(entry, metric_name.c_str()));
}
}
}
::testing::AssertionResult HistogramSizeEq(const char* histogram_name,
int size) {
uint64_t histogram_size =
histogram_tester_->GetAllSamples(histogram_name).size();
if (static_cast<uint64_t>(size) == histogram_size) {
return ::testing::AssertionSuccess();
} else {
return ::testing::AssertionFailure() << histogram_name << " expected "
<< size << " entries, but had "
<< histogram_size;
}
}
RenderWidgetHostLatencyTracker* tracker() { return tracker_.get(); }
ui::LatencyTracker* viz_tracker() { return &viz_tracker_; }
void ResetHistograms() {
histogram_tester_.reset(new base::HistogramTester());
}
const base::HistogramTester& histogram_tester() {
return *histogram_tester_;
}
void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
old_browser_client_ = SetBrowserClientForTesting(&test_browser_client_);
tracker_ = std::make_unique<RenderWidgetHostLatencyTracker>(contents());
}
void TearDown() override {
SetBrowserClientForTesting(old_browser_client_);
RenderViewHostImplTestHarness::TearDown();
test_browser_client_.GetTestUkmRecorder()->Purge();
}
protected:
std::unique_ptr<base::HistogramTester> histogram_tester_;
std::unique_ptr<RenderWidgetHostLatencyTracker> tracker_;
ui::LatencyTracker viz_tracker_;
RenderWidgetHostLatencyTrackerTestBrowserClient test_browser_client_;
ContentBrowserClient* old_browser_client_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostLatencyTrackerTest);
};
TEST_F(RenderWidgetHostLatencyTrackerTest, TestValidEventTiming) {
base::TimeTicks now = base::TimeTicks::Now();
ui::LatencyInfo latency_info;
latency_info.set_trace_id(kTraceEventId);
latency_info.set_source_event_type(ui::SourceEventType::WHEEL);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
now + base::TimeDelta::FromMilliseconds(60), 1);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT,
now + base::TimeDelta::FromMilliseconds(50), 1);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT,
now + base::TimeDelta::FromMilliseconds(40), 1);
latency_info.AddLatencyNumberWithTimestamp(
ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT,
now + base::TimeDelta::FromMilliseconds(30), 1);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
now + base::TimeDelta::FromMilliseconds(20), 1);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT,
now + base::TimeDelta::FromMilliseconds(10), 1);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT, now, 1);
viz_tracker()->OnGpuSwapBuffersCompleted(latency_info);
// When last_event_time of the end_component is less than the first_event_time
// of the start_component, zero is recorded instead of a negative value.
histogram_tester().ExpectUniqueSample(
"Event.Latency.ScrollBegin.Wheel.TimeToScrollUpdateSwapBegin4", 0, 1);
histogram_tester().ExpectUniqueSample(
"Event.Latency.Scroll.Wheel.TimeToScrollUpdateSwapBegin2", 0, 1);
histogram_tester().ExpectUniqueSample(
"Event.Latency.ScrollBegin.Wheel.TimeToHandled2_Impl", 0, 1);
histogram_tester().ExpectUniqueSample(
"Event.Latency.Scroll.Wheel.TimeToHandled2_Impl", 0, 1);
histogram_tester().ExpectUniqueSample(
"Event.Latency.ScrollBegin.Wheel.HandledToRendererSwap2_Impl", 0, 1);
histogram_tester().ExpectUniqueSample(
"Event.Latency.ScrollBegin.Wheel.RendererSwapToBrowserNotified2", 0, 1);
histogram_tester().ExpectUniqueSample(
"Event.Latency.ScrollBegin.Wheel.BrowserNotifiedToBeforeGpuSwap2", 0, 1);
histogram_tester().ExpectUniqueSample(
"Event.Latency.ScrollBegin.Wheel.GpuSwap2", 0, 1);
}
TEST_F(RenderWidgetHostLatencyTrackerTest, TestWheelToFirstScrollHistograms) {
const GURL url(kUrl);
size_t total_ukm_entry_count = 0;
contents()->NavigateAndCommit(url);
ukm::SourceId source_id = static_cast<WebContentsImpl*>(contents())
->GetUkmSourceIdForLastCommittedSource();
EXPECT_NE(ukm::kInvalidSourceId, source_id);
for (bool rendering_on_main : {false, true}) {
ResetHistograms();
{
auto wheel = SyntheticWebMouseWheelEventBuilder::Build(
blink::WebMouseWheelEvent::kPhaseChanged);
base::TimeTicks now = base::TimeTicks::Now();
wheel.SetTimeStamp(now);
ui::LatencyInfo wheel_latency(ui::SourceEventType::WHEEL);
wheel_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, now,
1);
AddFakeComponentsWithTimeStamp(*tracker(), &wheel_latency, now);
AddRenderingScheduledComponent(&wheel_latency, rendering_on_main, now);
tracker()->OnInputEvent(wheel, &wheel_latency);
EXPECT_TRUE(wheel_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(wheel_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr));
tracker()->OnInputEventAck(wheel, &wheel_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
viz_tracker()->OnGpuSwapBuffersCompleted(wheel_latency);
// UKM metrics.
total_ukm_entry_count++;
ExpectUkmReported(
source_id, "Event.ScrollBegin.Wheel",
{"TimeToScrollUpdateSwapBegin", "TimeToHandled", "IsMainThread"},
total_ukm_entry_count);
// UMA histograms.
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin."
"TimeToScrollUpdateSwapBegin2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate."
"TimeToScrollUpdateSwapBegin2",
0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel."
"TimeToScrollUpdateSwapBegin4",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.Scroll.Wheel."
"TimeToScrollUpdateSwapBegin2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.Wheel."
"TimeToScrollUpdateSwapBegin4",
0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel.TimeToHandled2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel.TimeToHandled2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.Scroll.Wheel.TimeToHandled2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.Scroll.Wheel.TimeToHandled2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Wheel.HandledToRendererSwap2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Wheel.HandledToRendererSwap2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel."
"RendererSwapToBrowserNotified2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel."
"BrowserNotifiedToBeforeGpuSwap2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel.GpuSwap2", 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.TimeToHandled2_Main", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.TimeToHandled2_Impl", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.HandledToRendererSwap2_Main", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.HandledToRendererSwap2_Impl", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.RendererSwapToBrowserNotified2",
0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.BrowserNotifiedToBeforeGpuSwap2",
0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.Wheel.GpuSwap2", 0));
}
}
}
TEST_F(RenderWidgetHostLatencyTrackerTest, TestWheelToScrollHistograms) {
const GURL url(kUrl);
size_t total_ukm_entry_count = 0;
contents()->NavigateAndCommit(url);
ukm::SourceId source_id = static_cast<WebContentsImpl*>(contents())
->GetUkmSourceIdForLastCommittedSource();
EXPECT_NE(ukm::kInvalidSourceId, source_id);
for (bool rendering_on_main : {false, true}) {
ResetHistograms();
{
auto wheel = SyntheticWebMouseWheelEventBuilder::Build(
blink::WebMouseWheelEvent::kPhaseChanged);
base::TimeTicks now = base::TimeTicks::Now();
wheel.SetTimeStamp(now);
ui::LatencyInfo wheel_latency(ui::SourceEventType::WHEEL);
wheel_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, now, 1);
AddFakeComponentsWithTimeStamp(*tracker(), &wheel_latency, now);
AddRenderingScheduledComponent(&wheel_latency, rendering_on_main, now);
tracker()->OnInputEvent(wheel, &wheel_latency);
EXPECT_TRUE(wheel_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(wheel_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr));
tracker()->OnInputEventAck(wheel, &wheel_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
viz_tracker()->OnGpuSwapBuffersCompleted(wheel_latency);
// UKM metrics.
total_ukm_entry_count++;
ExpectUkmReported(
source_id, "Event.ScrollUpdate.Wheel",
{"TimeToScrollUpdateSwapBegin", "TimeToHandled", "IsMainThread"},
total_ukm_entry_count);
// UMA histograms.
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin."
"TimeToScrollUpdateSwapBegin2",
0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate."
"TimeToScrollUpdateSwapBegin2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel."
"TimeToScrollUpdateSwapBegin4",
0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.Scroll.Wheel."
"TimeToScrollUpdateSwapBegin2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.Wheel."
"TimeToScrollUpdateSwapBegin4",
1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Wheel.TimeToHandled2_Main", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Wheel.TimeToHandled2_Impl", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Wheel.HandledToRendererSwap2_Main", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Wheel.HandledToRendererSwap2_Impl", 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel."
"RendererSwapToBrowserNotified2",
0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel."
"BrowserNotifiedToBeforeGpuSwap2",
0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Wheel.GpuSwap2", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.TimeToHandled2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.TimeToHandled2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.Scroll.Wheel.TimeToHandled2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.Scroll.Wheel.TimeToHandled2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.HandledToRendererSwap2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.HandledToRendererSwap2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.RendererSwapToBrowserNotified2",
1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Wheel.BrowserNotifiedToBeforeGpuSwap2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.Wheel.GpuSwap2", 1));
}
}
}
TEST_F(RenderWidgetHostLatencyTrackerTest, TestInertialToScrollHistograms) {
const GURL url(kUrl);
contents()->NavigateAndCommit(url);
for (bool rendering_on_main : {false, true}) {
ResetHistograms();
{
auto scroll = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
5.f, -5.f, 0, blink::WebGestureDevice::kTouchscreen);
base::TimeTicks now = base::TimeTicks::Now();
scroll.SetTimeStamp(now);
ui::LatencyInfo scroll_latency(ui::SourceEventType::INERTIAL);
AddFakeComponentsWithTimeStamp(*tracker(), &scroll_latency, now);
AddRenderingScheduledComponent(&scroll_latency, rendering_on_main, now);
tracker()->OnInputEvent(scroll, &scroll_latency);
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr));
tracker()->OnInputEventAck(scroll, &scroll_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
viz_tracker()->OnGpuSwapBuffersCompleted(scroll_latency);
}
// UMA histograms.
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollInertial.Touch."
"TimeToScrollUpdateSwapBegin4",
1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollInertial.Touch.TimeToHandled2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollInertial.Touch.TimeToHandled2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollInertial.Touch.HandledToRendererSwap2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollInertial.Touch.HandledToRendererSwap2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollInertial.Touch.RendererSwapToBrowserNotified2",
1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollInertial.Touch.BrowserNotifiedToBeforeGpuSwap2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollInertial.Touch.GpuSwap2", 1));
}
}
TEST_F(RenderWidgetHostLatencyTrackerTest, TestTouchToFirstScrollHistograms) {
const GURL url(kUrl);
contents()->NavigateAndCommit(url);
size_t total_ukm_entry_count = 0;
ukm::SourceId source_id = static_cast<WebContentsImpl*>(contents())
->GetUkmSourceIdForLastCommittedSource();
EXPECT_NE(ukm::kInvalidSourceId, source_id);
for (bool rendering_on_main : {false, true}) {
ResetHistograms();
{
auto scroll = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
5.f, -5.f, 0, blink::WebGestureDevice::kTouchscreen);
base::TimeTicks now = base::TimeTicks::Now();
scroll.SetTimeStamp(now);
ui::LatencyInfo scroll_latency;
AddFakeComponentsWithTimeStamp(*tracker(), &scroll_latency, now);
AddRenderingScheduledComponent(&scroll_latency, rendering_on_main, now);
tracker()->OnInputEvent(scroll, &scroll_latency);
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr));
tracker()->OnInputEventAck(scroll, &scroll_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
}
{
SyntheticWebTouchEvent touch;
touch.PressPoint(0, 0);
touch.PressPoint(1, 1);
ui::LatencyInfo touch_latency(ui::SourceEventType::TOUCH);
base::TimeTicks now = base::TimeTicks::Now();
touch_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, now,
1);
touch_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT, now, 1);
AddFakeComponentsWithTimeStamp(*tracker(), &touch_latency, now);
AddRenderingScheduledComponent(&touch_latency, rendering_on_main, now);
tracker()->OnInputEvent(touch, &touch_latency);
EXPECT_TRUE(touch_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(touch_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr));
tracker()->OnInputEventAck(touch, &touch_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
viz_tracker()->OnGpuSwapBuffersCompleted(touch_latency);
}
// UKM metrics.
total_ukm_entry_count++;
ExpectUkmReported(
source_id, "Event.ScrollBegin.Touch",
{"TimeToScrollUpdateSwapBegin", "TimeToHandled", "IsMainThread"},
total_ukm_entry_count);
// UMA histograms.
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin."
"TimeToScrollUpdateSwapBegin2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate."
"TimeToScrollUpdateSwapBegin2",
0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Touch.TimeToScrollUpdateSwapBegin4", 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin4", 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Touch.TimeToHandled2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Touch.TimeToHandled2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Touch.HandledToRendererSwap2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Touch.HandledToRendererSwap2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Touch."
"RendererSwapToBrowserNotified2",
1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Touch."
"BrowserNotifiedToBeforeGpuSwap2",
1));
EXPECT_TRUE(HistogramSizeEq("Event.Latency.ScrollBegin.Touch.GpuSwap2", 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.TimeToHandled2_Main", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.TimeToHandled2_Impl", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.HandledToRendererSwap2_Main", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.HandledToRendererSwap2_Impl", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.RendererSwapToBrowserNotified2", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.BrowserNotifiedToBeforeGpuSwap2", 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.Touch.GpuSwap2", 0));
}
}
TEST_F(RenderWidgetHostLatencyTrackerTest, TestTouchToScrollHistograms) {
const GURL url(kUrl);
contents()->NavigateAndCommit(url);
size_t total_ukm_entry_count = 0;
ukm::SourceId source_id = static_cast<WebContentsImpl*>(contents())
->GetUkmSourceIdForLastCommittedSource();
EXPECT_NE(ukm::kInvalidSourceId, source_id);
for (bool rendering_on_main : {false, true}) {
ResetHistograms();
{
auto scroll = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
5.f, -5.f, 0, blink::WebGestureDevice::kTouchscreen);
base::TimeTicks now = base::TimeTicks::Now();
scroll.SetTimeStamp(now);
ui::LatencyInfo scroll_latency;
AddFakeComponentsWithTimeStamp(*tracker(), &scroll_latency, now);
AddRenderingScheduledComponent(&scroll_latency, rendering_on_main, now);
tracker()->OnInputEvent(scroll, &scroll_latency);
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr));
tracker()->OnInputEventAck(scroll, &scroll_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
}
{
SyntheticWebTouchEvent touch;
touch.PressPoint(0, 0);
touch.PressPoint(1, 1);
ui::LatencyInfo touch_latency(ui::SourceEventType::TOUCH);
base::TimeTicks now = base::TimeTicks::Now();
touch_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, now, 1);
touch_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT, now, 1);
AddFakeComponentsWithTimeStamp(*tracker(), &touch_latency, now);
AddRenderingScheduledComponent(&touch_latency, rendering_on_main, now);
tracker()->OnInputEvent(touch, &touch_latency);
EXPECT_TRUE(touch_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(touch_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr));
tracker()->OnInputEventAck(touch, &touch_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
viz_tracker()->OnGpuSwapBuffersCompleted(touch_latency);
}
// UKM metrics.
total_ukm_entry_count++;
ExpectUkmReported(
source_id, "Event.ScrollUpdate.Touch",
{"TimeToScrollUpdateSwapBegin", "TimeToHandled", "IsMainThread"},
total_ukm_entry_count);
// UMA histograms.
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin."
"TimeToScrollUpdateSwapBegin2",
0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate."
"TimeToScrollUpdateSwapBegin2",
1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Touch.TimeToScrollUpdateSwapBegin4", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin4", 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Touch.TimeToHandled2_Main", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Touch.TimeToHandled2_Impl", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Touch.HandledToRendererSwap2_Main", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollBegin.Touch.HandledToRendererSwap2_Impl", 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Touch."
"RendererSwapToBrowserNotified2",
0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollBegin.Touch."
"BrowserNotifiedToBeforeGpuSwap2",
0));
EXPECT_TRUE(HistogramSizeEq("Event.Latency.ScrollBegin.Touch.GpuSwap2", 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.Touch.TimeToHandled2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.Touch.TimeToHandled2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.HandledToRendererSwap2_Main",
rendering_on_main ? 1 : 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.HandledToRendererSwap2_Impl",
rendering_on_main ? 0 : 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.RendererSwapToBrowserNotified2", 1));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.Touch.BrowserNotifiedToBeforeGpuSwap2", 1));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.Touch.GpuSwap2", 1));
}
}
TEST_F(RenderWidgetHostLatencyTrackerTest,
LatencyTerminatedOnAckIfRenderingNotScheduled) {
{
auto scroll = SyntheticWebGestureEventBuilder::BuildScrollBegin(
5.f, -5.f, blink::WebGestureDevice::kTouchscreen);
ui::LatencyInfo scroll_latency;
AddFakeComponents(*tracker(), &scroll_latency);
// Don't include the rendering schedule component, since we're testing the
// case where rendering isn't scheduled.
tracker()->OnInputEvent(scroll, &scroll_latency);
tracker()->OnInputEventAck(scroll, &scroll_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(scroll_latency.terminated());
}
{
auto wheel = SyntheticWebMouseWheelEventBuilder::Build(
blink::WebMouseWheelEvent::kPhaseChanged);
ui::LatencyInfo wheel_latency;
wheel_latency.set_source_event_type(ui::SourceEventType::WHEEL);
AddFakeComponents(*tracker(), &wheel_latency);
tracker()->OnInputEvent(wheel, &wheel_latency);
tracker()->OnInputEventAck(wheel, &wheel_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(wheel_latency.terminated());
}
{
SyntheticWebTouchEvent touch;
touch.PressPoint(0, 0);
ui::LatencyInfo touch_latency;
touch_latency.set_source_event_type(ui::SourceEventType::TOUCH);
AddFakeComponents(*tracker(), &touch_latency);
tracker()->OnInputEvent(touch, &touch_latency);
tracker()->OnInputEventAck(touch, &touch_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(touch_latency.terminated());
}
{
auto mouse_move =
SyntheticWebMouseEventBuilder::Build(blink::WebMouseEvent::kMouseMove);
ui::LatencyInfo mouse_latency;
AddFakeComponents(*tracker(), &mouse_latency);
tracker()->OnInputEvent(mouse_move, &mouse_latency);
tracker()->OnInputEventAck(mouse_move, &mouse_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(mouse_latency.terminated());
}
{
auto key_event =
SyntheticWebKeyboardEventBuilder::Build(blink::WebKeyboardEvent::kChar);
ui::LatencyInfo key_latency;
key_latency.set_source_event_type(ui::SourceEventType::KEY_PRESS);
AddFakeComponents(*tracker(), &key_latency);
tracker()->OnInputEvent(key_event, &key_latency);
tracker()->OnInputEventAck(key_event, &key_latency,
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(key_latency.terminated());
}
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.TouchToHandled_Main", 0));
EXPECT_TRUE(
HistogramSizeEq("Event.Latency.ScrollUpdate.TouchToHandled_Impl", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.HandledToRendererSwap_Main", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.HandledToRendererSwap_Impl", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.RendererSwapToBrowserNotified", 0));
EXPECT_TRUE(HistogramSizeEq(
"Event.Latency.ScrollUpdate.BrowserNotifiedToBeforeGpuSwap", 0));
EXPECT_TRUE(HistogramSizeEq("Event.Latency.ScrollUpdate.GpuSwap", 0));
}
TEST_F(RenderWidgetHostLatencyTrackerTest, LatencyTerminatedOnAckIfGSUIgnored) {
for (blink::WebGestureDevice source_device :
{blink::WebGestureDevice::kTouchscreen,
blink::WebGestureDevice::kTouchpad}) {
for (bool rendering_on_main : {false, true}) {
auto scroll = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
5.f, -5.f, 0, source_device);
base::TimeTicks now = base::TimeTicks::Now();
scroll.SetTimeStamp(now);
ui::LatencyInfo scroll_latency;
scroll_latency.set_source_event_type(
source_device == blink::WebGestureDevice::kTouchscreen
? ui::SourceEventType::TOUCH
: ui::SourceEventType::WHEEL);
AddFakeComponentsWithTimeStamp(*tracker(), &scroll_latency, now);
AddRenderingScheduledComponent(&scroll_latency, rendering_on_main, now);
tracker()->OnInputEvent(scroll, &scroll_latency);
tracker()->OnInputEventAck(scroll, &scroll_latency,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
EXPECT_TRUE(scroll_latency.terminated());
}
}
}
TEST_F(RenderWidgetHostLatencyTrackerTest, ScrollLatency) {
auto scroll_begin = SyntheticWebGestureEventBuilder::BuildScrollBegin(
5, -5, blink::WebGestureDevice::kTouchscreen);
ui::LatencyInfo scroll_latency;
scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
tracker()->OnInputEvent(scroll_begin, &scroll_latency);
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_EQ(2U, scroll_latency.latency_components().size());
// The first GestureScrollUpdate should be provided with
// INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT.
auto first_scroll_update = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
5.f, -5.f, 0, blink::WebGestureDevice::kTouchscreen);
scroll_latency = ui::LatencyInfo();
scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
tracker()->OnInputEvent(first_scroll_update, &scroll_latency);
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, nullptr));
EXPECT_FALSE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, nullptr));
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT, nullptr));
EXPECT_EQ(4U, scroll_latency.latency_components().size());
// Subsequent GestureScrollUpdates should be provided with
// INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT.
auto scroll_update = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
-5.f, 5.f, 0, blink::WebGestureDevice::kTouchscreen);
scroll_latency = ui::LatencyInfo();
scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
tracker()->OnInputEvent(scroll_update, &scroll_latency);
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_FALSE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, nullptr));
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, nullptr));
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT, nullptr));
EXPECT_EQ(4U, scroll_latency.latency_components().size());
}
TEST_F(RenderWidgetHostLatencyTrackerTest, TouchBlockingAndQueueingTime) {
// These numbers are sensitive to where the histogram buckets are.
int touchstart_timestamps_ms[] = {11, 25, 35};
int touchmove_timestamps_ms[] = {1, 5, 12};
int touchend_timestamps_ms[] = {3, 8, 12};
for (InputEventAckState blocking :
{INPUT_EVENT_ACK_STATE_NOT_CONSUMED, INPUT_EVENT_ACK_STATE_CONSUMED}) {
SyntheticWebTouchEvent event;
{
// Touch start.
event.PressPoint(1, 1);
ui::LatencyInfo latency;
latency.set_source_event_type(ui::SourceEventType::TOUCH);
tracker()->OnInputEvent(event, &latency);
ui::LatencyInfo fake_latency;
fake_latency.set_trace_id(kTraceEventId);
fake_latency.set_source_event_type(ui::SourceEventType::TOUCH);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchstart_timestamps_ms[0]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchstart_timestamps_ms[1]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchstart_timestamps_ms[2]),
1);
// Call ComputeInputLatencyHistograms directly to avoid OnInputEventAck
// overwriting components.
tracker()->ComputeInputLatencyHistograms(event.GetType(), fake_latency,
blocking);
tracker()->OnInputEventAck(event, &latency,
blocking);
}
{
// Touch move.
ui::LatencyInfo latency;
latency.set_source_event_type(ui::SourceEventType::TOUCH);
event.MovePoint(0, 20, 20);
tracker()->OnInputEvent(event, &latency);
EXPECT_TRUE(latency.FindLatency(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr));
EXPECT_TRUE(latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_EQ(2U, latency.latency_components().size());
ui::LatencyInfo fake_latency;
fake_latency.set_trace_id(kTraceEventId);
fake_latency.set_source_event_type(ui::SourceEventType::TOUCH);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchmove_timestamps_ms[0]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchmove_timestamps_ms[1]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchmove_timestamps_ms[2]),
1);
// Call ComputeInputLatencyHistograms directly to avoid OnInputEventAck
// overwriting components.
tracker()->ComputeInputLatencyHistograms(event.GetType(), fake_latency,
blocking);
}
{
// Touch end.
ui::LatencyInfo latency;
latency.set_source_event_type(ui::SourceEventType::TOUCH);
event.ReleasePoint(0);
tracker()->OnInputEvent(event, &latency);
EXPECT_TRUE(latency.FindLatency(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr));
EXPECT_TRUE(latency.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
EXPECT_EQ(2U, latency.latency_components().size());
ui::LatencyInfo fake_latency;
fake_latency.set_trace_id(kTraceEventId);
fake_latency.set_source_event_type(ui::SourceEventType::TOUCH);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchend_timestamps_ms[0]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchend_timestamps_ms[1]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchend_timestamps_ms[2]),
1);
// Call ComputeInputLatencyHistograms directly to avoid OnInputEventAck
// overwriting components.
tracker()->ComputeInputLatencyHistograms(event.GetType(), fake_latency,
blocking);
}
}
// Touch start.
EXPECT_THAT(
histogram_tester().GetAllSamples(
"Event.Latency.QueueingTime.TouchStartDefaultPrevented"),
ElementsAre(Bucket(
touchstart_timestamps_ms[1] - touchstart_timestamps_ms[0], 1)));
EXPECT_THAT(
histogram_tester().GetAllSamples(
"Event.Latency.QueueingTime.TouchStartDefaultAllowed"),
ElementsAre(Bucket(
touchstart_timestamps_ms[1] - touchstart_timestamps_ms[0], 1)));
EXPECT_THAT(
histogram_tester().GetAllSamples(
"Event.Latency.BlockingTime.TouchStartDefaultPrevented"),
ElementsAre(Bucket(
touchstart_timestamps_ms[2] - touchstart_timestamps_ms[1], 1)));
EXPECT_THAT(
histogram_tester().GetAllSamples(
"Event.Latency.BlockingTime.TouchStartDefaultAllowed"),
ElementsAre(Bucket(
touchstart_timestamps_ms[2] - touchstart_timestamps_ms[1], 1)));
// Touch move.
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.QueueingTime.TouchMoveDefaultPrevented"),
ElementsAre(Bucket(
touchmove_timestamps_ms[1] - touchmove_timestamps_ms[0], 1)));
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.QueueingTime.TouchMoveDefaultAllowed"),
ElementsAre(Bucket(
touchmove_timestamps_ms[1] - touchmove_timestamps_ms[0], 1)));
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.BlockingTime.TouchMoveDefaultPrevented"),
ElementsAre(Bucket(
touchmove_timestamps_ms[2] - touchmove_timestamps_ms[1], 1)));
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.BlockingTime.TouchMoveDefaultAllowed"),
ElementsAre(Bucket(
touchmove_timestamps_ms[2] - touchmove_timestamps_ms[1], 1)));
// Touch end.
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.QueueingTime.TouchEndDefaultPrevented"),
ElementsAre(Bucket(
touchend_timestamps_ms[1] - touchend_timestamps_ms[0], 1)));
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.QueueingTime.TouchEndDefaultAllowed"),
ElementsAre(Bucket(
touchend_timestamps_ms[1] - touchend_timestamps_ms[0], 1)));
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.BlockingTime.TouchEndDefaultPrevented"),
ElementsAre(Bucket(
touchend_timestamps_ms[2] - touchend_timestamps_ms[1], 1)));
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.BlockingTime.TouchEndDefaultAllowed"),
ElementsAre(Bucket(
touchend_timestamps_ms[2] - touchend_timestamps_ms[1], 1)));
}
TEST_F(RenderWidgetHostLatencyTrackerTest, KeyBlockingAndQueueingTime) {
// These numbers are sensitive to where the histogram buckets are.
int event_timestamps_ms[] = {11, 25, 35};
for (InputEventAckState blocking :
{INPUT_EVENT_ACK_STATE_NOT_CONSUMED, INPUT_EVENT_ACK_STATE_CONSUMED}) {
{
NativeWebKeyboardEvent event(blink::WebKeyboardEvent::kRawKeyDown,
blink::WebInputEvent::kNoModifiers,
base::TimeTicks::Now());
ui::LatencyInfo latency_info;
latency_info.set_source_event_type(ui::SourceEventType::KEY_PRESS);
tracker()->OnInputEvent(event, &latency_info);
ui::LatencyInfo fake_latency;
fake_latency.set_trace_id(kTraceEventId);
fake_latency.set_source_event_type(ui::SourceEventType::KEY_PRESS);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(event_timestamps_ms[0]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(event_timestamps_ms[1]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(event_timestamps_ms[2]),
1);
// Call ComputeInputLatencyHistograms directly to avoid OnInputEventAck
// overwriting components.
tracker()->ComputeInputLatencyHistograms(event.GetType(), fake_latency,
blocking);
tracker()->OnInputEventAck(event, &latency_info, blocking);
}
}
EXPECT_THAT(
histogram_tester().GetAllSamples(
"Event.Latency.QueueingTime.KeyPressDefaultPrevented"),
ElementsAre(Bucket(event_timestamps_ms[1] - event_timestamps_ms[0], 1)));
EXPECT_THAT(
histogram_tester().GetAllSamples(
"Event.Latency.QueueingTime.KeyPressDefaultAllowed"),
ElementsAre(Bucket(event_timestamps_ms[1] - event_timestamps_ms[0], 1)));
EXPECT_THAT(
histogram_tester().GetAllSamples(
"Event.Latency.BlockingTime.KeyPressDefaultPrevented"),
ElementsAre(Bucket(event_timestamps_ms[2] - event_timestamps_ms[1], 1)));
EXPECT_THAT(
histogram_tester().GetAllSamples(
"Event.Latency.BlockingTime.KeyPressDefaultAllowed"),
ElementsAre(Bucket(event_timestamps_ms[2] - event_timestamps_ms[1], 1)));
}
TEST_F(RenderWidgetHostLatencyTrackerTest, KeyEndToEndLatency) {
// These numbers are sensitive to where the histogram buckets are.
int event_timestamps_microseconds[] = {11, 24};
ui::LatencyInfo latency_info;
latency_info.set_trace_id(kTraceEventId);
latency_info.set_source_event_type(ui::SourceEventType::KEY_PRESS);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[0]),
1);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[0]),
1);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[1]),
1);
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[1]),
1);
viz_tracker()->OnGpuSwapBuffersCompleted(latency_info);
EXPECT_THAT(
histogram_tester().GetAllSamples("Event.Latency.EndToEnd.KeyPress"),
ElementsAre(Bucket(
event_timestamps_microseconds[1] - event_timestamps_microseconds[0],
1)));
}
// Event.Latency.(Queueing|Blocking)Time.* histograms shouldn't be reported for
// multi-finger touch.
TEST_F(RenderWidgetHostLatencyTrackerTest,
MultiFingerTouchIgnoredForQueueingAndBlockingTimeMetrics) {
SyntheticWebTouchEvent event;
InputEventAckState ack_state = INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
{
// First touch start.
ui::LatencyInfo latency;
event.PressPoint(1, 1);
tracker()->OnInputEvent(event, &latency);
tracker()->OnInputEventAck(event, &latency, ack_state);
}
{
// Additional touch start will be ignored for queueing and blocking time
// metrics.
int touchstart_timestamps_ms[] = {11, 25, 35};
ui::LatencyInfo latency;
event.PressPoint(1, 1);
tracker()->OnInputEvent(event, &latency);
ui::LatencyInfo fake_latency;
fake_latency.set_trace_id(kTraceEventId);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchstart_timestamps_ms[0]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchstart_timestamps_ms[1]),
1);
fake_latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(touchstart_timestamps_ms[2]),
1);
// Call ComputeInputLatencyHistograms directly to avoid OnInputEventAck
// overwriting components.
tracker()->ComputeInputLatencyHistograms(event.GetType(),
fake_latency, ack_state);
tracker()->OnInputEventAck(event, &latency, ack_state);
}
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.QueueingTime.TouchStartDefaultAllowed"),
ElementsAre());
}
TEST_F(RenderWidgetHostLatencyTrackerTest, TouchpadPinchEvents) {
ui::LatencyInfo latency;
latency.set_trace_id(kTraceEventId);
latency.set_source_event_type(ui::SourceEventType::TOUCHPAD);
latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
base::TimeTicks() + base::TimeDelta::FromMilliseconds(1), 1);
latency.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
base::TimeTicks() + base::TimeDelta::FromMilliseconds(3), 1);
AddFakeComponentsWithTimeStamp(
*tracker(), &latency,
base::TimeTicks() + base::TimeDelta::FromMilliseconds(5));
viz_tracker()->OnGpuSwapBuffersCompleted(latency);
EXPECT_TRUE(HistogramSizeEq("Event.Latency.EventToRender.TouchpadPinch", 1));
EXPECT_TRUE(HistogramSizeEq("Event.Latency.EndToEnd.TouchpadPinch", 1));
}
} // namespace content