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 "platform/scheduler/base/time_domain.h" | 5 #include "platform/scheduler/base/time_domain.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "platform/scheduler/base/task_queue_impl.h" | 9 #include "platform/scheduler/base/task_queue_impl.h" |
10 #include "platform/scheduler/base/task_queue_manager_delegate.h" | 10 #include "platform/scheduler/base/task_queue_manager_delegate.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
22 void TimeDomain::RegisterQueue(internal::TaskQueueImpl* queue) { | 22 void TimeDomain::RegisterQueue(internal::TaskQueueImpl* queue) { |
23 DCHECK(main_thread_checker_.CalledOnValidThread()); | 23 DCHECK(main_thread_checker_.CalledOnValidThread()); |
24 DCHECK_EQ(queue->GetTimeDomain(), this); | 24 DCHECK_EQ(queue->GetTimeDomain(), this); |
25 } | 25 } |
26 | 26 |
27 void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) { | 27 void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) { |
28 DCHECK(main_thread_checker_.CalledOnValidThread()); | 28 DCHECK(main_thread_checker_.CalledOnValidThread()); |
29 DCHECK_EQ(queue->GetTimeDomain(), this); | 29 DCHECK_EQ(queue->GetTimeDomain(), this); |
30 UnregisterAsUpdatableTaskQueue(queue); | 30 UnregisterAsUpdatableTaskQueue(queue); |
31 | 31 |
32 // We need to remove |task_queue| from delayed_wakeup_multimap_ which is a | 32 // If present remove |task_queue| from delayed_wakeup_multimap_. |
33 // little awkward since it's keyed by time. O(n) running time. | 33 // O(log n) |
34 for (DelayedWakeupMultimap::iterator iter = delayed_wakeup_multimap_.begin(); | 34 QueueToDelayedWakeupMultimapIteratorMap::iterator it = |
35 iter != delayed_wakeup_multimap_.end();) { | 35 queue_to_delayed_wakeup_multimap_iterator_map_.find(queue); |
36 if (iter->second == queue) { | 36 |
37 // O(1) amortized. | 37 if (it == queue_to_delayed_wakeup_multimap_iterator_map_.end()) |
38 iter = delayed_wakeup_multimap_.erase(iter); | 38 return; |
39 } else { | 39 |
40 iter++; | 40 // O(1) amortized. |
41 } | 41 delayed_wakeup_multimap_.erase(it->second); |
42 } | 42 queue_to_delayed_wakeup_multimap_iterator_map_.erase(it); |
43 } | 43 } |
44 | 44 |
45 void TimeDomain::MigrateQueue(internal::TaskQueueImpl* queue, | 45 void TimeDomain::MigrateQueue(internal::TaskQueueImpl* queue, |
46 TimeDomain* destination_time_domain) { | 46 TimeDomain* destination_time_domain) { |
47 DCHECK(main_thread_checker_.CalledOnValidThread()); | 47 DCHECK(main_thread_checker_.CalledOnValidThread()); |
48 DCHECK_EQ(queue->GetTimeDomain(), this); | 48 DCHECK_EQ(queue->GetTimeDomain(), this); |
49 DCHECK(destination_time_domain); | 49 DCHECK(destination_time_domain); |
50 | 50 |
51 // Make sure we remember to update |queue| if it's got incoming immediate | 51 // Make sure we remember to update |queue| if it's got incoming immediate |
52 // work. | 52 // work. |
53 if (UnregisterAsUpdatableTaskQueue(queue)) | 53 if (UnregisterAsUpdatableTaskQueue(queue)) |
54 destination_time_domain->updatable_queue_set_.insert(queue); | 54 destination_time_domain->updatable_queue_set_.insert(queue); |
55 | 55 |
56 // If present remove |task_queue| from delayed_wakeup_multimap_. | |
57 // O(log n) | |
58 QueueToDelayedWakeupMultimapIteratorMap::iterator it = | |
59 queue_to_delayed_wakeup_multimap_iterator_map_.find(queue); | |
60 | |
61 if (it == queue_to_delayed_wakeup_multimap_iterator_map_.end()) | |
62 return; | |
63 | |
56 base::TimeTicks destination_now = destination_time_domain->Now(); | 64 base::TimeTicks destination_now = destination_time_domain->Now(); |
57 // We need to remove |task_queue| from delayed_wakeup_multimap_ which is a | 65 destination_time_domain->ScheduleDelayedWork(queue, it->second->first, |
58 // little awkward since it's keyed by time. O(n) running time. | 66 destination_now); |
59 for (DelayedWakeupMultimap::iterator iter = delayed_wakeup_multimap_.begin(); | 67 |
60 iter != delayed_wakeup_multimap_.end();) { | 68 // O(1) amortized. |
61 if (iter->second == queue) { | 69 delayed_wakeup_multimap_.erase(it->second); |
62 destination_time_domain->ScheduleDelayedWork(queue, iter->first, | 70 queue_to_delayed_wakeup_multimap_iterator_map_.erase(it); |
63 destination_now); | |
64 // O(1) amortized. | |
65 iter = delayed_wakeup_multimap_.erase(iter); | |
66 } else { | |
67 iter++; | |
68 } | |
69 } | |
70 } | 71 } |
71 | 72 |
72 void TimeDomain::ScheduleDelayedWork(internal::TaskQueueImpl* queue, | 73 void TimeDomain::ScheduleDelayedWork(internal::TaskQueueImpl* queue, |
73 base::TimeTicks delayed_run_time, | 74 base::TimeTicks delayed_run_time, |
74 base::TimeTicks now) { | 75 base::TimeTicks now) { |
75 DCHECK(main_thread_checker_.CalledOnValidThread()); | 76 DCHECK(main_thread_checker_.CalledOnValidThread()); |
76 if (delayed_wakeup_multimap_.empty() || | 77 // We only want to store a single wakeup per queue, so we need to remove any |
77 delayed_run_time < delayed_wakeup_multimap_.begin()->first) { | 78 // previously registered wake up for |queue|. |
78 base::TimeDelta delay = std::max(base::TimeDelta(), delayed_run_time - now); | 79 QueueToDelayedWakeupMultimapIteratorMap::iterator it = |
79 RequestWakeup(now, delay); | 80 queue_to_delayed_wakeup_multimap_iterator_map_.find(queue); |
81 | |
82 if (it != queue_to_delayed_wakeup_multimap_iterator_map_.end()) { | |
83 // TODO(alexclarke): Use C++17 extract & insert to more efficiently modify | |
84 // |queue_to_delayed_wakeup_multimap_iterator_map_|. | |
85 delayed_wakeup_multimap_.erase(it->second); | |
86 | |
87 if (delayed_wakeup_multimap_.empty() || | |
Sami
2016/09/22 11:20:54
nit: Feel free to ignore, but I'm wondering if thi
alex clarke (OOO till 29th)
2016/09/22 16:24:21
Done.
| |
88 delayed_run_time < delayed_wakeup_multimap_.begin()->first) { | |
89 base::TimeDelta delay = | |
90 std::max(base::TimeDelta(), delayed_run_time - now); | |
91 RequestWakeup(now, delay); | |
92 } | |
93 | |
94 it->second = delayed_wakeup_multimap_.insert( | |
95 std::make_pair(delayed_run_time, queue)); | |
96 } else { | |
97 if (delayed_wakeup_multimap_.empty() || | |
98 delayed_run_time < delayed_wakeup_multimap_.begin()->first) { | |
99 base::TimeDelta delay = | |
100 std::max(base::TimeDelta(), delayed_run_time - now); | |
101 RequestWakeup(now, delay); | |
102 } | |
103 | |
104 // Insert the wakeup and store the map iterator for later convenience. | |
105 queue_to_delayed_wakeup_multimap_iterator_map_.insert( | |
106 std::make_pair(queue, delayed_wakeup_multimap_.insert( | |
107 std::make_pair(delayed_run_time, queue)))); | |
80 } | 108 } |
81 | 109 |
82 delayed_wakeup_multimap_.insert(std::make_pair(delayed_run_time, queue)); | |
83 if (observer_) | 110 if (observer_) |
84 observer_->OnTimeDomainHasDelayedWork(); | 111 observer_->OnTimeDomainHasDelayedWork(); |
85 } | 112 } |
86 | 113 |
87 void TimeDomain::CancelDelayedWork(internal::TaskQueueImpl* queue, | |
88 base::TimeTicks delayed_run_time) { | |
89 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
90 | |
91 auto iterpair = delayed_wakeup_multimap_.equal_range(delayed_run_time); | |
92 for (auto it = iterpair.first; it != iterpair.second; ++it) { | |
93 if (it->second == queue) { | |
94 base::TimeTicks prev_first_wakeup = | |
95 delayed_wakeup_multimap_.begin()->first; | |
96 | |
97 // Note we only erase the entry corresponding to |queue|, there might be | |
98 // other queues that happen to require a wake up at |delayed_run_time| | |
99 // which we must respect. | |
100 delayed_wakeup_multimap_.erase(it); | |
101 | |
102 // If |delayed_wakeup_multimap_| is now empty, there's nothing to be done. | |
103 // Sadly the base TaskRunner does and some OSes don't support cancellation | |
104 // so we can't cancel something requested with RequestWakeup. | |
105 if (delayed_wakeup_multimap_.empty()) | |
106 break; | |
107 | |
108 base::TimeTicks first_wakeup = delayed_wakeup_multimap_.begin()->first; | |
109 | |
110 // If the first_wakeup hasn't changed we don't need to do anything, the | |
111 // wakeup was already requested. | |
112 if (first_wakeup == prev_first_wakeup) | |
113 break; | |
114 | |
115 // The first wakeup has changed, we need to re-schedule. | |
116 base::TimeTicks now = Now(); | |
117 base::TimeDelta delay = std::max(base::TimeDelta(), first_wakeup - now); | |
118 RequestWakeup(now, delay); | |
119 break; | |
120 } | |
121 } | |
122 } | |
123 | |
124 void TimeDomain::RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue) { | 114 void TimeDomain::RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue) { |
125 { | 115 { |
126 base::AutoLock lock(newly_updatable_lock_); | 116 base::AutoLock lock(newly_updatable_lock_); |
127 newly_updatable_.push_back(queue); | 117 newly_updatable_.push_back(queue); |
128 } | 118 } |
129 if (observer_) | 119 if (observer_) |
130 observer_->OnTimeDomainHasImmediateWork(); | 120 observer_->OnTimeDomainHasImmediateWork(); |
131 } | 121 } |
132 | 122 |
133 bool TimeDomain::UnregisterAsUpdatableTaskQueue( | 123 bool TimeDomain::UnregisterAsUpdatableTaskQueue( |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
179 updatable_queue_set_.insert(newly_updatable_.back()); | 169 updatable_queue_set_.insert(newly_updatable_.back()); |
180 newly_updatable_.pop_back(); | 170 newly_updatable_.pop_back(); |
181 } | 171 } |
182 } | 172 } |
183 | 173 |
184 void TimeDomain::WakeupReadyDelayedQueues(LazyNow* lazy_now) { | 174 void TimeDomain::WakeupReadyDelayedQueues(LazyNow* lazy_now) { |
185 DCHECK(main_thread_checker_.CalledOnValidThread()); | 175 DCHECK(main_thread_checker_.CalledOnValidThread()); |
186 // Wake up any queues with pending delayed work. Note std::multipmap stores | 176 // Wake up any queues with pending delayed work. Note std::multipmap stores |
187 // the elements sorted by key, so the begin() iterator points to the earliest | 177 // the elements sorted by key, so the begin() iterator points to the earliest |
188 // queue to wakeup. | 178 // queue to wakeup. |
189 std::set<internal::TaskQueueImpl*> dedup_set; | |
190 while (!delayed_wakeup_multimap_.empty()) { | 179 while (!delayed_wakeup_multimap_.empty()) { |
191 DelayedWakeupMultimap::iterator next_wakeup = | 180 DelayedWakeupMultimap::iterator next_wakeup = |
192 delayed_wakeup_multimap_.begin(); | 181 delayed_wakeup_multimap_.begin(); |
193 if (next_wakeup->first > lazy_now->Now()) | 182 if (next_wakeup->first > lazy_now->Now()) |
194 break; | 183 break; |
195 // A queue could have any number of delayed tasks pending so it's worthwhile | 184 |
196 // deduping calls to UpdateDelayedWorkQueue since it takes a lock. | 185 internal::TaskQueueImpl* queue = next_wakeup->second; |
197 // NOTE the order in which these are called matters since the order | 186 |
198 // in which EnqueueTaskLocks is called is respected when choosing which | 187 // O(1) amortized. |
199 // queue to execute a task from. | |
200 if (dedup_set.insert(next_wakeup->second).second) { | |
201 next_wakeup->second->MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); | |
202 } | |
203 delayed_wakeup_multimap_.erase(next_wakeup); | 188 delayed_wakeup_multimap_.erase(next_wakeup); |
189 // O(log n). | |
190 queue_to_delayed_wakeup_multimap_iterator_map_.erase(queue); | |
191 | |
192 queue->WakeUpForDelayedWork(lazy_now); | |
204 } | 193 } |
205 } | 194 } |
206 | 195 |
207 void TimeDomain::ClearExpiredWakeups() { | |
208 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
209 LazyNow lazy_now(CreateLazyNow()); | |
210 while (!delayed_wakeup_multimap_.empty()) { | |
211 DelayedWakeupMultimap::iterator next_wakeup = | |
212 delayed_wakeup_multimap_.begin(); | |
213 if (next_wakeup->first > lazy_now.Now()) | |
214 break; | |
215 delayed_wakeup_multimap_.erase(next_wakeup); | |
216 } | |
217 } | |
218 | |
219 bool TimeDomain::NextScheduledRunTime(base::TimeTicks* out_time) const { | 196 bool TimeDomain::NextScheduledRunTime(base::TimeTicks* out_time) const { |
220 DCHECK(main_thread_checker_.CalledOnValidThread()); | 197 DCHECK(main_thread_checker_.CalledOnValidThread()); |
221 if (delayed_wakeup_multimap_.empty()) | 198 if (delayed_wakeup_multimap_.empty()) |
222 return false; | 199 return false; |
223 | 200 |
224 *out_time = delayed_wakeup_multimap_.begin()->first; | 201 *out_time = delayed_wakeup_multimap_.begin()->first; |
225 return true; | 202 return true; |
226 } | 203 } |
227 | 204 |
228 bool TimeDomain::NextScheduledTaskQueue(TaskQueue** out_task_queue) const { | 205 bool TimeDomain::NextScheduledTaskQueue(TaskQueue** out_task_queue) const { |
(...skipping 16 matching lines...) Expand all Loading... | |
245 if (!delayed_wakeup_multimap_.empty()) { | 222 if (!delayed_wakeup_multimap_.empty()) { |
246 base::TimeDelta delay = delayed_wakeup_multimap_.begin()->first - Now(); | 223 base::TimeDelta delay = delayed_wakeup_multimap_.begin()->first - Now(); |
247 state->SetDouble("next_delay_ms", delay.InMillisecondsF()); | 224 state->SetDouble("next_delay_ms", delay.InMillisecondsF()); |
248 } | 225 } |
249 AsValueIntoInternal(state); | 226 AsValueIntoInternal(state); |
250 state->EndDictionary(); | 227 state->EndDictionary(); |
251 } | 228 } |
252 | 229 |
253 } // namespace scheduler | 230 } // namespace scheduler |
254 } // namespace blink | 231 } // namespace blink |
OLD | NEW |