| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/scheduler/renderer/user_model.h" | |
| 6 | |
| 7 #include "base/metrics/histogram_macros.h" | |
| 8 | |
| 9 namespace scheduler { | |
| 10 | |
| 11 namespace { | |
| 12 // This enum is used to back a histogram, and should therefore be treated as | |
| 13 // append-only. | |
| 14 enum GesturePredictionResult { | |
| 15 GESTURE_OCCURED_WAS_PREDICTED = 0, | |
| 16 GESTURE_OCCURED_BUT_NOT_PREDICTED = 1, | |
| 17 GESTURE_PREDICTED_BUT_DID_NOT_OCCUR = 2, | |
| 18 GESTURE_PREDICTION_RESULT_COUNT = 3 | |
| 19 }; | |
| 20 | |
| 21 void RecordGesturePrediction(GesturePredictionResult result) { | |
| 22 UMA_HISTOGRAM_ENUMERATION( | |
| 23 "RendererScheduler.UserModel.GesturePredictedCorrectly", result, | |
| 24 GESTURE_PREDICTION_RESULT_COUNT); | |
| 25 } | |
| 26 | |
| 27 } // namespace | |
| 28 | |
| 29 UserModel::UserModel() | |
| 30 : pending_input_event_count_(0), | |
| 31 is_gesture_active_(false), | |
| 32 is_gesture_expected_(false) {} | |
| 33 UserModel::~UserModel() {} | |
| 34 | |
| 35 void UserModel::DidStartProcessingInputEvent(blink::WebInputEvent::Type type, | |
| 36 const base::TimeTicks now) { | |
| 37 last_input_signal_time_ = now; | |
| 38 if (type == blink::WebInputEvent::TouchStart || | |
| 39 type == blink::WebInputEvent::GestureScrollBegin || | |
| 40 type == blink::WebInputEvent::GesturePinchBegin) { | |
| 41 // Only update stats once per gesture. | |
| 42 if (!is_gesture_active_) { | |
| 43 last_gesture_start_time_ = now; | |
| 44 | |
| 45 RecordGesturePrediction(is_gesture_expected_ | |
| 46 ? GESTURE_OCCURED_WAS_PREDICTED | |
| 47 : GESTURE_OCCURED_BUT_NOT_PREDICTED); | |
| 48 | |
| 49 if (!last_reset_time_.is_null()) { | |
| 50 base::TimeDelta time_since_reset = now - last_reset_time_; | |
| 51 UMA_HISTOGRAM_MEDIUM_TIMES( | |
| 52 "RendererScheduler.UserModel.GestureStartTimeSinceModelReset", | |
| 53 time_since_reset); | |
| 54 } | |
| 55 | |
| 56 // If there has been a previous gesture, record a UMA metric for the time | |
| 57 // interval between then and now. | |
| 58 if (!last_continuous_gesture_time_.is_null()) { | |
| 59 base::TimeDelta time_since_last_gesture = | |
| 60 now - last_continuous_gesture_time_; | |
| 61 UMA_HISTOGRAM_MEDIUM_TIMES( | |
| 62 "RendererScheduler.UserModel.TimeBetweenGestures", | |
| 63 time_since_last_gesture); | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 is_gesture_active_ = true; | |
| 68 } | |
| 69 | |
| 70 // We need to track continuous gestures seperatly for scroll detection | |
| 71 // because taps should not be confused with scrolls. | |
| 72 if (type == blink::WebInputEvent::GestureScrollBegin || | |
| 73 type == blink::WebInputEvent::GestureScrollEnd || | |
| 74 type == blink::WebInputEvent::GestureScrollUpdate || | |
| 75 type == blink::WebInputEvent::GestureFlingStart || | |
| 76 type == blink::WebInputEvent::GestureFlingCancel || | |
| 77 type == blink::WebInputEvent::GesturePinchBegin || | |
| 78 type == blink::WebInputEvent::GesturePinchEnd || | |
| 79 type == blink::WebInputEvent::GesturePinchUpdate) { | |
| 80 last_continuous_gesture_time_ = now; | |
| 81 } | |
| 82 | |
| 83 // If the gesture has ended, clear |is_gesture_active_| and record a UMA | |
| 84 // metric that tracks its duration. | |
| 85 if (type == blink::WebInputEvent::GestureScrollEnd || | |
| 86 type == blink::WebInputEvent::GesturePinchEnd || | |
| 87 type == blink::WebInputEvent::GestureFlingStart || | |
| 88 type == blink::WebInputEvent::TouchEnd) { | |
| 89 // Only update stats once per gesture. | |
| 90 if (is_gesture_active_) { | |
| 91 base::TimeDelta duration = now - last_gesture_start_time_; | |
| 92 UMA_HISTOGRAM_TIMES("RendererScheduler.UserModel.GestureDuration", | |
| 93 duration); | |
| 94 } | |
| 95 is_gesture_active_ = false; | |
| 96 } | |
| 97 | |
| 98 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | |
| 99 "is_gesture_active", is_gesture_active_); | |
| 100 | |
| 101 pending_input_event_count_++; | |
| 102 } | |
| 103 | |
| 104 void UserModel::DidFinishProcessingInputEvent(const base::TimeTicks now) { | |
| 105 last_input_signal_time_ = now; | |
| 106 if (pending_input_event_count_ > 0) | |
| 107 pending_input_event_count_--; | |
| 108 } | |
| 109 | |
| 110 base::TimeDelta UserModel::TimeLeftInUserGesture(base::TimeTicks now) const { | |
| 111 base::TimeDelta escalated_priority_duration = | |
| 112 base::TimeDelta::FromMilliseconds(kGestureEstimationLimitMillis); | |
| 113 | |
| 114 // If the input event is still pending, go into input prioritized policy and | |
| 115 // check again later. | |
| 116 if (pending_input_event_count_ > 0) | |
| 117 return escalated_priority_duration; | |
| 118 if (last_input_signal_time_.is_null() || | |
| 119 last_input_signal_time_ + escalated_priority_duration < now) { | |
| 120 return base::TimeDelta(); | |
| 121 } | |
| 122 return last_input_signal_time_ + escalated_priority_duration - now; | |
| 123 } | |
| 124 | |
| 125 bool UserModel::IsGestureExpectedSoon( | |
| 126 const base::TimeTicks now, | |
| 127 base::TimeDelta* prediction_valid_duration) { | |
| 128 bool was_gesture_expected = is_gesture_expected_; | |
| 129 is_gesture_expected_ = | |
| 130 IsGestureExpectedSoonImpl(now, prediction_valid_duration); | |
| 131 | |
| 132 // Track when we start expecting a gesture so we can work out later if a | |
| 133 // gesture actually happened. | |
| 134 if (!was_gesture_expected && is_gesture_expected_) | |
| 135 last_gesture_expected_start_time_ = now; | |
| 136 | |
| 137 if (was_gesture_expected && !is_gesture_expected_ && | |
| 138 last_gesture_expected_start_time_ > last_gesture_start_time_) { | |
| 139 RecordGesturePrediction(GESTURE_PREDICTED_BUT_DID_NOT_OCCUR); | |
| 140 } | |
| 141 return is_gesture_expected_; | |
| 142 } | |
| 143 | |
| 144 bool UserModel::IsGestureExpectedSoonImpl( | |
| 145 const base::TimeTicks now, | |
| 146 base::TimeDelta* prediction_valid_duration) const { | |
| 147 if (is_gesture_active_) { | |
| 148 if (IsGestureExpectedToContinue(now, prediction_valid_duration)) { | |
| 149 return false; | |
| 150 } else { | |
| 151 // If a gesture is not expected to continue then we expect a subsequent | |
| 152 // gesture soon. | |
| 153 *prediction_valid_duration = | |
| 154 base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis); | |
| 155 return true; | |
| 156 } | |
| 157 } else { | |
| 158 // If we've have a finished a gesture then a subsequent gesture is deemed | |
| 159 // likely. | |
| 160 base::TimeDelta expect_subsequent_gesture_for = | |
| 161 base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis); | |
| 162 if (last_continuous_gesture_time_.is_null() || | |
| 163 last_continuous_gesture_time_ + expect_subsequent_gesture_for <= now) { | |
| 164 return false; | |
| 165 } | |
| 166 *prediction_valid_duration = | |
| 167 last_continuous_gesture_time_ + expect_subsequent_gesture_for - now; | |
| 168 return true; | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 bool UserModel::IsGestureExpectedToContinue( | |
| 173 const base::TimeTicks now, | |
| 174 base::TimeDelta* prediction_valid_duration) const { | |
| 175 if (!is_gesture_active_) | |
| 176 return false; | |
| 177 | |
| 178 base::TimeDelta median_gesture_duration = | |
| 179 base::TimeDelta::FromMilliseconds(kMedianGestureDurationMillis); | |
| 180 base::TimeTicks expected_gesture_end_time = | |
| 181 last_gesture_start_time_ + median_gesture_duration; | |
| 182 | |
| 183 if (expected_gesture_end_time > now) { | |
| 184 *prediction_valid_duration = expected_gesture_end_time - now; | |
| 185 return true; | |
| 186 } | |
| 187 return false; | |
| 188 } | |
| 189 | |
| 190 void UserModel::Reset(base::TimeTicks now) { | |
| 191 last_input_signal_time_ = base::TimeTicks(); | |
| 192 last_gesture_start_time_ = base::TimeTicks(); | |
| 193 last_continuous_gesture_time_ = base::TimeTicks(); | |
| 194 last_gesture_expected_start_time_ = base::TimeTicks(); | |
| 195 last_reset_time_ = now; | |
| 196 is_gesture_active_ = false; | |
| 197 is_gesture_expected_ = false; | |
| 198 } | |
| 199 | |
| 200 void UserModel::AsValueInto(base::trace_event::TracedValue* state) const { | |
| 201 state->BeginDictionary("user_model"); | |
| 202 state->SetInteger("pending_input_event_count", pending_input_event_count_); | |
| 203 state->SetDouble( | |
| 204 "last_input_signal_time", | |
| 205 (last_input_signal_time_ - base::TimeTicks()).InMillisecondsF()); | |
| 206 state->SetDouble( | |
| 207 "last_gesture_start_time", | |
| 208 (last_gesture_start_time_ - base::TimeTicks()).InMillisecondsF()); | |
| 209 state->SetDouble( | |
| 210 "last_continuous_gesture_time", | |
| 211 (last_continuous_gesture_time_ - base::TimeTicks()).InMillisecondsF()); | |
| 212 state->SetDouble("last_gesture_expected_start_time", | |
| 213 (last_gesture_expected_start_time_ - base::TimeTicks()) | |
| 214 .InMillisecondsF()); | |
| 215 state->SetDouble("last_reset_time", | |
| 216 (last_reset_time_ - base::TimeTicks()).InMillisecondsF()); | |
| 217 state->SetBoolean("is_gesture_expected", is_gesture_expected_); | |
| 218 state->SetBoolean("is_gesture_active", is_gesture_active_); | |
| 219 state->EndDictionary(); | |
| 220 } | |
| 221 | |
| 222 } // namespace scheduler | |
| OLD | NEW |