| OLD | NEW |
| 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.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 | |
| 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 | 173 |
| 321 // Remove the entries with invalid component IDs. | 174 // TODO(mfomitchev): Move the method up. It's here temporarily for ease of |
| 322 latency->RemoveLatency(ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT); | 175 // review. |
| 323 | 176 void LatencyTracker::OnGpuSwapBuffersCompleted(const LatencyInfo& latency) { |
| 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; | 177 LatencyInfo::LatencyComponent gpu_swap_end_component; |
| 555 if (!latency.FindLatency( | 178 if (!latency.FindLatency( |
| 556 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, | 179 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, |
| 557 &gpu_swap_end_component)) { | 180 &gpu_swap_end_component)) { |
| 558 return; | 181 return; |
| 559 } | 182 } |
| 560 | 183 |
| 561 LatencyInfo::LatencyComponent gpu_swap_begin_component; | 184 LatencyInfo::LatencyComponent gpu_swap_begin_component; |
| 562 if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, | 185 if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, |
| 563 &gpu_swap_begin_component)) { | 186 &gpu_swap_begin_component)) { |
| 564 return; | 187 return; |
| 565 } | 188 } |
| 566 | 189 |
| 567 LatencyInfo::LatencyComponent tab_switch_component; | 190 LatencyInfo::LatencyComponent tab_switch_component; |
| 568 if (latency.FindLatency(ui::TAB_SHOW_COMPONENT, latency_component_id_, | 191 if (latency.FindLatency(ui::TAB_SHOW_COMPONENT, &tab_switch_component)) { |
| 569 &tab_switch_component)) { | |
| 570 base::TimeDelta delta = | 192 base::TimeDelta delta = |
| 571 gpu_swap_end_component.event_time - tab_switch_component.event_time; | 193 gpu_swap_end_component.event_time - tab_switch_component.event_time; |
| 572 for (size_t i = 0; i < tab_switch_component.event_count; i++) { | 194 for (size_t i = 0; i < tab_switch_component.event_count; i++) { |
| 573 UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta); | 195 UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta); |
| 574 } | 196 } |
| 575 } | 197 } |
| 576 | 198 |
| 577 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, | 199 if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, |
| 578 latency_component_id_, nullptr)) { | 200 nullptr)) { |
| 579 return; | 201 return; |
| 580 } | 202 } |
| 581 | 203 |
| 582 ui::SourceEventType source_event_type = latency.source_event_type(); | 204 ui::SourceEventType source_event_type = latency.source_event_type(); |
| 583 if (source_event_type == ui::SourceEventType::WHEEL || | 205 if (source_event_type == ui::SourceEventType::WHEEL || |
| 584 source_event_type == ui::SourceEventType::TOUCH) { | 206 source_event_type == ui::SourceEventType::TOUCH) { |
| 585 ComputeTouchAndWheelScrollLatencyHistograms( | 207 ComputeTouchAndWheelScrollLatencyHistograms( |
| 586 render_widget_host_delegate_, gpu_swap_begin_component, | 208 gpu_swap_begin_component, gpu_swap_end_component, latency); |
| 587 gpu_swap_end_component, latency_component_id_, latency); | |
| 588 } | 209 } |
| 589 | 210 |
| 590 // Compute the old scroll update latency metrics. They are exclusively | 211 // Compute the old scroll update latency metrics. They are exclusively |
| 591 // calculated for touch scrolls, and will be deprecated on M56. | 212 // calculated for touch scrolls, and will be deprecated on M56. |
| 592 // (https://crbug.com/649754) | 213 // (https://crbug.com/649754) |
| 593 LatencyInfo::LatencyComponent mouse_wheel_scroll_update_component; | 214 LatencyInfo::LatencyComponent mouse_wheel_scroll_update_component; |
| 594 if (!latency.FindLatency( | 215 if (!latency.FindLatency( |
| 595 ui::INPUT_EVENT_LATENCY_GENERATE_SCROLL_UPDATE_FROM_MOUSE_WHEEL, 0, | 216 ui::INPUT_EVENT_LATENCY_GENERATE_SCROLL_UPDATE_FROM_MOUSE_WHEEL, 0, |
| 596 &mouse_wheel_scroll_update_component)) { | 217 &mouse_wheel_scroll_update_component)) { |
| 597 ComputeScrollLatencyHistograms(gpu_swap_begin_component, | 218 ComputeScrollLatencyHistograms(gpu_swap_begin_component, |
| 598 gpu_swap_end_component, | 219 gpu_swap_end_component, latency); |
| 599 latency_component_id_, latency); | |
| 600 } | 220 } |
| 601 } | 221 } |
| 602 | 222 |
| 603 void RenderWidgetHostLatencyTracker::SetDelegate( | 223 } // namespace ui |
| 604 RenderWidgetHostDelegate* delegate) { | |
| 605 render_widget_host_delegate_ = delegate; | |
| 606 } | |
| 607 | |
| 608 } // namespace content | |
| OLD | NEW |