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

Side by Side Diff: ui/latency/latency_tracker.cc

Issue 2814483002: Splitting up RenderWidgetHostLatencyTracker and some renames. (Closed)
Patch Set: [Moving OnGpuSwapBuffersCompleted() back up. 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
« no previous file with comments | « ui/latency/latency_tracker.h ('k') | ui/latency/mojo/latency_info.mojom » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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 "ui/latency/latency_tracker.h"
6 6
7 #include <stddef.h>
8
9 #include "base/logging.h"
10 #include "base/metrics/histogram_functions.h" 7 #include "base/metrics/histogram_functions.h"
11 #include "base/metrics/histogram_macros.h" 8 #include "base/metrics/histogram_macros.h"
12 #include "build/build_config.h" 9 #include "ui/latency/latency_histogram_macros.h"
13 #include "components/rappor/public/rappor_utils.h"
14 #include "content/browser/renderer_host/render_widget_host_delegate.h"
15 #include "content/public/browser/content_browser_client.h"
16 #include "content/public/common/content_client.h"
17 #include "ui/events/blink/web_input_event_traits.h"
18 10
19 using blink::WebGestureEvent; 11 namespace ui {
20 using blink::WebInputEvent;
21 using blink::WebMouseEvent;
22 using blink::WebMouseWheelEvent;
23 using blink::WebTouchEvent;
24 using ui::LatencyInfo;
25
26 namespace content {
27 namespace { 12 namespace {
28 13
29 void UpdateLatencyCoordinatesImpl(const blink::WebTouchEvent& touch,
30 LatencyInfo* latency,
31 float device_scale_factor) {
32 for (uint32_t i = 0; i < touch.touches_length; ++i) {
33 gfx::PointF coordinate(touch.touches[i].position.x * device_scale_factor,
34 touch.touches[i].position.y * device_scale_factor);
35 if (!latency->AddInputCoordinate(coordinate))
36 break;
37 }
38 }
39
40 void UpdateLatencyCoordinatesImpl(const WebGestureEvent& gesture,
41 LatencyInfo* latency,
42 float device_scale_factor) {
43 latency->AddInputCoordinate(gfx::PointF(gesture.x * device_scale_factor,
44 gesture.y * device_scale_factor));
45 }
46
47 void UpdateLatencyCoordinatesImpl(const WebMouseEvent& mouse,
48 LatencyInfo* latency,
49 float device_scale_factor) {
50 latency->AddInputCoordinate(
51 gfx::PointF(mouse.PositionInWidget().x * device_scale_factor,
52 mouse.PositionInWidget().y * device_scale_factor));
53 }
54
55 void UpdateLatencyCoordinatesImpl(const WebMouseWheelEvent& wheel,
56 LatencyInfo* latency,
57 float device_scale_factor) {
58 latency->AddInputCoordinate(
59 gfx::PointF(wheel.PositionInWidget().x * device_scale_factor,
60 wheel.PositionInWidget().y * device_scale_factor));
61 }
62
63 void UpdateLatencyCoordinates(const WebInputEvent& event,
64 float device_scale_factor,
65 LatencyInfo* latency) {
66 if (WebInputEvent::IsMouseEventType(event.GetType())) {
67 UpdateLatencyCoordinatesImpl(static_cast<const WebMouseEvent&>(event),
68 latency, device_scale_factor);
69 } else if (WebInputEvent::IsGestureEventType(event.GetType())) {
70 UpdateLatencyCoordinatesImpl(static_cast<const WebGestureEvent&>(event),
71 latency, device_scale_factor);
72 } else if (WebInputEvent::IsTouchEventType(event.GetType())) {
73 UpdateLatencyCoordinatesImpl(static_cast<const WebTouchEvent&>(event),
74 latency, device_scale_factor);
75 } else if (event.GetType() == WebInputEvent::kMouseWheel) {
76 UpdateLatencyCoordinatesImpl(static_cast<const WebMouseWheelEvent&>(event),
77 latency, device_scale_factor);
78 }
79 }
80
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( 14 std::string LatencySourceEventTypeToInputModalityString(
133 ui::SourceEventType type) { 15 ui::SourceEventType type) {
134 switch (type) { 16 switch (type) {
135 case ui::SourceEventType::WHEEL: 17 case ui::SourceEventType::WHEEL:
136 return "Wheel"; 18 return "Wheel";
137 case ui::SourceEventType::TOUCH: 19 case ui::SourceEventType::TOUCH:
138 return "Touch"; 20 return "Touch";
139 default: 21 default:
140 return ""; 22 return "";
141 } 23 }
142 } 24 }
143 25
144 std::string WebInputEventTypeToInputModalityString(WebInputEvent::Type type) {
145 if (type == blink::WebInputEvent::kMouseWheel) {
146 return "Wheel";
147 } else if (WebInputEvent::IsKeyboardEventType(type)) {
148 return "Key";
149 } else if (WebInputEvent::IsMouseEventType(type)) {
150 return "Mouse";
151 } else if (WebInputEvent::IsTouchEventType(type)) {
152 return "Touch";
153 }
154 return "";
155 }
156
157 void ComputeScrollLatencyHistograms( 26 void ComputeScrollLatencyHistograms(
158 const LatencyInfo::LatencyComponent& gpu_swap_begin_component, 27 const LatencyInfo::LatencyComponent& gpu_swap_begin_component,
159 const LatencyInfo::LatencyComponent& gpu_swap_end_component, 28 const LatencyInfo::LatencyComponent& gpu_swap_end_component,
160 int64_t latency_component_id,
161 const LatencyInfo& latency) { 29 const LatencyInfo& latency) {
162 DCHECK(!latency.coalesced()); 30 DCHECK(!latency.coalesced());
163 if (latency.coalesced()) 31 if (latency.coalesced())
164 return; 32 return;
165 33
166 DCHECK(!gpu_swap_begin_component.event_time.is_null()); 34 DCHECK(!gpu_swap_begin_component.event_time.is_null());
167 DCHECK(!gpu_swap_end_component.event_time.is_null()); 35 DCHECK(!gpu_swap_end_component.event_time.is_null());
168 LatencyInfo::LatencyComponent original_component; 36 LatencyInfo::LatencyComponent original_component;
169 if (latency.FindLatency( 37 if (latency.FindLatency(
170 ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, 38 ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
171 latency_component_id, &original_component)) { 39 &original_component)) {
172 // This UMA metric tracks the time between the final frame swap for the 40 // 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 41 // first scroll event in a sequence and the original timestamp of that
174 // scroll event's underlying touch event. 42 // scroll event's underlying touch event.
175 for (size_t i = 0; i < original_component.event_count; i++) { 43 for (size_t i = 0; i < original_component.event_count; i++) {
176 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( 44 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
177 "Event.Latency.TouchToFirstScrollUpdateSwapBegin", 45 "Event.Latency.TouchToFirstScrollUpdateSwapBegin", original_component,
178 original_component, gpu_swap_begin_component); 46 gpu_swap_begin_component);
179 } 47 }
180 } else if (!latency.FindLatency( 48 } else if (!latency.FindLatency(
181 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, 49 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
182 latency_component_id, &original_component)) { 50 &original_component)) {
183 return; 51 return;
184 } 52 }
185 53
186 // This UMA metric tracks the time from when the original touch event is 54 // 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. 55 // created to when the scroll gesture results in final frame swap.
188 for (size_t i = 0; i < original_component.event_count; i++) { 56 for (size_t i = 0; i < original_component.event_count; i++) {
189 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( 57 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
190 "Event.Latency.TouchToScrollUpdateSwapBegin", original_component, 58 "Event.Latency.TouchToScrollUpdateSwapBegin", original_component,
191 gpu_swap_begin_component); 59 gpu_swap_begin_component);
192 } 60 }
193 } 61 }
194 62
195 void ComputeTouchAndWheelScrollLatencyHistograms( 63 } // namespace
196 RenderWidgetHostDelegate* render_widget_host_delegate, 64
65 void LatencyTracker::OnGpuSwapBuffersCompleted(const LatencyInfo& latency) {
66 LatencyInfo::LatencyComponent gpu_swap_end_component;
67 if (!latency.FindLatency(
68 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0,
69 &gpu_swap_end_component)) {
70 return;
71 }
72
73 LatencyInfo::LatencyComponent gpu_swap_begin_component;
74 if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0,
75 &gpu_swap_begin_component)) {
76 return;
77 }
78
79 LatencyInfo::LatencyComponent tab_switch_component;
80 if (latency.FindLatency(ui::TAB_SHOW_COMPONENT, &tab_switch_component)) {
81 base::TimeDelta delta =
82 gpu_swap_end_component.event_time - tab_switch_component.event_time;
83 for (size_t i = 0; i < tab_switch_component.event_count; i++) {
84 UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta);
85 }
86 }
87
88 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
89 nullptr)) {
90 return;
91 }
92
93 ui::SourceEventType source_event_type = latency.source_event_type();
94 if (source_event_type == ui::SourceEventType::WHEEL ||
95 source_event_type == ui::SourceEventType::TOUCH) {
96 ComputeTouchAndWheelScrollLatencyHistograms(
97 gpu_swap_begin_component, gpu_swap_end_component, latency);
98 }
99
100 // Compute the old scroll update latency metrics. They are exclusively
101 // calculated for touch scrolls, and will be deprecated on M56.
102 // (https://crbug.com/649754)
103 LatencyInfo::LatencyComponent mouse_wheel_scroll_update_component;
104 if (!latency.FindLatency(
105 ui::INPUT_EVENT_LATENCY_GENERATE_SCROLL_UPDATE_FROM_MOUSE_WHEEL, 0,
106 &mouse_wheel_scroll_update_component)) {
107 ComputeScrollLatencyHistograms(gpu_swap_begin_component,
108 gpu_swap_end_component, latency);
109 }
110 }
111
112 void LatencyTracker::ReportRapporScrollLatency(
113 const std::string& name,
114 const LatencyInfo::LatencyComponent& start_component,
115 const LatencyInfo::LatencyComponent& end_component) {}
116
117 void LatencyTracker::ComputeTouchAndWheelScrollLatencyHistograms(
197 const ui::LatencyInfo::LatencyComponent& gpu_swap_begin_component, 118 const ui::LatencyInfo::LatencyComponent& gpu_swap_begin_component,
198 const ui::LatencyInfo::LatencyComponent& gpu_swap_end_component, 119 const ui::LatencyInfo::LatencyComponent& gpu_swap_end_component,
199 int64_t latency_component_id,
200 const ui::LatencyInfo& latency) { 120 const ui::LatencyInfo& latency) {
201 DCHECK(!latency.coalesced()); 121 DCHECK(!latency.coalesced());
202 if (latency.coalesced()) 122 if (latency.coalesced())
203 return; 123 return;
204 124
205 LatencyInfo::LatencyComponent original_component; 125 LatencyInfo::LatencyComponent original_component;
206 std::string scroll_name = "ScrollUpdate"; 126 std::string scroll_name = "ScrollUpdate";
207 127
208 const std::string input_modality = 128 const std::string input_modality =
209 LatencySourceEventTypeToInputModalityString(latency.source_event_type()); 129 LatencySourceEventTypeToInputModalityString(latency.source_event_type());
210 130
211 if (latency.FindLatency( 131 if (latency.FindLatency(
212 ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, 132 ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
213 latency_component_id, &original_component)) { 133 &original_component)) {
214 scroll_name = "ScrollBegin"; 134 scroll_name = "ScrollBegin";
215 // This UMA metric tracks the time between the final frame swap for the 135 // 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 136 // first scroll event in a sequence and the original timestamp of that
217 // scroll event's underlying touch/wheel event. 137 // scroll event's underlying touch/wheel event.
218 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( 138 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
219 "Event.Latency.ScrollBegin." + input_modality + 139 "Event.Latency.ScrollBegin." + input_modality +
220 ".TimeToScrollUpdateSwapBegin2", 140 ".TimeToScrollUpdateSwapBegin2",
221 original_component, gpu_swap_begin_component); 141 original_component, gpu_swap_begin_component);
222 142
223 RAPPOR_TOUCH_WHEEL_TO_SCROLL_LATENCY( 143 ReportRapporScrollLatency("Event.Latency.ScrollBegin." + input_modality +
224 render_widget_host_delegate, 144 ".TimeToScrollUpdateSwapBegin2",
225 "Event.Latency.ScrollBegin." + input_modality + 145 original_component, gpu_swap_begin_component);
226 ".TimeToScrollUpdateSwapBegin2",
227 original_component, gpu_swap_begin_component);
228 146
229 // TODO(lanwei): Will remove them when M56 is stable, see 147 // TODO(lanwei): Will remove them when M56 is stable, see
230 // https://crbug.com/669618. 148 // https://crbug.com/669618.
231 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( 149 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
232 "Event.Latency.ScrollUpdate." + input_modality + 150 "Event.Latency.ScrollUpdate." + input_modality +
233 ".TimeToFirstScrollUpdateSwapBegin2", 151 ".TimeToFirstScrollUpdateSwapBegin2",
234 original_component, gpu_swap_begin_component); 152 original_component, gpu_swap_begin_component);
235 } else if (latency.FindLatency( 153 } else if (latency.FindLatency(
236 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, 154 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
237 latency_component_id, &original_component)) { 155 &original_component)) {
238 // This UMA metric tracks the time from when the original touch event is 156 // 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. 157 // created to when the scroll gesture results in final frame swap.
240 // First scroll events are excluded from this metric. 158 // First scroll events are excluded from this metric.
241 if (input_modality == "Touch") { 159 if (input_modality == "Touch") {
242 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( 160 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
243 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2", 161 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2",
244 original_component, gpu_swap_begin_component); 162 original_component, gpu_swap_begin_component);
245 163
246 RAPPOR_TOUCH_WHEEL_TO_SCROLL_LATENCY( 164 ReportRapporScrollLatency(
247 render_widget_host_delegate,
248 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2", 165 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2",
249 original_component, gpu_swap_begin_component); 166 original_component, gpu_swap_begin_component);
250 } 167 }
251 } else { 168 } else {
252 // No original component found. 169 // No original component found.
253 return; 170 return;
254 } 171 }
255 172
256 LatencyInfo::LatencyComponent rendering_scheduled_component; 173 LatencyInfo::LatencyComponent rendering_scheduled_component;
257 bool rendering_scheduled_on_main = latency.FindLatency( 174 bool rendering_scheduled_on_main = latency.FindLatency(
(...skipping 17 matching lines...) Expand all
275 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, 192 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0,
276 &renderer_swap_component)) 193 &renderer_swap_component))
277 return; 194 return;
278 195
279 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2( 196 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2(
280 "Event.Latency." + scroll_name + "." + input_modality + 197 "Event.Latency." + scroll_name + "." + input_modality +
281 ".HandledToRendererSwap2_" + thread_name, 198 ".HandledToRendererSwap2_" + thread_name,
282 rendering_scheduled_component, renderer_swap_component); 199 rendering_scheduled_component, renderer_swap_component);
283 200
284 LatencyInfo::LatencyComponent browser_received_swap_component; 201 LatencyInfo::LatencyComponent browser_received_swap_component;
285 if (!latency.FindLatency( 202 if (!latency.FindLatency(ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, 0,
286 ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0, 203 &browser_received_swap_component))
287 &browser_received_swap_component))
288 return; 204 return;
289 205
290 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2( 206 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2(
291 "Event.Latency." + scroll_name + "." + input_modality + 207 "Event.Latency." + scroll_name + "." + input_modality +
292 ".RendererSwapToBrowserNotified2", 208 ".RendererSwapToBrowserNotified2",
293 renderer_swap_component, browser_received_swap_component); 209 renderer_swap_component, browser_received_swap_component);
294 210
295 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2( 211 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2(
296 "Event.Latency." + scroll_name + "." + input_modality + 212 "Event.Latency." + scroll_name + "." + input_modality +
297 ".BrowserNotifiedToBeforeGpuSwap2", 213 ".BrowserNotifiedToBeforeGpuSwap2",
298 browser_received_swap_component, gpu_swap_begin_component); 214 browser_received_swap_component, gpu_swap_begin_component);
299 215
300 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2( 216 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2(
301 "Event.Latency." + scroll_name + "." + input_modality + ".GpuSwap2", 217 "Event.Latency." + scroll_name + "." + input_modality + ".GpuSwap2",
302 gpu_swap_begin_component, gpu_swap_end_component); 218 gpu_swap_begin_component, gpu_swap_end_component);
303 } 219 }
304 // LatencyComponents generated in the renderer must have component IDs
305 // provided to them by the browser process. This function adds the correct
306 // component ID where necessary.
307 void AddLatencyInfoComponentIds(LatencyInfo* latency,
308 int64_t latency_component_id) {
309 std::vector<std::pair<ui::LatencyComponentType, int64_t>> new_components_key;
310 std::vector<LatencyInfo::LatencyComponent> new_components_value;
311 for (const auto& lc : latency->latency_components()) {
312 ui::LatencyComponentType component_type = lc.first.first;
313 if (component_type == ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT) {
314 // Generate a new component entry with the correct component ID
315 new_components_key.push_back(std::make_pair(component_type,
316 latency_component_id));
317 new_components_value.push_back(lc.second);
318 }
319 }
320 220
321 // Remove the entries with invalid component IDs. 221 } // namespace ui
322 latency->RemoveLatency(ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT);
323
324 // Add newly generated components into the latency info
325 for (size_t i = 0; i < new_components_key.size(); i++) {
326 latency->AddLatencyNumberWithTimestamp(
327 new_components_key[i].first,
328 new_components_key[i].second,
329 new_components_value[i].sequence_number,
330 new_components_value[i].event_time,
331 new_components_value[i].event_count);
332 }
333 }
334
335 } // namespace
336
337 RenderWidgetHostLatencyTracker::RenderWidgetHostLatencyTracker()
338 : last_event_id_(0),
339 latency_component_id_(0),
340 device_scale_factor_(1),
341 has_seen_first_gesture_scroll_update_(false),
342 active_multi_finger_gesture_(false),
343 touch_start_default_prevented_(false),
344 render_widget_host_delegate_(nullptr) {}
345
346 RenderWidgetHostLatencyTracker::~RenderWidgetHostLatencyTracker() {}
347
348 void RenderWidgetHostLatencyTracker::Initialize(int routing_id,
349 int process_id) {
350 DCHECK_EQ(0, last_event_id_);
351 DCHECK_EQ(0, latency_component_id_);
352 last_event_id_ = static_cast<int64_t>(process_id) << 32;
353 latency_component_id_ = routing_id | last_event_id_;
354 }
355
356 void RenderWidgetHostLatencyTracker::ComputeInputLatencyHistograms(
357 WebInputEvent::Type type,
358 int64_t latency_component_id,
359 const LatencyInfo& latency,
360 InputEventAckState ack_result) {
361 // If this event was coalesced into another event, ignore it, as the event it
362 // was coalesced into will reflect the full latency.
363 if (latency.coalesced())
364 return;
365
366 if (type != blink::WebInputEvent::kMouseWheel &&
367 !WebInputEvent::IsTouchEventType(type)) {
368 return;
369 }
370
371 LatencyInfo::LatencyComponent rwh_component;
372 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
373 latency_component_id, &rwh_component)) {
374 return;
375 }
376 DCHECK_EQ(rwh_component.event_count, 1u);
377
378 bool multi_finger_touch_gesture =
379 WebInputEvent::IsTouchEventType(type) && active_multi_finger_gesture_;
380
381 LatencyInfo::LatencyComponent ui_component;
382 if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0,
383 &ui_component)) {
384 DCHECK_EQ(ui_component.event_count, 1u);
385 base::TimeDelta ui_delta =
386 rwh_component.last_event_time - ui_component.first_event_time;
387
388 if (type == blink::WebInputEvent::kMouseWheel) {
389 UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser.WheelUI",
390 ui_delta.InMicroseconds(), 1, 20000, 100);
391 } else {
392 DCHECK(WebInputEvent::IsTouchEventType(type));
393 UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser.TouchUI",
394 ui_delta.InMicroseconds(), 1, 20000, 100);
395 }
396 }
397
398 // Both tap and scroll gestures depend on the disposition of the touch start
399 // and the current touch. For touch start, touch_start_default_prevented_ ==
400 // (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED).
401 bool action_prevented = touch_start_default_prevented_ ||
402 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
403
404 std::string event_name = WebInputEvent::GetName(type);
405
406 std::string default_action_status =
407 action_prevented ? "DefaultPrevented" : "DefaultAllowed";
408
409 LatencyInfo::LatencyComponent main_component;
410 if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT, 0,
411 &main_component)) {
412 DCHECK_EQ(main_component.event_count, 1u);
413 if (!multi_finger_touch_gesture) {
414 UMA_HISTOGRAM_INPUT_LATENCY_MILLISECONDS(
415 "Event.Latency.QueueingTime." + event_name + default_action_status,
416 rwh_component, main_component);
417 }
418 }
419
420 LatencyInfo::LatencyComponent acked_component;
421 if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0,
422 &acked_component)) {
423 DCHECK_EQ(acked_component.event_count, 1u);
424 if (!multi_finger_touch_gesture &&
425 main_component.event_time != base::TimeTicks()) {
426 UMA_HISTOGRAM_INPUT_LATENCY_MILLISECONDS(
427 "Event.Latency.BlockingTime." + event_name + default_action_status,
428 main_component, acked_component);
429 }
430
431 std::string input_modality = WebInputEventTypeToInputModalityString(type);
432 if (input_modality != "") {
433 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS(
434 "Event.Latency.Browser." + input_modality + "Acked", rwh_component,
435 acked_component);
436 }
437 }
438 }
439
440 void RenderWidgetHostLatencyTracker::OnInputEvent(
441 const blink::WebInputEvent& event,
442 LatencyInfo* latency) {
443 DCHECK(latency);
444
445 if (event.GetType() == WebInputEvent::kTouchStart) {
446 const WebTouchEvent& touch_event =
447 *static_cast<const WebTouchEvent*>(&event);
448 DCHECK(touch_event.touches_length >= 1);
449 active_multi_finger_gesture_ = touch_event.touches_length != 1;
450 }
451
452 if (latency->FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
453 latency_component_id_, NULL)) {
454 return;
455 }
456
457 if (event.TimeStampSeconds() &&
458 !latency->FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
459 NULL)) {
460 base::TimeTicks timestamp_now = base::TimeTicks::Now();
461 base::TimeTicks timestamp_original =
462 base::TimeTicks() +
463 base::TimeDelta::FromSecondsD(event.TimeStampSeconds());
464
465 // Timestamp from platform input can wrap, e.g. 32 bits timestamp
466 // for Xserver and Window MSG time will wrap about 49.6 days. Do a
467 // sanity check here and if wrap does happen, use TimeTicks::Now()
468 // as the timestamp instead.
469 if ((timestamp_now - timestamp_original).InDays() > 0)
470 timestamp_original = timestamp_now;
471
472 latency->AddLatencyNumberWithTimestamp(
473 ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
474 0,
475 0,
476 timestamp_original,
477 1);
478 }
479
480 latency->AddLatencyNumberWithTraceName(
481 ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, latency_component_id_,
482 ++last_event_id_, WebInputEvent::GetName(event.GetType()));
483
484 UpdateLatencyCoordinates(event, device_scale_factor_, latency);
485
486 if (event.GetType() == blink::WebInputEvent::kGestureScrollBegin) {
487 has_seen_first_gesture_scroll_update_ = false;
488 } else if (event.GetType() == blink::WebInputEvent::kGestureScrollUpdate) {
489 // Make a copy of the INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT with a
490 // different name INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT.
491 // So we can track the latency specifically for scroll update events.
492 LatencyInfo::LatencyComponent original_component;
493 if (latency->FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
494 &original_component)) {
495 latency->AddLatencyNumberWithTimestamp(
496 has_seen_first_gesture_scroll_update_
497 ? ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT
498 : ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
499 latency_component_id_, original_component.sequence_number,
500 original_component.event_time, original_component.event_count);
501 }
502
503 has_seen_first_gesture_scroll_update_ = true;
504 }
505 }
506
507 void RenderWidgetHostLatencyTracker::OnInputEventAck(
508 const blink::WebInputEvent& event,
509 LatencyInfo* latency, InputEventAckState ack_result) {
510 DCHECK(latency);
511
512 // Latency ends if an event is acked but does not cause render scheduling.
513 bool rendering_scheduled = latency->FindLatency(
514 ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT, 0, nullptr);
515 rendering_scheduled |= latency->FindLatency(
516 ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT, 0, nullptr);
517
518 if (WebInputEvent::IsTouchEventType(event.GetType())) {
519 const WebTouchEvent& touch_event =
520 *static_cast<const WebTouchEvent*>(&event);
521 if (event.GetType() == WebInputEvent::kTouchStart) {
522 touch_start_default_prevented_ =
523 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
524 } else if (event.GetType() == WebInputEvent::kTouchEnd ||
525 event.GetType() == WebInputEvent::kTouchCancel) {
526 active_multi_finger_gesture_ = touch_event.touches_length > 2;
527 }
528 }
529
530 latency->AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0, 0);
531 // If this event couldn't have caused a gesture event, and it didn't trigger
532 // rendering, we're done processing it.
533 if (!rendering_scheduled) {
534 latency->AddLatencyNumber(
535 ui::INPUT_EVENT_LATENCY_TERMINATED_NO_SWAP_COMPONENT, 0, 0);
536 }
537
538 ComputeInputLatencyHistograms(event.GetType(), latency_component_id_,
539 *latency, ack_result);
540 }
541
542 void RenderWidgetHostLatencyTracker::OnSwapCompositorFrame(
543 std::vector<LatencyInfo>* latencies) {
544 DCHECK(latencies);
545 for (LatencyInfo& latency : *latencies) {
546 AddLatencyInfoComponentIds(&latency, latency_component_id_);
547 latency.AddLatencyNumber(
548 ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0, 0);
549 }
550 }
551
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(
604 RenderWidgetHostDelegate* delegate) {
605 render_widget_host_delegate_ = delegate;
606 }
607
608 } // namespace content
OLDNEW
« no previous file with comments | « ui/latency/latency_tracker.h ('k') | ui/latency/mojo/latency_info.mojom » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698