OLD | NEW |
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 "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.touchesLength; ++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.type())) { | |
67 UpdateLatencyCoordinatesImpl(static_cast<const WebMouseEvent&>(event), | |
68 latency, device_scale_factor); | |
69 } else if (WebInputEvent::isGestureEventType(event.type())) { | |
70 UpdateLatencyCoordinatesImpl(static_cast<const WebGestureEvent&>(event), | |
71 latency, device_scale_factor); | |
72 } else if (WebInputEvent::isTouchEventType(event.type())) { | |
73 UpdateLatencyCoordinatesImpl(static_cast<const WebTouchEvent&>(event), | |
74 latency, device_scale_factor); | |
75 } else if (event.type() == WebInputEvent::MouseWheel) { | |
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::MouseWheel) { | |
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::ReportRapporScrollLatency( |
| 66 const std::string& name, |
| 67 const LatencyInfo::LatencyComponent& start_component, |
| 68 const LatencyInfo::LatencyComponent& end_component) {} |
| 69 |
| 70 void LatencyTracker::ComputeTouchAndWheelScrollLatencyHistograms( |
197 const ui::LatencyInfo::LatencyComponent& gpu_swap_begin_component, | 71 const ui::LatencyInfo::LatencyComponent& gpu_swap_begin_component, |
198 const ui::LatencyInfo::LatencyComponent& gpu_swap_end_component, | 72 const ui::LatencyInfo::LatencyComponent& gpu_swap_end_component, |
199 int64_t latency_component_id, | |
200 const ui::LatencyInfo& latency) { | 73 const ui::LatencyInfo& latency) { |
201 DCHECK(!latency.coalesced()); | 74 DCHECK(!latency.coalesced()); |
202 if (latency.coalesced()) | 75 if (latency.coalesced()) |
203 return; | 76 return; |
204 | 77 |
205 LatencyInfo::LatencyComponent original_component; | 78 LatencyInfo::LatencyComponent original_component; |
206 std::string scroll_name = "ScrollUpdate"; | 79 std::string scroll_name = "ScrollUpdate"; |
207 | 80 |
208 const std::string input_modality = | 81 const std::string input_modality = |
209 LatencySourceEventTypeToInputModalityString(latency.source_event_type()); | 82 LatencySourceEventTypeToInputModalityString(latency.source_event_type()); |
210 | 83 |
211 if (latency.FindLatency( | 84 if (latency.FindLatency( |
212 ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, | 85 ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, |
213 latency_component_id, &original_component)) { | 86 &original_component)) { |
214 scroll_name = "ScrollBegin"; | 87 scroll_name = "ScrollBegin"; |
215 // This UMA metric tracks the time between the final frame swap for the | 88 // 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 | 89 // first scroll event in a sequence and the original timestamp of that |
217 // scroll event's underlying touch/wheel event. | 90 // scroll event's underlying touch/wheel event. |
218 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( | 91 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( |
219 "Event.Latency.ScrollBegin." + input_modality + | 92 "Event.Latency.ScrollBegin." + input_modality + |
220 ".TimeToScrollUpdateSwapBegin2", | 93 ".TimeToScrollUpdateSwapBegin2", |
221 original_component, gpu_swap_begin_component); | 94 original_component, gpu_swap_begin_component); |
222 | 95 |
223 RAPPOR_TOUCH_WHEEL_TO_SCROLL_LATENCY( | 96 ReportRapporScrollLatency("Event.Latency.ScrollBegin." + input_modality + |
224 render_widget_host_delegate, | 97 ".TimeToScrollUpdateSwapBegin2", |
225 "Event.Latency.ScrollBegin." + input_modality + | 98 original_component, gpu_swap_begin_component); |
226 ".TimeToScrollUpdateSwapBegin2", | |
227 original_component, gpu_swap_begin_component); | |
228 | 99 |
229 // TODO(lanwei): Will remove them when M56 is stable, see | 100 // TODO(lanwei): Will remove them when M56 is stable, see |
230 // https://crbug.com/669618. | 101 // https://crbug.com/669618. |
231 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( | 102 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( |
232 "Event.Latency.ScrollUpdate." + input_modality + | 103 "Event.Latency.ScrollUpdate." + input_modality + |
233 ".TimeToFirstScrollUpdateSwapBegin2", | 104 ".TimeToFirstScrollUpdateSwapBegin2", |
234 original_component, gpu_swap_begin_component); | 105 original_component, gpu_swap_begin_component); |
235 } else if (latency.FindLatency( | 106 } else if (latency.FindLatency( |
236 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, | 107 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, |
237 latency_component_id, &original_component)) { | 108 &original_component)) { |
238 // This UMA metric tracks the time from when the original touch event is | 109 // 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. | 110 // created to when the scroll gesture results in final frame swap. |
240 // First scroll events are excluded from this metric. | 111 // First scroll events are excluded from this metric. |
241 if (input_modality == "Touch") { | 112 if (input_modality == "Touch") { |
242 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( | 113 UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( |
243 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2", | 114 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2", |
244 original_component, gpu_swap_begin_component); | 115 original_component, gpu_swap_begin_component); |
245 | 116 |
246 RAPPOR_TOUCH_WHEEL_TO_SCROLL_LATENCY( | 117 ReportRapporScrollLatency( |
247 render_widget_host_delegate, | |
248 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2", | 118 "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2", |
249 original_component, gpu_swap_begin_component); | 119 original_component, gpu_swap_begin_component); |
250 } | 120 } |
251 } else { | 121 } else { |
252 // No original component found. | 122 // No original component found. |
253 return; | 123 return; |
254 } | 124 } |
255 | 125 |
256 LatencyInfo::LatencyComponent rendering_scheduled_component; | 126 LatencyInfo::LatencyComponent rendering_scheduled_component; |
257 bool rendering_scheduled_on_main = latency.FindLatency( | 127 bool rendering_scheduled_on_main = latency.FindLatency( |
(...skipping 17 matching lines...) Expand all Loading... |
275 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, | 145 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, |
276 &renderer_swap_component)) | 146 &renderer_swap_component)) |
277 return; | 147 return; |
278 | 148 |
279 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2( | 149 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2( |
280 "Event.Latency." + scroll_name + "." + input_modality + | 150 "Event.Latency." + scroll_name + "." + input_modality + |
281 ".HandledToRendererSwap2_" + thread_name, | 151 ".HandledToRendererSwap2_" + thread_name, |
282 rendering_scheduled_component, renderer_swap_component); | 152 rendering_scheduled_component, renderer_swap_component); |
283 | 153 |
284 LatencyInfo::LatencyComponent browser_received_swap_component; | 154 LatencyInfo::LatencyComponent browser_received_swap_component; |
285 if (!latency.FindLatency( | 155 if (!latency.FindLatency(ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, 0, |
286 ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0, | 156 &browser_received_swap_component)) |
287 &browser_received_swap_component)) | |
288 return; | 157 return; |
289 | 158 |
290 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2( | 159 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2( |
291 "Event.Latency." + scroll_name + "." + input_modality + | 160 "Event.Latency." + scroll_name + "." + input_modality + |
292 ".RendererSwapToBrowserNotified2", | 161 ".RendererSwapToBrowserNotified2", |
293 renderer_swap_component, browser_received_swap_component); | 162 renderer_swap_component, browser_received_swap_component); |
294 | 163 |
295 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2( | 164 UMA_HISTOGRAM_SCROLL_LATENCY_LONG_2( |
296 "Event.Latency." + scroll_name + "." + input_modality + | 165 "Event.Latency." + scroll_name + "." + input_modality + |
297 ".BrowserNotifiedToBeforeGpuSwap2", | 166 ".BrowserNotifiedToBeforeGpuSwap2", |
298 browser_received_swap_component, gpu_swap_begin_component); | 167 browser_received_swap_component, gpu_swap_begin_component); |
299 | 168 |
300 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2( | 169 UMA_HISTOGRAM_SCROLL_LATENCY_SHORT_2( |
301 "Event.Latency." + scroll_name + "." + input_modality + ".GpuSwap2", | 170 "Event.Latency." + scroll_name + "." + input_modality + ".GpuSwap2", |
302 gpu_swap_begin_component, gpu_swap_end_component); | 171 gpu_swap_begin_component, gpu_swap_end_component); |
303 } | 172 } |
304 // LatencyComponents generated in the renderer must have component IDs | 173 |
305 // provided to them by the browser process. This function adds the correct | 174 // TODO(mfomitchev): Move the method up. It's here temporarily for ease of |
306 // component ID where necessary. | 175 // review. |
307 void AddLatencyInfoComponentIds(LatencyInfo* latency, | 176 void LatencyTracker::OnGpuSwapBuffersCompleted(const LatencyInfo& latency) { |
308 int64_t latency_component_id) { | 177 LOG(ERROR) << "LatencyTracker::OnGpuSwapBuffersCompleted"; |
309 std::vector<std::pair<ui::LatencyComponentType, int64_t>> new_components_key; | 178 int i = 0; |
310 std::vector<LatencyInfo::LatencyComponent> new_components_value; | 179 for (const auto& lc : latency.latency_components()) { |
311 for (const auto& lc : latency->latency_components()) { | 180 ++i; |
312 ui::LatencyComponentType component_type = lc.first.first; | 181 LOG(ERROR) << "Component " << i << ": " |
313 if (component_type == ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT) { | 182 << ui::GetComponentName(lc.first.first) |
314 // Generate a new component entry with the correct component ID | 183 << ", timestamp: " << lc.second.event_time; |
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 } | 184 } |
320 | 185 |
321 // Remove the entries with invalid component IDs. | |
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::MouseWheel && | |
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::MouseWheel) { | |
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.type() == WebInputEvent::TouchStart) { | |
446 const WebTouchEvent& touch_event = | |
447 *static_cast<const WebTouchEvent*>(&event); | |
448 DCHECK(touch_event.touchesLength >= 1); | |
449 active_multi_finger_gesture_ = touch_event.touchesLength != 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.type())); | |
483 | |
484 UpdateLatencyCoordinates(event, device_scale_factor_, latency); | |
485 | |
486 if (event.type() == blink::WebInputEvent::GestureScrollBegin) { | |
487 has_seen_first_gesture_scroll_update_ = false; | |
488 } else if (event.type() == blink::WebInputEvent::GestureScrollUpdate) { | |
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.type())) { | |
519 const WebTouchEvent& touch_event = | |
520 *static_cast<const WebTouchEvent*>(&event); | |
521 if (event.type() == WebInputEvent::TouchStart) { | |
522 touch_start_default_prevented_ = | |
523 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED; | |
524 } else if (event.type() == WebInputEvent::TouchEnd || | |
525 event.type() == WebInputEvent::TouchCancel) { | |
526 active_multi_finger_gesture_ = touch_event.touchesLength > 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.type(), latency_component_id_, *latency, | |
539 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; | 186 LatencyInfo::LatencyComponent gpu_swap_end_component; |
555 if (!latency.FindLatency( | 187 if (!latency.FindLatency( |
556 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, | 188 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, |
557 &gpu_swap_end_component)) { | 189 &gpu_swap_end_component)) { |
558 return; | 190 return; |
559 } | 191 } |
560 | 192 |
561 LatencyInfo::LatencyComponent gpu_swap_begin_component; | 193 LatencyInfo::LatencyComponent gpu_swap_begin_component; |
562 if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, | 194 if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, |
563 &gpu_swap_begin_component)) { | 195 &gpu_swap_begin_component)) { |
564 return; | 196 return; |
565 } | 197 } |
566 | 198 |
567 LatencyInfo::LatencyComponent tab_switch_component; | 199 LatencyInfo::LatencyComponent tab_switch_component; |
568 if (latency.FindLatency(ui::TAB_SHOW_COMPONENT, latency_component_id_, | 200 if (latency.FindLatency(ui::TAB_SHOW_COMPONENT, &tab_switch_component)) { |
569 &tab_switch_component)) { | |
570 base::TimeDelta delta = | 201 base::TimeDelta delta = |
571 gpu_swap_end_component.event_time - tab_switch_component.event_time; | 202 gpu_swap_end_component.event_time - tab_switch_component.event_time; |
572 for (size_t i = 0; i < tab_switch_component.event_count; i++) { | 203 for (size_t i = 0; i < tab_switch_component.event_count; i++) { |
573 UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta); | 204 UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta); |
574 } | 205 } |
575 } | 206 } |
576 | 207 |
577 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, | 208 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, |
578 latency_component_id_, nullptr)) { | 209 nullptr)) { |
579 return; | 210 return; |
580 } | 211 } |
581 | 212 |
582 ui::SourceEventType source_event_type = latency.source_event_type(); | 213 ui::SourceEventType source_event_type = latency.source_event_type(); |
583 if (source_event_type == ui::SourceEventType::WHEEL || | 214 if (source_event_type == ui::SourceEventType::WHEEL || |
584 source_event_type == ui::SourceEventType::TOUCH) { | 215 source_event_type == ui::SourceEventType::TOUCH) { |
585 ComputeTouchAndWheelScrollLatencyHistograms( | 216 ComputeTouchAndWheelScrollLatencyHistograms( |
586 render_widget_host_delegate_, gpu_swap_begin_component, | 217 gpu_swap_begin_component, gpu_swap_end_component, latency); |
587 gpu_swap_end_component, latency_component_id_, latency); | |
588 } | 218 } |
589 | 219 |
590 // Compute the old scroll update latency metrics. They are exclusively | 220 // Compute the old scroll update latency metrics. They are exclusively |
591 // calculated for touch scrolls, and will be deprecated on M56. | 221 // calculated for touch scrolls, and will be deprecated on M56. |
592 // (https://crbug.com/649754) | 222 // (https://crbug.com/649754) |
593 LatencyInfo::LatencyComponent mouse_wheel_scroll_update_component; | 223 LatencyInfo::LatencyComponent mouse_wheel_scroll_update_component; |
594 if (!latency.FindLatency( | 224 if (!latency.FindLatency( |
595 ui::INPUT_EVENT_LATENCY_GENERATE_SCROLL_UPDATE_FROM_MOUSE_WHEEL, 0, | 225 ui::INPUT_EVENT_LATENCY_GENERATE_SCROLL_UPDATE_FROM_MOUSE_WHEEL, 0, |
596 &mouse_wheel_scroll_update_component)) { | 226 &mouse_wheel_scroll_update_component)) { |
597 ComputeScrollLatencyHistograms(gpu_swap_begin_component, | 227 ComputeScrollLatencyHistograms(gpu_swap_begin_component, |
598 gpu_swap_end_component, | 228 gpu_swap_end_component, latency); |
599 latency_component_id_, latency); | |
600 } | 229 } |
601 } | 230 } |
602 | 231 |
603 void RenderWidgetHostLatencyTracker::SetDelegate( | 232 } // namespace ui |
604 RenderWidgetHostDelegate* delegate) { | |
605 render_widget_host_delegate_ = delegate; | |
606 } | |
607 | |
608 } // namespace content | |
OLD | NEW |