Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(938)

Side by Side Diff: content/browser/renderer_host/input/render_widget_host_latency_tracker.cc

Issue 2771053003: WIP: Plumbing input event latency reporting through Mus GPU.
Patch Set: NON_EXPORTED_BASE Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/input/render_widget_host_latency_tracker .h" 5 #include "content/browser/renderer_host/input/render_widget_host_latency_tracker .h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/histogram_functions.h" 10 #include "base/metrics/histogram_functions.h"
11 #include "base/metrics/histogram_macros.h" 11 #include "base/metrics/histogram_macros.h"
12 #include "build/build_config.h" 12 #include "build/build_config.h"
13 #include "components/rappor/public/rappor_utils.h" 13 #include "components/rappor/public/rappor_utils.h"
14 #include "content/browser/renderer_host/render_widget_host_delegate.h" 14 #include "content/browser/renderer_host/render_widget_host_delegate.h"
15 #include "content/public/browser/content_browser_client.h" 15 #include "content/public/browser/content_browser_client.h"
16 #include "content/public/common/content_client.h" 16 #include "content/public/common/content_client.h"
17 #include "ui/events/blink/web_input_event_traits.h" 17 #include "ui/events/blink/web_input_event_traits.h"
18 #include "ui/latency/latency_histogram_macros.h"
18 19
19 using blink::WebGestureEvent; 20 using blink::WebGestureEvent;
20 using blink::WebInputEvent; 21 using blink::WebInputEvent;
21 using blink::WebMouseEvent; 22 using blink::WebMouseEvent;
22 using blink::WebMouseWheelEvent; 23 using blink::WebMouseWheelEvent;
23 using blink::WebTouchEvent; 24 using blink::WebTouchEvent;
24 using ui::LatencyInfo; 25 using ui::LatencyInfo;
25 26
26 namespace content { 27 namespace content {
27 namespace { 28 namespace {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 latency, device_scale_factor); 72 latency, device_scale_factor);
72 } else if (WebInputEvent::isTouchEventType(event.type())) { 73 } else if (WebInputEvent::isTouchEventType(event.type())) {
73 UpdateLatencyCoordinatesImpl(static_cast<const WebTouchEvent&>(event), 74 UpdateLatencyCoordinatesImpl(static_cast<const WebTouchEvent&>(event),
74 latency, device_scale_factor); 75 latency, device_scale_factor);
75 } else if (event.type() == WebInputEvent::MouseWheel) { 76 } else if (event.type() == WebInputEvent::MouseWheel) {
76 UpdateLatencyCoordinatesImpl(static_cast<const WebMouseWheelEvent&>(event), 77 UpdateLatencyCoordinatesImpl(static_cast<const WebMouseWheelEvent&>(event),
77 latency, device_scale_factor); 78 latency, device_scale_factor);
78 } 79 }
79 } 80 }
80 81
81 // Check valid timing for start and end latency components.
82 #define CONFIRM_VALID_TIMING(start, end) \
83 DCHECK(!start.first_event_time.is_null()); \
84 DCHECK(!end.last_event_time.is_null()); \
85 DCHECK_GE(end.last_event_time, start.first_event_time);
86
87 // Event latency that is mostly under 1 second. We should only use 100 buckets
88 // when needed.
89 #define UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(name, start, \
90 end) \
91 CONFIRM_VALID_TIMING(start, end) \
92 base::UmaHistogramCustomCounts( \
93 name, (end.last_event_time - start.first_event_time).InMicroseconds(), \
94 1, 1000000, 100);
95
96 #define UMA_HISTOGRAM_INPUT_LATENCY_MILLISECONDS(name, start, end) \
97 CONFIRM_VALID_TIMING(start, end) \
98 base::UmaHistogramCustomCounts( \
99 name, (end.last_event_time - start.first_event_time).InMilliseconds(), \
100 1, 1000, 50);
101
102 // Touch/wheel to scroll latency using Rappor.
103 #define RAPPOR_TOUCH_WHEEL_TO_SCROLL_LATENCY(delegate, name, start, end) \
104 CONFIRM_VALID_TIMING(start, end) \
105 rappor::RapporService* rappor_service = \
106 GetContentClient()->browser()->GetRapporService(); \
107 if (rappor_service && delegate) { \
108 std::unique_ptr<rappor::Sample> sample = \
109 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE); \
110 delegate->AddDomainInfoToRapporSample(sample.get()); \
111 sample->SetUInt64Field( \
112 "Latency", \
113 (end.last_event_time - start.first_event_time).InMicroseconds(), \
114 rappor::NO_NOISE); \
115 rappor_service->RecordSample(name, std::move(sample)); \
116 }
117
118 // Long touch/wheel scroll latency component that is mostly under 200ms.
119 #define UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2(name, start, end) \
120 CONFIRM_VALID_TIMING(start, end) \
121 base::Histogram::FactoryGet(name, 1000, 200000, 50, \
122 base::HistogramBase::kUmaTargetedHistogramFlag) \
123 ->Add((end.last_event_time - start.first_event_time).InMicroseconds());
124
125 // Short touch/wheel scroll latency component that is mostly under 50ms.
126 #define UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2(name, start, end) \
127 CONFIRM_VALID_TIMING(start, end) \
128 base::Histogram::FactoryGet(name, 1, 50000, 50, \
129 base::HistogramBase::kUmaTargetedHistogramFlag) \
130 ->Add((end.last_event_time - start.first_event_time).InMicroseconds());
131
132 std::string LatencySourceEventTypeToInputModalityString(
133 ui::SourceEventType type) {
134 switch (type) {
135 case ui::SourceEventType::WHEEL:
136 return "Wheel";
137 case ui::SourceEventType::TOUCH:
138 return "Touch";
139 default:
140 return "";
141 }
142 }
143
144 std::string WebInputEventTypeToInputModalityString(WebInputEvent::Type type) { 82 std::string WebInputEventTypeToInputModalityString(WebInputEvent::Type type) {
145 if (type == blink::WebInputEvent::MouseWheel) { 83 if (type == blink::WebInputEvent::MouseWheel) {
146 return "Wheel"; 84 return "Wheel";
147 } else if (WebInputEvent::isKeyboardEventType(type)) { 85 } else if (WebInputEvent::isKeyboardEventType(type)) {
148 return "Key"; 86 return "Key";
149 } else if (WebInputEvent::isMouseEventType(type)) { 87 } else if (WebInputEvent::isMouseEventType(type)) {
150 return "Mouse"; 88 return "Mouse";
151 } else if (WebInputEvent::isTouchEventType(type)) { 89 } else if (WebInputEvent::isTouchEventType(type)) {
152 return "Touch"; 90 return "Touch";
153 } 91 }
154 return ""; 92 return "";
155 } 93 }
156 94
157 void ComputeScrollLatencyHistograms(
158 const LatencyInfo::LatencyComponent& gpu_swap_begin_component,
159 const LatencyInfo::LatencyComponent& gpu_swap_end_component,
160 int64_t latency_component_id,
161 const LatencyInfo& latency) {
162 DCHECK(!latency.coalesced());
163 if (latency.coalesced())
164 return;
165
166 DCHECK(!gpu_swap_begin_component.event_time.is_null());
167 DCHECK(!gpu_swap_end_component.event_time.is_null());
168 LatencyInfo::LatencyComponent original_component;
169 if (latency.FindLatency(
170 ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
171 latency_component_id, &original_component)) {
172 // This UMA metric tracks the time between the final frame swap for the
173 // first scroll event in a sequence and the original timestamp of that
174 // scroll event's underlying touch event.
175 for (size_t i = 0; i < original_component.event_count; i++) {
176 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
177 "Event.Latency.TouchToFirstScrollUpdateSwapBegin",
178 original_component, gpu_swap_begin_component);
179 }
180 } else if (!latency.FindLatency(
181 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
182 latency_component_id, &original_component)) {
183 return;
184 }
185
186 // This UMA metric tracks the time from when the original touch event is
187 // created to when the scroll gesture results in final frame swap.
188 for (size_t i = 0; i < original_component.event_count; i++) {
189 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
190 "Event.Latency.TouchToScrollUpdateSwapBegin", original_component,
191 gpu_swap_begin_component);
192 }
193 }
194
195 void ComputeTouchAndWheelScrollLatencyHistograms(
196 RenderWidgetHostDelegate* render_widget_host_delegate,
197 const ui::LatencyInfo::LatencyComponent& gpu_swap_begin_component,
198 const ui::LatencyInfo::LatencyComponent& gpu_swap_end_component,
199 int64_t latency_component_id,
200 const ui::LatencyInfo& latency) {
201 DCHECK(!latency.coalesced());
202 if (latency.coalesced())
203 return;
204
205 LatencyInfo::LatencyComponent original_component;
206 std::string scroll_name = "ScrollUpdate";
207
208 const std::string input_modality =
209 LatencySourceEventTypeToInputModalityString(latency.source_event_type());
210
211 if (latency.FindLatency(
212 ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
213 latency_component_id, &original_component)) {
214 scroll_name = "ScrollBegin";
215 // This UMA metric tracks the time between the final frame swap for the
216 // first scroll event in a sequence and the original timestamp of that
217 // scroll event's underlying touch/wheel event.
218 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
219 "Event.Latency.ScrollBegin." + input_modality +
220 ".TimeToScrollUpdateSwapBegin2",
221 original_component, gpu_swap_begin_component);
222
223 RAPPOR_TOUCH_WHEEL_TO_SCROLL_LATENCY(
224 render_widget_host_delegate,
225 "Event.Latency.ScrollBegin." + input_modality +
226 ".TimeToScrollUpdateSwapBegin2",
227 original_component, gpu_swap_begin_component);
228
229 // TODO(lanwei): Will remove them when M56 is stable, see
230 // https://crbug.com/669618.
231 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
232 "Event.Latency.ScrollUpdate." + input_modality +
233 ".TimeToFirstScrollUpdateSwapBegin2",
234 original_component, gpu_swap_begin_component);
235 } else if (latency.FindLatency(
236 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
237 latency_component_id, &original_component)) {
238 // This UMA metric tracks the time from when the original touch event is
239 // created to when the scroll gesture results in final frame swap.
240 // First scroll events are excluded from this metric.
241 if (input_modality == "Touch") {
242 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
243 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2",
244 original_component, gpu_swap_begin_component);
245
246 RAPPOR_TOUCH_WHEEL_TO_SCROLL_LATENCY(
247 render_widget_host_delegate,
248 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2",
249 original_component, gpu_swap_begin_component);
250 }
251 } else {
252 // No original component found.
253 return;
254 }
255
256 LatencyInfo::LatencyComponent rendering_scheduled_component;
257 bool rendering_scheduled_on_main = latency.FindLatency(
258 ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT, 0,
259 &rendering_scheduled_component);
260 if (!rendering_scheduled_on_main) {
261 if (!latency.FindLatency(
262 ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT, 0,
263 &rendering_scheduled_component))
264 return;
265 }
266
267 const std::string thread_name = rendering_scheduled_on_main ? "Main" : "Impl";
268
269 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2(
270 "Event.Latency." + scroll_name + "." + input_modality +
271 ".TimeToHandled2_" + thread_name,
272 original_component, rendering_scheduled_component);
273
274 LatencyInfo::LatencyComponent renderer_swap_component;
275 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0,
276 &renderer_swap_component))
277 return;
278
279 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2(
280 "Event.Latency." + scroll_name + "." + input_modality +
281 ".HandledToRendererSwap2_" + thread_name,
282 rendering_scheduled_component, renderer_swap_component);
283
284 LatencyInfo::LatencyComponent browser_received_swap_component;
285 if (!latency.FindLatency(
286 ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0,
287 &browser_received_swap_component))
288 return;
289
290 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2(
291 "Event.Latency." + scroll_name + "." + input_modality +
292 ".RendererSwapToBrowserNotified2",
293 renderer_swap_component, browser_received_swap_component);
294
295 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2(
296 "Event.Latency." + scroll_name + "." + input_modality +
297 ".BrowserNotifiedToBeforeGpuSwap2",
298 browser_received_swap_component, gpu_swap_begin_component);
299
300 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2(
301 "Event.Latency." + scroll_name + "." + input_modality + ".GpuSwap2",
302 gpu_swap_begin_component, gpu_swap_end_component);
303 }
304 // LatencyComponents generated in the renderer must have component IDs 95 // LatencyComponents generated in the renderer must have component IDs
305 // provided to them by the browser process. This function adds the correct 96 // provided to them by the browser process. This function adds the correct
306 // component ID where necessary. 97 // component ID where necessary.
307 void AddLatencyInfoComponentIds(LatencyInfo* latency, 98 void AddLatencyInfoComponentIds(LatencyInfo* latency,
308 int64_t latency_component_id) { 99 int64_t latency_component_id) {
309 std::vector<std::pair<ui::LatencyComponentType, int64_t>> new_components_key; 100 std::vector<std::pair<ui::LatencyComponentType, int64_t>> new_components_key;
310 std::vector<LatencyInfo::LatencyComponent> new_components_value; 101 std::vector<LatencyInfo::LatencyComponent> new_components_value;
311 for (const auto& lc : latency->latency_components()) { 102 for (const auto& lc : latency->latency_components()) {
312 ui::LatencyComponentType component_type = lc.first.first; 103 ui::LatencyComponentType component_type = lc.first.first;
313 if (component_type == ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT) { 104 if (component_type == ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT) {
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 ComputeInputLatencyHistograms(event.type(), latency_component_id_, *latency, 329 ComputeInputLatencyHistograms(event.type(), latency_component_id_, *latency,
539 ack_result); 330 ack_result);
540 } 331 }
541 332
542 void RenderWidgetHostLatencyTracker::OnSwapCompositorFrame( 333 void RenderWidgetHostLatencyTracker::OnSwapCompositorFrame(
543 std::vector<LatencyInfo>* latencies) { 334 std::vector<LatencyInfo>* latencies) {
544 DCHECK(latencies); 335 DCHECK(latencies);
545 for (LatencyInfo& latency : *latencies) { 336 for (LatencyInfo& latency : *latencies) {
546 AddLatencyInfoComponentIds(&latency, latency_component_id_); 337 AddLatencyInfoComponentIds(&latency, latency_component_id_);
547 latency.AddLatencyNumber( 338 latency.AddLatencyNumber(
548 ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0, 0); 339 ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, 0, 0);
549 } 340 }
550 } 341 }
551 342
552 void RenderWidgetHostLatencyTracker::OnGpuSwapBuffersCompleted(
553 const LatencyInfo& latency) {
554 LatencyInfo::LatencyComponent gpu_swap_end_component;
555 if (!latency.FindLatency(
556 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0,
557 &gpu_swap_end_component)) {
558 return;
559 }
560
561 LatencyInfo::LatencyComponent gpu_swap_begin_component;
562 if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0,
563 &gpu_swap_begin_component)) {
564 return;
565 }
566
567 LatencyInfo::LatencyComponent tab_switch_component;
568 if (latency.FindLatency(ui::TAB_SHOW_COMPONENT, latency_component_id_,
569 &tab_switch_component)) {
570 base::TimeDelta delta =
571 gpu_swap_end_component.event_time - tab_switch_component.event_time;
572 for (size_t i = 0; i < tab_switch_component.event_count; i++) {
573 UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta);
574 }
575 }
576
577 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
578 latency_component_id_, nullptr)) {
579 return;
580 }
581
582 ui::SourceEventType source_event_type = latency.source_event_type();
583 if (source_event_type == ui::SourceEventType::WHEEL ||
584 source_event_type == ui::SourceEventType::TOUCH) {
585 ComputeTouchAndWheelScrollLatencyHistograms(
586 render_widget_host_delegate_, gpu_swap_begin_component,
587 gpu_swap_end_component, latency_component_id_, latency);
588 }
589
590 // Compute the old scroll update latency metrics. They are exclusively
591 // calculated for touch scrolls, and will be deprecated on M56.
592 // (https://crbug.com/649754)
593 LatencyInfo::LatencyComponent mouse_wheel_scroll_update_component;
594 if (!latency.FindLatency(
595 ui::INPUT_EVENT_LATENCY_GENERATE_SCROLL_UPDATE_FROM_MOUSE_WHEEL, 0,
596 &mouse_wheel_scroll_update_component)) {
597 ComputeScrollLatencyHistograms(gpu_swap_begin_component,
598 gpu_swap_end_component,
599 latency_component_id_, latency);
600 }
601 }
602
603 void RenderWidgetHostLatencyTracker::SetDelegate( 343 void RenderWidgetHostLatencyTracker::SetDelegate(
604 RenderWidgetHostDelegate* delegate) { 344 RenderWidgetHostDelegate* delegate) {
605 render_widget_host_delegate_ = delegate; 345 render_widget_host_delegate_ = delegate;
606 } 346 }
607 347
348 void RenderWidgetHostLatencyTracker::ReportRapporScrollLatency(
349 const std::string& name,
350 const LatencyInfo::LatencyComponent& start_component,
351 const LatencyInfo::LatencyComponent& end_component) {
352 CONFIRM_VALID_TIMING(start_component, end_component)
353 rappor::RapporService* rappor_service =
354 GetContentClient()->browser()->GetRapporService();
355 if (rappor_service && render_widget_host_delegate_) {
356 std::unique_ptr<rappor::Sample> sample =
357 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE);
358 render_widget_host_delegate_->AddDomainInfoToRapporSample(sample.get());
359 sample->SetUInt64Field(
360 "Latency",
361 (end_component.last_event_time - start_component.first_event_time)
362 .InMicroseconds(),
363 rappor::NO_NOISE);
364 rappor_service->RecordSample(name, std::move(sample));
365 }
366 }
367
608 } // namespace content 368 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698