Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1290)

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/base/time_domain.cc

Issue 2359493002: Prevent redundant DoWorks due to canceled delayed tasks (v2) (Closed)
Patch Set: Added a test and removed some code we probably don't need. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698