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