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

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

Issue 2419793002: [Reland] Optimize blink scheduler with an intrusive heap (Closed)
Patch Set: Fix bug in MoveHoleDown 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"
11 #include "platform/scheduler/base/work_queue.h" 11 #include "platform/scheduler/base/work_queue.h"
12 12
13 namespace blink { 13 namespace blink {
14 namespace scheduler { 14 namespace scheduler {
15 15
16 struct TimeDomain::HeapElement {
17 base::TimeTicks key;
18 internal::TaskQueueImpl* value;
19
20 bool operator<=(const HeapElement& other) const { return key <= other.key; }
21
22 void SetHeapIndex(size_t i) { value->set_heap_index(i); }
23 };
24
16 TimeDomain::TimeDomain(Observer* observer) : observer_(observer) {} 25 TimeDomain::TimeDomain(Observer* observer) : observer_(observer) {}
17 26
18 TimeDomain::~TimeDomain() { 27 TimeDomain::~TimeDomain() {
19 DCHECK(main_thread_checker_.CalledOnValidThread()); 28 DCHECK(main_thread_checker_.CalledOnValidThread());
20 } 29 }
21 30
22 void TimeDomain::RegisterQueue(internal::TaskQueueImpl* queue) { 31 void TimeDomain::RegisterQueue(internal::TaskQueueImpl* queue) {
23 DCHECK(main_thread_checker_.CalledOnValidThread()); 32 DCHECK(main_thread_checker_.CalledOnValidThread());
24 DCHECK_EQ(queue->GetTimeDomain(), this); 33 DCHECK_EQ(queue->GetTimeDomain(), this);
25 } 34 }
26 35
27 void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) { 36 void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) {
28 DCHECK(main_thread_checker_.CalledOnValidThread()); 37 DCHECK(main_thread_checker_.CalledOnValidThread());
29 DCHECK_EQ(queue->GetTimeDomain(), this); 38 DCHECK_EQ(queue->GetTimeDomain(), this);
30 UnregisterAsUpdatableTaskQueue(queue); 39 UnregisterAsUpdatableTaskQueue(queue);
31 40
32 // If present remove |task_queue| from delayed_wakeup_multimap_. 41 // If no wakeup has been requested then bail out.
33 // O(log n) 42 if (queue->time_domain_wakeup().is_null())
34 QueueToDelayedWakeupMultimapIteratorMap::iterator it =
35 queue_to_delayed_wakeup_multimap_iterator_map_.find(queue);
36
37 if (it == queue_to_delayed_wakeup_multimap_iterator_map_.end())
38 return; 43 return;
39 44
40 // O(1) amortized. 45 // O(log n)
41 delayed_wakeup_multimap_.erase(it->second); 46 delayed_wakeup_queue_.eraseHeapIndex(queue->heap_index());
42 queue_to_delayed_wakeup_multimap_iterator_map_.erase(it); 47 queue->set_time_domain_wakeup(base::TimeTicks());
48 queue->set_heap_index(0u);
Sami 2016/10/14 07:26:16 Could we make 0u a named constant so 1-basedness o
alex clarke (OOO till 29th) 2016/10/14 13:55:35 I think I should actually move this into the templ
43 } 49 }
44 50
45 void TimeDomain::MigrateQueue(internal::TaskQueueImpl* queue, 51 void TimeDomain::MigrateQueue(internal::TaskQueueImpl* queue,
46 TimeDomain* destination_time_domain) { 52 TimeDomain* destination_time_domain) {
47 DCHECK(main_thread_checker_.CalledOnValidThread()); 53 DCHECK(main_thread_checker_.CalledOnValidThread());
48 DCHECK_EQ(queue->GetTimeDomain(), this); 54 DCHECK_EQ(queue->GetTimeDomain(), this);
49 DCHECK(destination_time_domain); 55 DCHECK(destination_time_domain);
50 56
51 // Make sure we remember to update |queue| if it's got incoming immediate 57 // Make sure we remember to update |queue| if it's got incoming immediate
52 // work. 58 // work.
53 if (UnregisterAsUpdatableTaskQueue(queue)) 59 if (UnregisterAsUpdatableTaskQueue(queue))
54 destination_time_domain->updatable_queue_set_.insert(queue); 60 destination_time_domain->updatable_queue_set_.insert(queue);
55 61
56 // If present remove |task_queue| from delayed_wakeup_multimap_. 62 // If no wakeup has been requested then bail out.
57 // O(log n) 63 if (queue->time_domain_wakeup().is_null())
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; 64 return;
63 65
66 // O(log n)
67 delayed_wakeup_queue_.eraseHeapIndex(queue->heap_index());
68 queue->set_time_domain_wakeup(base::TimeTicks());
69 queue->set_heap_index(0u);
70
64 base::TimeTicks destination_now = destination_time_domain->Now(); 71 base::TimeTicks destination_now = destination_time_domain->Now();
65 destination_time_domain->ScheduleDelayedWork(queue, it->second->first, 72 destination_time_domain->ScheduleDelayedWork(
66 destination_now); 73 queue, queue->time_domain_wakeup(), destination_now);
67
68 // O(1) amortized.
69 delayed_wakeup_multimap_.erase(it->second);
70 queue_to_delayed_wakeup_multimap_iterator_map_.erase(it);
71 } 74 }
72 75
73 void TimeDomain::ScheduleDelayedWork(internal::TaskQueueImpl* queue, 76 void TimeDomain::ScheduleDelayedWork(internal::TaskQueueImpl* queue,
74 base::TimeTicks delayed_run_time, 77 base::TimeTicks delayed_run_time,
75 base::TimeTicks now) { 78 base::TimeTicks now) {
76 DCHECK(main_thread_checker_.CalledOnValidThread()); 79 DCHECK(main_thread_checker_.CalledOnValidThread());
77 // We only want to store a single wakeup per queue, so we need to remove any 80 // We only want to store a single wakeup per queue, so we need to remove any
78 // previously registered wake up for |queue|. 81 // previously registered wake up for |queue|.
79 QueueToDelayedWakeupMultimapIteratorMap::iterator it = 82 if (!queue->time_domain_wakeup().is_null()) {
80 queue_to_delayed_wakeup_multimap_iterator_map_.find(queue); 83 delayed_wakeup_queue_.eraseHeapIndex(queue->heap_index());
84 queue->set_time_domain_wakeup(base::TimeTicks());
85 queue->set_heap_index(0u);
86 }
81 87
82 if (it != queue_to_delayed_wakeup_multimap_iterator_map_.end()) 88 if (delayed_wakeup_queue_.empty() ||
83 delayed_wakeup_multimap_.erase(it->second); 89 delayed_run_time < delayed_wakeup_queue_.min().key) {
84
85 if (delayed_wakeup_multimap_.empty() ||
86 delayed_run_time < delayed_wakeup_multimap_.begin()->first) {
87 base::TimeDelta delay = std::max(base::TimeDelta(), delayed_run_time - now); 90 base::TimeDelta delay = std::max(base::TimeDelta(), delayed_run_time - now);
88 RequestWakeup(now, delay); 91 RequestWakeup(now, delay);
89 } 92 }
90 93
91 if (it != queue_to_delayed_wakeup_multimap_iterator_map_.end()) { 94 delayed_wakeup_queue_.insert({delayed_run_time, queue});
Sami 2016/10/14 07:26:16 Would it make sense to add an emplace() for this?
alex clarke (OOO till 29th) 2016/10/14 13:55:35 The thing about emplace is, if we're gonna do it w
92 // TODO(alexclarke): Use C++17 extract & insert to more efficiently modify 95 queue->set_time_domain_wakeup(delayed_run_time);
93 // |queue_to_delayed_wakeup_multimap_iterator_map_|.
94 it->second = delayed_wakeup_multimap_.insert({delayed_run_time, queue});
95 } else {
96 // Insert the wakeup and store the map iterator for later convenience.
97 queue_to_delayed_wakeup_multimap_iterator_map_.insert(
98 {queue, delayed_wakeup_multimap_.insert({delayed_run_time, queue})});
99 }
100 96
101 if (observer_) 97 if (observer_)
102 observer_->OnTimeDomainHasDelayedWork(queue); 98 observer_->OnTimeDomainHasDelayedWork(queue);
103 } 99 }
104 100
105 void TimeDomain::RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue) { 101 void TimeDomain::RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue) {
106 { 102 {
107 base::AutoLock lock(newly_updatable_lock_); 103 base::AutoLock lock(newly_updatable_lock_);
108 newly_updatable_.push_back(queue); 104 newly_updatable_.push_back(queue);
109 } 105 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 updatable_queue_set_.insert(newly_updatable_.back()); 156 updatable_queue_set_.insert(newly_updatable_.back());
161 newly_updatable_.pop_back(); 157 newly_updatable_.pop_back();
162 } 158 }
163 } 159 }
164 160
165 void TimeDomain::WakeupReadyDelayedQueues(LazyNow* lazy_now) { 161 void TimeDomain::WakeupReadyDelayedQueues(LazyNow* lazy_now) {
166 DCHECK(main_thread_checker_.CalledOnValidThread()); 162 DCHECK(main_thread_checker_.CalledOnValidThread());
167 // Wake up any queues with pending delayed work. Note std::multipmap stores 163 // Wake up any queues with pending delayed work. Note std::multipmap stores
168 // the elements sorted by key, so the begin() iterator points to the earliest 164 // the elements sorted by key, so the begin() iterator points to the earliest
169 // queue to wakeup. 165 // queue to wakeup.
170 while (!delayed_wakeup_multimap_.empty()) { 166 while (!delayed_wakeup_queue_.empty() &&
171 DelayedWakeupMultimap::iterator next_wakeup = 167 delayed_wakeup_queue_.min().key <= lazy_now->Now()) {
172 delayed_wakeup_multimap_.begin(); 168 internal::TaskQueueImpl* queue = delayed_wakeup_queue_.min().value;
173 if (next_wakeup->first > lazy_now->Now()) 169 // O(log n)
174 break; 170 delayed_wakeup_queue_.eraseMin();
175 171
176 internal::TaskQueueImpl* queue = next_wakeup->second; 172 queue->set_time_domain_wakeup(base::TimeTicks());
177
178 // O(1) amortized.
179 delayed_wakeup_multimap_.erase(next_wakeup);
180 // O(log n).
181 queue_to_delayed_wakeup_multimap_iterator_map_.erase(queue);
182
183 queue->WakeUpForDelayedWork(lazy_now); 173 queue->WakeUpForDelayedWork(lazy_now);
184 } 174 }
185 } 175 }
186 176
187 bool TimeDomain::NextScheduledRunTime(base::TimeTicks* out_time) const { 177 bool TimeDomain::NextScheduledRunTime(base::TimeTicks* out_time) const {
188 DCHECK(main_thread_checker_.CalledOnValidThread()); 178 DCHECK(main_thread_checker_.CalledOnValidThread());
189 if (delayed_wakeup_multimap_.empty()) 179 if (delayed_wakeup_queue_.empty())
190 return false; 180 return false;
191 181
192 *out_time = delayed_wakeup_multimap_.begin()->first; 182 *out_time = delayed_wakeup_queue_.min().key;
193 return true; 183 return true;
194 } 184 }
195 185
196 bool TimeDomain::NextScheduledTaskQueue(TaskQueue** out_task_queue) const { 186 bool TimeDomain::NextScheduledTaskQueue(TaskQueue** out_task_queue) const {
197 DCHECK(main_thread_checker_.CalledOnValidThread()); 187 DCHECK(main_thread_checker_.CalledOnValidThread());
198 if (delayed_wakeup_multimap_.empty()) 188 if (delayed_wakeup_queue_.empty())
199 return false; 189 return false;
200 190
201 *out_task_queue = delayed_wakeup_multimap_.begin()->second; 191 *out_task_queue = delayed_wakeup_queue_.min().value;
202 return true; 192 return true;
203 } 193 }
204 194
205 void TimeDomain::AsValueInto(base::trace_event::TracedValue* state) const { 195 void TimeDomain::AsValueInto(base::trace_event::TracedValue* state) const {
206 state->BeginDictionary(); 196 state->BeginDictionary();
207 state->SetString("name", GetName()); 197 state->SetString("name", GetName());
208 state->BeginArray("updatable_queue_set"); 198 state->BeginArray("updatable_queue_set");
209 for (auto* queue : updatable_queue_set_) 199 for (auto* queue : updatable_queue_set_)
210 state->AppendString(queue->GetName()); 200 state->AppendString(queue->GetName());
211 state->EndArray(); 201 state->EndArray();
212 state->SetInteger("registered_delay_count", delayed_wakeup_multimap_.size()); 202 state->SetInteger("registered_delay_count", delayed_wakeup_queue_.size());
213 if (!delayed_wakeup_multimap_.empty()) { 203 if (!delayed_wakeup_queue_.empty()) {
214 base::TimeDelta delay = delayed_wakeup_multimap_.begin()->first - Now(); 204 base::TimeDelta delay = delayed_wakeup_queue_.min().key - Now();
215 state->SetDouble("next_delay_ms", delay.InMillisecondsF()); 205 state->SetDouble("next_delay_ms", delay.InMillisecondsF());
216 } 206 }
217 AsValueIntoInternal(state); 207 AsValueIntoInternal(state);
218 state->EndDictionary(); 208 state->EndDictionary();
219 } 209 }
220 210
221 } // namespace scheduler 211 } // namespace scheduler
222 } // namespace blink 212 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698