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

Side by Side Diff: content/renderer/scheduler/task_queue_manager.cc

Issue 962273002: Experimental: Chrome side of killing the blink timer heap (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Minor tweaks Created 5 years, 9 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "content/renderer/scheduler/task_queue_manager.h" 5 #include "content/renderer/scheduler/task_queue_manager.h"
6 6
7 #include <queue> 7 #include <queue>
8 #include <set>
8 9
9 #include "base/bind.h" 10 #include "base/bind.h"
10 #include "base/trace_event/trace_event.h" 11 #include "base/trace_event/trace_event.h"
11 #include "base/trace_event/trace_event_argument.h" 12 #include "base/trace_event/trace_event_argument.h"
12 #include "cc/test/test_now_source.h" 13 #include "cc/test/test_now_source.h"
13 #include "content/renderer/scheduler/task_queue_selector.h" 14 #include "content/renderer/scheduler/task_queue_selector.h"
14 15
15 namespace { 16 namespace {
16 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max(); 17 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max();
17 } 18 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 NON_NESTABLE, 61 NON_NESTABLE,
61 }; 62 };
62 63
63 ~TaskQueue() override; 64 ~TaskQueue() override;
64 65
65 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here, 66 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here,
66 const base::Closure& task, 67 const base::Closure& task,
67 base::TimeDelta delay, 68 base::TimeDelta delay,
68 TaskType task_type); 69 TaskType task_type);
69 70
71 // Delayed task posted to the chromium run loop, which calls
72 // ScheduleDelayedWorkLocked to enqueue any delayed timers which should be run
73 // now.
74 void KickDelayedTasks();
75
76 // Enqueues any delayed timers which should be run now, and (maybe) posts
77 // KickDelayedTasks if there isn't already a timer posted on the chromium
78 // runloop for the next task's scheduled run time.
79 bool ScheduleDelayedWorkLocked(base::TimeTicks now);
80
70 // Adds a task at the end of the incoming task queue and schedules a call to 81 // Adds a task at the end of the incoming task queue and schedules a call to
71 // TaskQueueManager::DoWork() if the incoming queue was empty and automatic 82 // TaskQueueManager::DoWork() if the incoming queue was empty and automatic
72 // pumping is enabled. Can be called on an arbitrary thread. 83 // pumping is enabled. Can be called on an arbitrary thread.
73 void EnqueueTask(const base::PendingTask& pending_task); 84 void EnqueueTask(const base::PendingTask& pending_task);
74 85
75 void PumpQueueLocked(); 86 void PumpQueueLocked();
76 bool ShouldAutoPumpQueueLocked( 87 bool ShouldAutoPumpQueueLocked(
77 TaskQueueManager::WorkQueueUpdateEventType event_type); 88 TaskQueueManager::WorkQueueUpdateEventType event_type);
78 void EnqueueTaskLocked(const base::PendingTask& pending_task); 89 void EnqueueTaskLocked(const base::PendingTask& pending_task);
79 90
80 void TraceQueueSize(bool is_locked) const; 91 void TraceQueueSize(bool is_locked) const;
81 static const char* PumpPolicyToString( 92 static const char* PumpPolicyToString(
82 TaskQueueManager::PumpPolicy pump_policy); 93 TaskQueueManager::PumpPolicy pump_policy);
83 static void QueueAsValueInto(const base::TaskQueue& queue, 94 static void QueueAsValueInto(const base::TaskQueue& queue,
84 base::trace_event::TracedValue* state); 95 base::trace_event::TracedValue* state);
85 static void TaskAsValueInto(const base::PendingTask& task, 96 static void TaskAsValueInto(const base::PendingTask& task,
86 base::trace_event::TracedValue* state); 97 base::trace_event::TracedValue* state);
87 98
88 // This lock protects all members except the work queue. 99 // This lock protects all members except the work queue.
89 mutable base::Lock lock_; 100 mutable base::Lock lock_;
90 TaskQueueManager* task_queue_manager_; 101 TaskQueueManager* task_queue_manager_;
91 base::TaskQueue incoming_queue_; 102 base::TaskQueue incoming_queue_;
92 TaskQueueManager::PumpPolicy pump_policy_; 103 TaskQueueManager::PumpPolicy pump_policy_;
93 const char* name_; 104 const char* name_;
94 std::priority_queue<base::TimeTicks, 105 base::DelayedTaskQueue delayed_task_queue_;
95 std::vector<base::TimeTicks>, 106 std::set<base::TimeTicks> in_flight_kick_delayed_tasks_;
96 std::greater<base::TimeTicks>> delayed_task_run_times_;
97 107
98 base::TaskQueue work_queue_; 108 base::TaskQueue work_queue_;
99 109
100 DISALLOW_COPY_AND_ASSIGN(TaskQueue); 110 DISALLOW_COPY_AND_ASSIGN(TaskQueue);
101 }; 111 };
102 112
103 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager) 113 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager)
104 : task_queue_manager_(task_queue_manager), 114 : task_queue_manager_(task_queue_manager),
105 pump_policy_(TaskQueueManager::PumpPolicy::AUTO), 115 pump_policy_(TaskQueueManager::PumpPolicy::AUTO),
106 name_(nullptr) { 116 name_(nullptr) {
107 } 117 }
108 118
109 TaskQueue::~TaskQueue() { 119 TaskQueue::~TaskQueue() {
110 } 120 }
111 121
112 void TaskQueue::WillDeleteTaskQueueManager() { 122 void TaskQueue::WillDeleteTaskQueueManager() {
113 base::AutoLock lock(lock_); 123 base::AutoLock lock(lock_);
114 task_queue_manager_ = nullptr; 124 task_queue_manager_ = nullptr;
125
126 // Clear all delayed tasks because we need them to be deleted before the blink
127 // heap goes away.
128 while (!delayed_task_queue_.empty())
Sami 2015/02/27 18:22:33 Is there a clear() or reset() that does this in on
alex clarke (OOO till 29th) 2015/03/03 10:11:15 Irritatingly no :( http://en.cppreference.com/w
rmcilroy 2015/03/03 10:22:21 One option would be to just make it a scoped_ptr<b
129 delayed_task_queue_.pop();
115 } 130 }
116 131
117 bool TaskQueue::RunsTasksOnCurrentThread() const { 132 bool TaskQueue::RunsTasksOnCurrentThread() const {
118 base::AutoLock lock(lock_); 133 base::AutoLock lock(lock_);
119 if (!task_queue_manager_) 134 if (!task_queue_manager_)
120 return false; 135 return false;
121 return task_queue_manager_->RunsTasksOnCurrentThread(); 136 return task_queue_manager_->RunsTasksOnCurrentThread();
122 } 137 }
123 138
124 bool TaskQueue::PostDelayedTaskImpl(const tracked_objects::Location& from_here, 139 bool TaskQueue::PostDelayedTaskImpl(const tracked_objects::Location& from_here,
125 const base::Closure& task, 140 const base::Closure& task,
126 base::TimeDelta delay, 141 base::TimeDelta delay,
127 TaskType task_type) { 142 TaskType task_type) {
128 base::AutoLock lock(lock_); 143 base::AutoLock lock(lock_);
129 if (!task_queue_manager_) 144 if (!task_queue_manager_)
130 return false; 145 return false;
131 146
132 base::PendingTask pending_task(from_here, task, base::TimeTicks(), 147 base::PendingTask pending_task(from_here, task, base::TimeTicks(),
133 task_type != TaskType::NON_NESTABLE); 148 task_type != TaskType::NON_NESTABLE);
134 task_queue_manager_->DidQueueTask(&pending_task); 149 task_queue_manager_->DidQueueTask(&pending_task);
135 150
136 if (delay > base::TimeDelta()) { 151 if (delay > base::TimeDelta()) {
137 pending_task.delayed_run_time = task_queue_manager_->Now() + delay; 152 base::TimeTicks now = task_queue_manager_->Now();
138 delayed_task_run_times_.push(pending_task.delayed_run_time); 153 pending_task.delayed_run_time = now + delay;
139 return task_queue_manager_->PostDelayedTask( 154 delayed_task_queue_.push(pending_task);
140 FROM_HERE, Bind(&TaskQueue::EnqueueTask, this, pending_task), delay); 155 // If we changed the topmost task, then it is time to reschedule.
156 if (delayed_task_queue_.top().task.Equals(pending_task.task))
157 return ScheduleDelayedWorkLocked(now);
158 return true;
rmcilroy 2015/03/02 13:53:57 drive-by comment: I'm wondering if it be simpler j
alex clarke (OOO till 29th) 2015/03/02 16:08:10 That's a really interesting idea. I quite like th
Sami 2015/03/02 16:38:33 As one more data point, this comment here suggests
rmcilroy 2015/03/03 10:22:21 As discussed offline, the message_loop goes to a f
alex clarke (OOO till 29th) 2015/03/03 16:40:26 Circling back on this. I tried it: https://coder
141 } 159 }
142 EnqueueTaskLocked(pending_task); 160 EnqueueTaskLocked(pending_task);
143 return true; 161 return true;
144 } 162 }
145 163
164 bool TaskQueue::ScheduleDelayedWorkLocked(base::TimeTicks now) {
165 lock_.AssertAcquired();
166
167 // Enqueue all delayed tasks that should be running now.
Sami 2015/03/02 16:38:33 base::MessageLoop always interleaves delayed and n
alex clarke (OOO till 29th) 2015/03/03 16:40:26 I think that adding a TimerQueue should help a lot
168 while (!delayed_task_queue_.empty() &&
169 delayed_task_queue_.top().delayed_run_time <= now) {
170 in_flight_kick_delayed_tasks_.erase(
171 delayed_task_queue_.top().delayed_run_time);
172 EnqueueTaskLocked(delayed_task_queue_.top());
173 delayed_task_queue_.pop();
174 }
175 // Any remaining tasks are in the future, so queue a task to kick them.
176 if (!delayed_task_queue_.empty()) {
177 base::TimeTicks next_run_time = delayed_task_queue_.top().delayed_run_time;
178 // Make sure we don't have more than one KickDelayedTasks posted for a
179 // particular scheduled run time (note it's fine to have multiple ones in
180 // flight for distinct run times).
181 if (in_flight_kick_delayed_tasks_.find(next_run_time) ==
182 in_flight_kick_delayed_tasks_.end()) {
183 in_flight_kick_delayed_tasks_.insert(next_run_time);
184 base::TimeDelta delay = next_run_time - now;
185 return task_queue_manager_->PostDelayedTask(
186 FROM_HERE, Bind(&TaskQueue::KickDelayedTasks, this), delay);
187 }
188 }
189 return true;
190 }
191
192 void TaskQueue::KickDelayedTasks() {
193 base::AutoLock lock(lock_);
194 ScheduleDelayedWorkLocked(task_queue_manager_->Now());
195 }
196
146 bool TaskQueue::IsQueueEmpty() const { 197 bool TaskQueue::IsQueueEmpty() const {
147 if (!work_queue_.empty()) 198 if (!work_queue_.empty())
148 return false; 199 return false;
149 200
150 { 201 {
151 base::AutoLock lock(lock_); 202 base::AutoLock lock(lock_);
152 return incoming_queue_.empty(); 203 return incoming_queue_.empty();
153 } 204 }
154 } 205 }
155 206
(...skipping 11 matching lines...) Expand all
167 } 218 }
168 219
169 bool TaskQueue::UpdateWorkQueue( 220 bool TaskQueue::UpdateWorkQueue(
170 base::TimeTicks* next_pending_delayed_task, 221 base::TimeTicks* next_pending_delayed_task,
171 TaskQueueManager::WorkQueueUpdateEventType event_type) { 222 TaskQueueManager::WorkQueueUpdateEventType event_type) {
172 if (!work_queue_.empty()) 223 if (!work_queue_.empty())
173 return true; 224 return true;
174 225
175 { 226 {
176 base::AutoLock lock(lock_); 227 base::AutoLock lock(lock_);
177 if (!delayed_task_run_times_.empty()) { 228 if (!delayed_task_queue_.empty()) {
178 *next_pending_delayed_task = 229 *next_pending_delayed_task =
179 std::min(*next_pending_delayed_task, delayed_task_run_times_.top()); 230 std::min(*next_pending_delayed_task,
231 delayed_task_queue_.top().delayed_run_time);
180 } 232 }
181 if (!ShouldAutoPumpQueueLocked(event_type)) 233 if (!ShouldAutoPumpQueueLocked(event_type))
182 return false; 234 return false;
183 work_queue_.Swap(&incoming_queue_); 235 work_queue_.Swap(&incoming_queue_);
184 TraceQueueSize(true); 236 TraceQueueSize(true);
185 return true; 237 return true;
186 } 238 }
187 } 239 }
188 240
189 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() { 241 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() {
(...skipping 27 matching lines...) Expand all
217 void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) { 269 void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) {
218 lock_.AssertAcquired(); 270 lock_.AssertAcquired();
219 if (!task_queue_manager_) 271 if (!task_queue_manager_)
220 return; 272 return;
221 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO && 273 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO &&
222 incoming_queue_.empty()) 274 incoming_queue_.empty())
223 task_queue_manager_->MaybePostDoWorkOnMainRunner(); 275 task_queue_manager_->MaybePostDoWorkOnMainRunner();
224 incoming_queue_.push(pending_task); 276 incoming_queue_.push(pending_task);
225 277
226 if (!pending_task.delayed_run_time.is_null()) { 278 if (!pending_task.delayed_run_time.is_null()) {
227 // Update the time of the next pending delayed task.
228 while (!delayed_task_run_times_.empty() &&
229 delayed_task_run_times_.top() <= pending_task.delayed_run_time) {
230 delayed_task_run_times_.pop();
231 }
232 // Clear the delayed run time because we've already applied the delay 279 // Clear the delayed run time because we've already applied the delay
233 // before getting here. 280 // before getting here.
234 incoming_queue_.back().delayed_run_time = base::TimeTicks(); 281 incoming_queue_.back().delayed_run_time = base::TimeTicks();
Sami 2015/03/02 16:38:32 int: could do this unconditionally now.
235 } 282 }
236 TraceQueueSize(true); 283 TraceQueueSize(true);
237 } 284 }
238 285
239 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) { 286 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) {
240 base::AutoLock lock(lock_); 287 base::AutoLock lock(lock_);
241 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO && 288 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO &&
242 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) { 289 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) {
243 PumpQueueLocked(); 290 PumpQueueLocked();
244 } 291 }
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 state->EndArray(); 601 state->EndArray();
555 state->BeginDictionary("selector"); 602 state->BeginDictionary("selector");
556 selector_->AsValueInto(state.get()); 603 selector_->AsValueInto(state.get());
557 state->EndDictionary(); 604 state->EndDictionary();
558 if (should_run) 605 if (should_run)
559 state->SetInteger("selected_queue", selected_queue); 606 state->SetInteger("selected_queue", selected_queue);
560 return state; 607 return state;
561 } 608 }
562 609
563 } // namespace content 610 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698