OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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 "components/scheduler/child/idle_helper.h" | 5 #include "components/scheduler/child/idle_helper.h" |
6 | 6 |
| 7 #include "base/time/time.h" |
7 #include "base/trace_event/trace_event.h" | 8 #include "base/trace_event/trace_event.h" |
8 #include "base/trace_event/trace_event_argument.h" | 9 #include "base/trace_event/trace_event_argument.h" |
9 #include "components/scheduler/child/scheduler_helper.h" | 10 #include "components/scheduler/child/scheduler_helper.h" |
10 | 11 |
11 namespace scheduler { | 12 namespace scheduler { |
12 | 13 |
13 IdleHelper::IdleHelper( | 14 IdleHelper::IdleHelper( |
14 SchedulerHelper* helper, | 15 SchedulerHelper* helper, |
15 Delegate* delegate, | 16 Delegate* delegate, |
16 size_t idle_queue_index, | 17 size_t idle_queue_index, |
17 const char* tracing_category, | 18 const char* tracing_category, |
18 const char* disabled_by_default_tracing_category, | 19 const char* disabled_by_default_tracing_category, |
19 const char* idle_period_tracing_name, | 20 const char* idle_period_tracing_name, |
20 base::TimeDelta required_quiescence_duration_before_long_idle_period) | 21 base::TimeDelta required_quiescence_duration_before_long_idle_period) |
21 : helper_(helper), | 22 : helper_(helper), |
22 delegate_(delegate), | 23 delegate_(delegate), |
23 idle_queue_index_(idle_queue_index), | 24 idle_queue_index_(idle_queue_index), |
24 idle_period_state_(IdlePeriodState::NOT_IN_IDLE_PERIOD), | 25 state_(helper, |
| 26 tracing_category, |
| 27 disabled_by_default_tracing_category, |
| 28 idle_period_tracing_name), |
25 quiescence_monitored_task_queue_mask_( | 29 quiescence_monitored_task_queue_mask_( |
26 helper_->GetQuiescenceMonitoredTaskQueueMask() & | 30 helper_->GetQuiescenceMonitoredTaskQueueMask() & |
27 ~(1ull << idle_queue_index_)), | 31 ~(1ull << idle_queue_index_)), |
28 required_quiescence_duration_before_long_idle_period_( | 32 required_quiescence_duration_before_long_idle_period_( |
29 required_quiescence_duration_before_long_idle_period), | 33 required_quiescence_duration_before_long_idle_period), |
30 tracing_category_(tracing_category), | |
31 disabled_by_default_tracing_category_( | 34 disabled_by_default_tracing_category_( |
32 disabled_by_default_tracing_category), | 35 disabled_by_default_tracing_category), |
33 idle_period_tracing_name_(idle_period_tracing_name), | |
34 weak_factory_(this) { | 36 weak_factory_(this) { |
35 weak_idle_helper_ptr_ = weak_factory_.GetWeakPtr(); | 37 weak_idle_helper_ptr_ = weak_factory_.GetWeakPtr(); |
36 end_idle_period_closure_.Reset( | |
37 base::Bind(&IdleHelper::EndIdlePeriod, weak_idle_helper_ptr_)); | |
38 enable_next_long_idle_period_closure_.Reset( | 38 enable_next_long_idle_period_closure_.Reset( |
39 base::Bind(&IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_)); | 39 base::Bind(&IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_)); |
40 enable_next_long_idle_period_after_wakeup_closure_.Reset(base::Bind( | 40 on_idle_task_posted_closure_.Reset(base::Bind( |
41 &IdleHelper::EnableLongIdlePeriodAfterWakeup, weak_idle_helper_ptr_)); | 41 &IdleHelper::OnIdleTaskPostedOnMainThread, weak_idle_helper_ptr_)); |
42 | 42 |
43 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( | 43 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( |
44 helper_->TaskRunnerForQueue(idle_queue_index_), | 44 helper_->TaskRunnerForQueue(idle_queue_index_), |
45 helper_->ControlAfterWakeUpTaskRunner(), | 45 helper_->ControlAfterWakeUpTaskRunner(), this, tracing_category)); |
46 base::Bind(&IdleHelper::CurrentIdleTaskDeadlineCallback, | |
47 weak_idle_helper_ptr_), | |
48 tracing_category)); | |
49 | 46 |
50 helper_->DisableQueue(idle_queue_index_); | 47 helper_->DisableQueue(idle_queue_index_); |
51 helper_->SetPumpPolicy(idle_queue_index_, | 48 helper_->SetPumpPolicy(idle_queue_index_, |
52 TaskQueueManager::PumpPolicy::MANUAL); | 49 TaskQueueManager::PumpPolicy::MANUAL); |
| 50 |
| 51 helper_->AddTaskObserver(this); |
53 } | 52 } |
54 | 53 |
55 IdleHelper::~IdleHelper() { | 54 IdleHelper::~IdleHelper() { |
| 55 helper_->RemoveTaskObserver(this); |
56 } | 56 } |
57 | 57 |
58 IdleHelper::Delegate::Delegate() { | 58 IdleHelper::Delegate::Delegate() { |
59 } | 59 } |
60 | 60 |
61 IdleHelper::Delegate::~Delegate() { | 61 IdleHelper::Delegate::~Delegate() { |
62 } | 62 } |
63 | 63 |
64 scoped_refptr<SingleThreadIdleTaskRunner> IdleHelper::IdleTaskRunner() { | 64 scoped_refptr<SingleThreadIdleTaskRunner> IdleHelper::IdleTaskRunner() { |
65 helper_->CheckOnValidThread(); | 65 helper_->CheckOnValidThread(); |
66 return idle_task_runner_; | 66 return idle_task_runner_; |
67 } | 67 } |
68 | 68 |
69 void IdleHelper::CurrentIdleTaskDeadlineCallback( | |
70 base::TimeTicks* deadline_out) const { | |
71 helper_->CheckOnValidThread(); | |
72 *deadline_out = idle_period_deadline_; | |
73 } | |
74 | |
75 IdleHelper::IdlePeriodState IdleHelper::ComputeNewLongIdlePeriodState( | 69 IdleHelper::IdlePeriodState IdleHelper::ComputeNewLongIdlePeriodState( |
76 const base::TimeTicks now, | 70 const base::TimeTicks now, |
77 base::TimeDelta* next_long_idle_period_delay_out) { | 71 base::TimeDelta* next_long_idle_period_delay_out) { |
78 helper_->CheckOnValidThread(); | 72 helper_->CheckOnValidThread(); |
79 | 73 |
80 if (!delegate_->CanEnterLongIdlePeriod(now, | 74 if (!delegate_->CanEnterLongIdlePeriod(now, |
81 next_long_idle_period_delay_out)) { | 75 next_long_idle_period_delay_out)) { |
82 return IdlePeriodState::NOT_IN_IDLE_PERIOD; | 76 return IdlePeriodState::NOT_IN_IDLE_PERIOD; |
83 } | 77 } |
84 | 78 |
85 base::TimeTicks next_pending_delayed_task = | 79 base::TimeTicks next_pending_delayed_task = |
86 helper_->NextPendingDelayedTaskRunTime(); | 80 helper_->NextPendingDelayedTaskRunTime(); |
87 base::TimeDelta max_long_idle_period_duration = | 81 base::TimeDelta max_long_idle_period_duration = |
88 base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis); | 82 base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis); |
89 base::TimeDelta long_idle_period_duration; | 83 base::TimeDelta long_idle_period_duration; |
90 if (next_pending_delayed_task.is_null()) { | 84 if (next_pending_delayed_task.is_null()) { |
91 long_idle_period_duration = max_long_idle_period_duration; | 85 long_idle_period_duration = max_long_idle_period_duration; |
92 } else { | 86 } else { |
93 // Limit the idle period duration to be before the next pending task. | 87 // Limit the idle period duration to be before the next pending task. |
94 long_idle_period_duration = std::min(next_pending_delayed_task - now, | 88 long_idle_period_duration = std::min(next_pending_delayed_task - now, |
95 max_long_idle_period_duration); | 89 max_long_idle_period_duration); |
96 } | 90 } |
97 | 91 |
98 if (long_idle_period_duration > base::TimeDelta()) { | 92 if (long_idle_period_duration > base::TimeDelta()) { |
99 *next_long_idle_period_delay_out = long_idle_period_duration; | 93 *next_long_idle_period_delay_out = long_idle_period_duration; |
100 return long_idle_period_duration == max_long_idle_period_duration | 94 if (helper_->IsQueueEmpty(idle_queue_index_)) { |
101 ? IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE | 95 return IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED; |
102 : IdlePeriodState::IN_LONG_IDLE_PERIOD; | 96 } else if (long_idle_period_duration == max_long_idle_period_duration) { |
| 97 return IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE; |
| 98 } else { |
| 99 return IdlePeriodState::IN_LONG_IDLE_PERIOD; |
| 100 } |
103 } else { | 101 } else { |
104 // If we can't start the idle period yet then try again after wakeup. | 102 // If we can't start the idle period yet then try again after wakeup. |
105 *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds( | 103 *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds( |
106 kRetryEnableLongIdlePeriodDelayMillis); | 104 kRetryEnableLongIdlePeriodDelayMillis); |
107 return IdlePeriodState::NOT_IN_IDLE_PERIOD; | 105 return IdlePeriodState::NOT_IN_IDLE_PERIOD; |
108 } | 106 } |
109 } | 107 } |
110 | 108 |
111 bool IdleHelper::ShouldWaitForQuiescence() { | 109 bool IdleHelper::ShouldWaitForQuiescence() { |
112 helper_->CheckOnValidThread(); | 110 helper_->CheckOnValidThread(); |
(...skipping 14 matching lines...) Expand all Loading... |
127 task_queues_run_since_last_check_bitmap); | 125 task_queues_run_since_last_check_bitmap); |
128 | 126 |
129 // If anything was run on the queues we care about, then we're not quiescent | 127 // If anything was run on the queues we care about, then we're not quiescent |
130 // and we should wait. | 128 // and we should wait. |
131 return task_queues_run_since_last_check_bitmap != 0; | 129 return task_queues_run_since_last_check_bitmap != 0; |
132 } | 130 } |
133 | 131 |
134 void IdleHelper::EnableLongIdlePeriod() { | 132 void IdleHelper::EnableLongIdlePeriod() { |
135 TRACE_EVENT0(disabled_by_default_tracing_category_, "EnableLongIdlePeriod"); | 133 TRACE_EVENT0(disabled_by_default_tracing_category_, "EnableLongIdlePeriod"); |
136 helper_->CheckOnValidThread(); | 134 helper_->CheckOnValidThread(); |
| 135 if (helper_->IsShutdown()) |
| 136 return; |
137 | 137 |
138 // End any previous idle period. | 138 // End any previous idle period. |
139 EndIdlePeriod(); | 139 EndIdlePeriod(); |
140 | 140 |
141 if (ShouldWaitForQuiescence()) { | 141 if (ShouldWaitForQuiescence()) { |
142 helper_->ControlTaskRunner()->PostDelayedTask( | 142 helper_->ControlTaskRunner()->PostDelayedTask( |
143 FROM_HERE, enable_next_long_idle_period_closure_.callback(), | 143 FROM_HERE, enable_next_long_idle_period_closure_.callback(), |
144 required_quiescence_duration_before_long_idle_period_); | 144 required_quiescence_duration_before_long_idle_period_); |
145 delegate_->IsNotQuiescent(); | 145 delegate_->IsNotQuiescent(); |
146 return; | 146 return; |
147 } | 147 } |
148 | 148 |
149 base::TimeTicks now(helper_->Now()); | 149 base::TimeTicks now(helper_->Now()); |
150 base::TimeDelta next_long_idle_period_delay; | 150 base::TimeDelta next_long_idle_period_delay; |
151 IdlePeriodState new_idle_period_state = | 151 IdlePeriodState new_idle_period_state = |
152 ComputeNewLongIdlePeriodState(now, &next_long_idle_period_delay); | 152 ComputeNewLongIdlePeriodState(now, &next_long_idle_period_delay); |
153 if (IsInIdlePeriod(new_idle_period_state)) { | 153 if (IsInIdlePeriod(new_idle_period_state)) { |
154 StartIdlePeriod(new_idle_period_state, now, | 154 StartIdlePeriod(new_idle_period_state, now, |
155 now + next_long_idle_period_delay, false); | 155 now + next_long_idle_period_delay); |
156 } | |
157 | |
158 if (helper_->IsQueueEmpty(idle_queue_index_)) { | |
159 // If there are no current idle tasks then post the call to initiate the | |
160 // next idle for execution after wakeup (at which point after-wakeup idle | |
161 // tasks might be eligible to run or more idle tasks posted). | |
162 helper_->ControlAfterWakeUpTaskRunner()->PostDelayedTask( | |
163 FROM_HERE, | |
164 enable_next_long_idle_period_after_wakeup_closure_.callback(), | |
165 next_long_idle_period_delay); | |
166 } else { | 156 } else { |
167 // Otherwise post on the normal control task queue. | 157 // Otherwise wait for the next long idle period delay before trying again. |
168 helper_->ControlTaskRunner()->PostDelayedTask( | 158 helper_->ControlTaskRunner()->PostDelayedTask( |
169 FROM_HERE, enable_next_long_idle_period_closure_.callback(), | 159 FROM_HERE, enable_next_long_idle_period_closure_.callback(), |
170 next_long_idle_period_delay); | 160 next_long_idle_period_delay); |
171 } | 161 } |
172 } | 162 } |
173 | 163 |
174 void IdleHelper::EnableLongIdlePeriodAfterWakeup() { | |
175 TRACE_EVENT0(disabled_by_default_tracing_category_, | |
176 "EnableLongIdlePeriodAfterWakeup"); | |
177 helper_->CheckOnValidThread(); | |
178 | |
179 if (IsInIdlePeriod(idle_period_state_)) { | |
180 // Since we were asleep until now, end the async idle period trace event at | |
181 // the time when it would have ended were we awake. | |
182 TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0( | |
183 tracing_category_, idle_period_tracing_name_, this, | |
184 std::min(idle_period_deadline_, helper_->Now()).ToInternalValue()); | |
185 idle_period_state_ = IdlePeriodState::ENDING_LONG_IDLE_PERIOD; | |
186 EndIdlePeriod(); | |
187 } | |
188 | |
189 // Post a task to initiate the next long idle period rather than calling it | |
190 // directly to allow all pending PostIdleTaskAfterWakeup tasks to get enqueued | |
191 // on the idle task queue before the next idle period starts so they are | |
192 // eligible to be run during the new idle period. | |
193 helper_->ControlTaskRunner()->PostTask( | |
194 FROM_HERE, enable_next_long_idle_period_closure_.callback()); | |
195 } | |
196 | |
197 void IdleHelper::StartIdlePeriod(IdlePeriodState new_state, | 164 void IdleHelper::StartIdlePeriod(IdlePeriodState new_state, |
198 base::TimeTicks now, | 165 base::TimeTicks now, |
199 base::TimeTicks idle_period_deadline, | 166 base::TimeTicks idle_period_deadline) { |
200 bool post_end_idle_period) { | |
201 DCHECK_GT(idle_period_deadline, now); | 167 DCHECK_GT(idle_period_deadline, now); |
202 TRACE_EVENT_ASYNC_BEGIN0(tracing_category_, idle_period_tracing_name_, this); | |
203 helper_->CheckOnValidThread(); | 168 helper_->CheckOnValidThread(); |
204 DCHECK(IsInIdlePeriod(new_state)); | 169 DCHECK(IsInIdlePeriod(new_state)); |
| 170 TRACE_EVENT0(disabled_by_default_tracing_category_, "StartIdlePeriod"); |
205 | 171 |
206 helper_->EnableQueue(idle_queue_index_, | 172 helper_->EnableQueue(idle_queue_index_, |
207 PrioritizingTaskQueueSelector::BEST_EFFORT_PRIORITY); | 173 PrioritizingTaskQueueSelector::BEST_EFFORT_PRIORITY); |
208 helper_->PumpQueue(idle_queue_index_); | 174 helper_->PumpQueue(idle_queue_index_); |
209 idle_period_state_ = new_state; | |
210 | 175 |
211 idle_period_deadline_ = idle_period_deadline; | 176 state_.UpdateState(new_state, idle_period_deadline, now); |
212 if (post_end_idle_period) { | |
213 helper_->ControlTaskRunner()->PostDelayedTask( | |
214 FROM_HERE, end_idle_period_closure_.callback(), | |
215 idle_period_deadline_ - now); | |
216 } | |
217 } | 177 } |
218 | 178 |
219 void IdleHelper::EndIdlePeriod() { | 179 void IdleHelper::EndIdlePeriod() { |
220 helper_->CheckOnValidThread(); | 180 helper_->CheckOnValidThread(); |
| 181 TRACE_EVENT0(disabled_by_default_tracing_category_, "EndIdlePeriod"); |
221 | 182 |
222 end_idle_period_closure_.Cancel(); | |
223 enable_next_long_idle_period_closure_.Cancel(); | 183 enable_next_long_idle_period_closure_.Cancel(); |
224 enable_next_long_idle_period_after_wakeup_closure_.Cancel(); | 184 on_idle_task_posted_closure_.Cancel(); |
225 | 185 |
226 // If we weren't already within an idle period then early-out. | 186 // If we weren't already within an idle period then early-out. |
227 if (!IsInIdlePeriod(idle_period_state_)) | 187 if (!IsInIdlePeriod(state_.idle_period_state())) |
228 return; | 188 return; |
229 | 189 |
230 // If we are in the ENDING_LONG_IDLE_PERIOD state we have already logged the | 190 helper_->DisableQueue(idle_queue_index_); |
231 // trace event. | 191 state_.UpdateState(IdlePeriodState::NOT_IN_IDLE_PERIOD, base::TimeTicks(), |
232 if (idle_period_state_ != IdlePeriodState::ENDING_LONG_IDLE_PERIOD) { | 192 base::TimeTicks()); |
233 bool is_tracing; | 193 } |
234 TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); | 194 |
235 if (is_tracing && !idle_period_deadline_.is_null() && | 195 void IdleHelper::WillProcessTask(const base::PendingTask& pending_task) { |
236 helper_->Now() > idle_period_deadline_) { | 196 } |
237 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( | 197 |
238 tracing_category_, idle_period_tracing_name_, this, "DeadlineOverrun", | 198 void IdleHelper::DidProcessTask(const base::PendingTask& pending_task) { |
239 idle_period_deadline_.ToInternalValue()); | 199 helper_->CheckOnValidThread(); |
| 200 TRACE_EVENT0(disabled_by_default_tracing_category_, "DidProcessTask"); |
| 201 if (IsInIdlePeriod(state_.idle_period_state()) && |
| 202 state_.idle_period_state() != |
| 203 IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED && |
| 204 helper_->Now() >= state_.idle_period_deadline()) { |
| 205 // If the idle period deadline has now been reached, either end the idle |
| 206 // period or trigger a new long-idle period. |
| 207 if (IsInLongIdlePeriod(state_.idle_period_state())) { |
| 208 EnableLongIdlePeriod(); |
| 209 } else { |
| 210 DCHECK(IdlePeriodState::IN_SHORT_IDLE_PERIOD == |
| 211 state_.idle_period_state()); |
| 212 EndIdlePeriod(); |
240 } | 213 } |
241 TRACE_EVENT_ASYNC_END0(tracing_category_, idle_period_tracing_name_, this); | |
242 } | 214 } |
| 215 } |
243 | 216 |
244 helper_->DisableQueue(idle_queue_index_); | 217 void IdleHelper::UpdateLongIdlePeriodStateAfterIdleTask() { |
245 idle_period_state_ = IdlePeriodState::NOT_IN_IDLE_PERIOD; | 218 helper_->CheckOnValidThread(); |
246 idle_period_deadline_ = base::TimeTicks(); | 219 DCHECK(IsInLongIdlePeriod(state_.idle_period_state())); |
| 220 TRACE_EVENT0(disabled_by_default_tracing_category_, |
| 221 "UpdateLongIdlePeriodStateAfterIdleTask"); |
| 222 TaskQueueManager::QueueState queue_state = |
| 223 helper_->GetQueueState(idle_queue_index_); |
| 224 if (queue_state == TaskQueueManager::QueueState::EMPTY) { |
| 225 // If there are no more idle tasks then pause long idle period ticks until a |
| 226 // new idle task is posted. |
| 227 state_.UpdateState(IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED, |
| 228 state_.idle_period_deadline(), base::TimeTicks()); |
| 229 } else if (queue_state == TaskQueueManager::QueueState::NEEDS_PUMPING) { |
| 230 // If there is still idle work to do then just start the next idle period. |
| 231 base::TimeDelta next_long_idle_period_delay; |
| 232 if (state_.idle_period_state() == |
| 233 IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE) { |
| 234 // If we are in a max deadline long idle period then start the next |
| 235 // idle period immediately. |
| 236 next_long_idle_period_delay = base::TimeDelta(); |
| 237 } else { |
| 238 // Otherwise ensure that we kick the scheduler at the right time to |
| 239 // initiate the next idle period. |
| 240 next_long_idle_period_delay = std::max( |
| 241 base::TimeDelta(), state_.idle_period_deadline() - helper_->Now()); |
| 242 } |
| 243 helper_->ControlTaskRunner()->PostDelayedTask( |
| 244 FROM_HERE, enable_next_long_idle_period_closure_.callback(), |
| 245 next_long_idle_period_delay); |
| 246 } |
| 247 } |
| 248 |
| 249 base::TimeTicks IdleHelper::CurrentIdleTaskDeadline() const { |
| 250 helper_->CheckOnValidThread(); |
| 251 return state_.idle_period_deadline(); |
| 252 } |
| 253 |
| 254 void IdleHelper::OnIdleTaskPosted() { |
| 255 TRACE_EVENT0(disabled_by_default_tracing_category_, "OnIdleTaskPosted"); |
| 256 if (idle_task_runner_->RunsTasksOnCurrentThread()) { |
| 257 OnIdleTaskPostedOnMainThread(); |
| 258 } else { |
| 259 helper_->ControlTaskRunner()->PostTask( |
| 260 FROM_HERE, on_idle_task_posted_closure_.callback()); |
| 261 } |
| 262 } |
| 263 |
| 264 void IdleHelper::OnIdleTaskPostedOnMainThread() { |
| 265 TRACE_EVENT0(disabled_by_default_tracing_category_, |
| 266 "OnIdleTaskPostedOnMainThread"); |
| 267 if (state_.idle_period_state() == |
| 268 IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { |
| 269 // Restart long idle period ticks. |
| 270 helper_->ControlTaskRunner()->PostTask( |
| 271 FROM_HERE, enable_next_long_idle_period_closure_.callback()); |
| 272 } |
| 273 } |
| 274 |
| 275 base::TimeTicks IdleHelper::WillProcessIdleTask() { |
| 276 helper_->CheckOnValidThread(); |
| 277 DCHECK(IsInIdlePeriod(state_.idle_period_state())); |
| 278 |
| 279 state_.TraceIdleIdleTaskStart(); |
| 280 return CurrentIdleTaskDeadline(); |
| 281 } |
| 282 |
| 283 void IdleHelper::DidProcessIdleTask() { |
| 284 helper_->CheckOnValidThread(); |
| 285 state_.TraceIdleIdleTaskEnd(); |
| 286 if (IsInLongIdlePeriod(state_.idle_period_state())) { |
| 287 UpdateLongIdlePeriodStateAfterIdleTask(); |
| 288 } |
247 } | 289 } |
248 | 290 |
249 // static | 291 // static |
250 bool IdleHelper::IsInIdlePeriod(IdlePeriodState state) { | 292 bool IdleHelper::IsInIdlePeriod(IdlePeriodState state) { |
251 return state != IdlePeriodState::NOT_IN_IDLE_PERIOD; | 293 return state != IdlePeriodState::NOT_IN_IDLE_PERIOD; |
252 } | 294 } |
253 | 295 |
| 296 // static |
| 297 bool IdleHelper::IsInLongIdlePeriod(IdlePeriodState state) { |
| 298 return state == IdlePeriodState::IN_LONG_IDLE_PERIOD || |
| 299 state == IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE || |
| 300 state == IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED; |
| 301 } |
| 302 |
254 bool IdleHelper::CanExceedIdleDeadlineIfRequired() const { | 303 bool IdleHelper::CanExceedIdleDeadlineIfRequired() const { |
255 TRACE_EVENT0(tracing_category_, "CanExceedIdleDeadlineIfRequired"); | 304 TRACE_EVENT0(disabled_by_default_tracing_category_, |
| 305 "CanExceedIdleDeadlineIfRequired"); |
256 helper_->CheckOnValidThread(); | 306 helper_->CheckOnValidThread(); |
257 return idle_period_state_ == | 307 return state_.idle_period_state() == |
258 IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE; | 308 IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE; |
259 } | 309 } |
260 | 310 |
261 IdleHelper::IdlePeriodState IdleHelper::SchedulerIdlePeriodState() const { | 311 IdleHelper::IdlePeriodState IdleHelper::SchedulerIdlePeriodState() const { |
| 312 return state_.idle_period_state(); |
| 313 } |
| 314 |
| 315 IdleHelper::State::State(SchedulerHelper* helper, |
| 316 const char* tracing_category, |
| 317 const char* disabled_by_default_tracing_category, |
| 318 const char* idle_period_tracing_name) |
| 319 : helper_(helper), |
| 320 idle_period_state_(IdlePeriodState::NOT_IN_IDLE_PERIOD), |
| 321 nestable_events_started_(false), |
| 322 tracing_category_(tracing_category), |
| 323 disabled_by_default_tracing_category_( |
| 324 disabled_by_default_tracing_category), |
| 325 idle_period_tracing_name_(idle_period_tracing_name) { |
| 326 } |
| 327 |
| 328 IdleHelper::State::~State() { |
| 329 } |
| 330 |
| 331 IdleHelper::IdlePeriodState IdleHelper::State::idle_period_state() const { |
| 332 helper_->CheckOnValidThread(); |
262 return idle_period_state_; | 333 return idle_period_state_; |
263 } | 334 } |
264 | 335 |
| 336 base::TimeTicks IdleHelper::State::idle_period_deadline() const { |
| 337 helper_->CheckOnValidThread(); |
| 338 return idle_period_deadline_; |
| 339 } |
| 340 |
| 341 void IdleHelper::State::UpdateState(IdlePeriodState new_state, |
| 342 base::TimeTicks new_deadline, |
| 343 base::TimeTicks optional_now) { |
| 344 helper_->CheckOnValidThread(); |
| 345 if (new_state == idle_period_state_) { |
| 346 DCHECK_EQ(new_deadline, idle_period_deadline_); |
| 347 return; |
| 348 } |
| 349 |
| 350 bool is_tracing; |
| 351 TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); |
| 352 if (is_tracing) { |
| 353 base::TimeTicks now(optional_now.is_null() ? helper_->Now() : optional_now); |
| 354 TraceEventIdlePeriodStateChange(new_state, new_deadline, now); |
| 355 idle_period_deadline_for_tracing_ = |
| 356 base::TraceTicks::Now() + (new_deadline - now); |
| 357 } |
| 358 |
| 359 idle_period_state_ = new_state; |
| 360 idle_period_deadline_ = new_deadline; |
| 361 } |
| 362 |
| 363 void IdleHelper::State::TraceIdleIdleTaskStart() { |
| 364 helper_->CheckOnValidThread(); |
| 365 |
| 366 bool is_tracing; |
| 367 TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); |
| 368 if (is_tracing && nestable_events_started_) { |
| 369 last_idle_task_trace_time_ = base::TraceTicks::Now(); |
| 370 TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0( |
| 371 tracing_category_, "RunningIdleTask", this, |
| 372 last_idle_task_trace_time_.ToInternalValue()); |
| 373 } |
| 374 } |
| 375 |
| 376 void IdleHelper::State::TraceIdleIdleTaskEnd() { |
| 377 helper_->CheckOnValidThread(); |
| 378 |
| 379 bool is_tracing; |
| 380 TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); |
| 381 if (is_tracing && nestable_events_started_) { |
| 382 if (!idle_period_deadline_for_tracing_.is_null() && |
| 383 base::TraceTicks::Now() > idle_period_deadline_for_tracing_) { |
| 384 TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0( |
| 385 tracing_category_, "DeadlineOverrun", this, |
| 386 std::max(idle_period_deadline_for_tracing_, |
| 387 last_idle_task_trace_time_).ToInternalValue()); |
| 388 TRACE_EVENT_NESTABLE_ASYNC_END0(tracing_category_, "DeadlineOverrun", |
| 389 this); |
| 390 } |
| 391 TRACE_EVENT_NESTABLE_ASYNC_END0(tracing_category_, "RunningIdleTask", this); |
| 392 } |
| 393 } |
| 394 |
| 395 void IdleHelper::State::TraceEventIdlePeriodStateChange( |
| 396 IdlePeriodState new_state, |
| 397 base::TimeTicks new_deadline, |
| 398 base::TimeTicks now) { |
| 399 TRACE_EVENT2(disabled_by_default_tracing_category_, "SetIdlePeriodState", |
| 400 "old_state", |
| 401 IdleHelper::IdlePeriodStateToString(idle_period_state_), |
| 402 "new_state", IdleHelper::IdlePeriodStateToString(new_state)); |
| 403 if (nestable_events_started_) { |
| 404 // End async tracing events for the state we are leaving. |
| 405 if (idle_period_state_ == IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { |
| 406 TRACE_EVENT_NESTABLE_ASYNC_END0(tracing_category_, "LongIdlePeriodPaused", |
| 407 this); |
| 408 } |
| 409 if (IsInLongIdlePeriod(idle_period_state_) && |
| 410 !IsInLongIdlePeriod(new_state)) { |
| 411 TRACE_EVENT_NESTABLE_ASYNC_END0(tracing_category_, "LongIdlePeriod", |
| 412 this); |
| 413 } |
| 414 if (idle_period_state_ == IdlePeriodState::IN_SHORT_IDLE_PERIOD) { |
| 415 TRACE_EVENT_NESTABLE_ASYNC_END0(tracing_category_, "ShortIdlePeriod", |
| 416 this); |
| 417 } |
| 418 if (IsInIdlePeriod(idle_period_state_) && !IsInIdlePeriod(new_state)) { |
| 419 TRACE_EVENT_NESTABLE_ASYNC_END0(tracing_category_, |
| 420 idle_period_tracing_name_, this); |
| 421 nestable_events_started_ = false; |
| 422 } |
| 423 } |
| 424 |
| 425 // Start async tracing events for the state we are entering. |
| 426 if (IsInIdlePeriod(new_state) && !IsInIdlePeriod(idle_period_state_)) { |
| 427 nestable_events_started_ = true; |
| 428 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( |
| 429 tracing_category_, idle_period_tracing_name_, this, |
| 430 "idle_period_length_ms", (new_deadline - now).ToInternalValue()); |
| 431 } |
| 432 if (new_state == IdlePeriodState::IN_SHORT_IDLE_PERIOD) { |
| 433 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(tracing_category_, "ShortIdlePeriod", |
| 434 this); |
| 435 } |
| 436 if (IsInLongIdlePeriod(new_state) && |
| 437 !IsInLongIdlePeriod(idle_period_state_)) { |
| 438 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(tracing_category_, "LongIdlePeriod", |
| 439 this); |
| 440 } |
| 441 if (new_state == IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { |
| 442 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(tracing_category_, "LongIdlePeriodPaused", |
| 443 this); |
| 444 } |
| 445 } |
| 446 |
265 // static | 447 // static |
266 const char* IdleHelper::IdlePeriodStateToString( | 448 const char* IdleHelper::IdlePeriodStateToString( |
267 IdlePeriodState idle_period_state) { | 449 IdlePeriodState idle_period_state) { |
268 switch (idle_period_state) { | 450 switch (idle_period_state) { |
269 case IdlePeriodState::NOT_IN_IDLE_PERIOD: | 451 case IdlePeriodState::NOT_IN_IDLE_PERIOD: |
270 return "not_in_idle_period"; | 452 return "not_in_idle_period"; |
271 case IdlePeriodState::IN_SHORT_IDLE_PERIOD: | 453 case IdlePeriodState::IN_SHORT_IDLE_PERIOD: |
272 return "in_short_idle_period"; | 454 return "in_short_idle_period"; |
273 case IdlePeriodState::IN_LONG_IDLE_PERIOD: | 455 case IdlePeriodState::IN_LONG_IDLE_PERIOD: |
274 return "in_long_idle_period"; | 456 return "in_long_idle_period"; |
275 case IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE: | 457 case IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE: |
276 return "in_long_idle_period_with_max_deadline"; | 458 return "in_long_idle_period_with_max_deadline"; |
277 case IdlePeriodState::ENDING_LONG_IDLE_PERIOD: | 459 case IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED: |
278 return "ending_long_idle_period"; | 460 return "in_long_idle_period_paused"; |
279 default: | 461 default: |
280 NOTREACHED(); | 462 NOTREACHED(); |
281 return nullptr; | 463 return nullptr; |
282 } | 464 } |
283 } | 465 } |
284 | 466 |
285 } // namespace scheduler | 467 } // namespace scheduler |
OLD | NEW |