OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef CC_RESOURCES_TASK_GRAPH_RUNNER_H_ | |
6 #define CC_RESOURCES_TASK_GRAPH_RUNNER_H_ | |
7 | |
8 #include <queue> | |
9 #include <string> | |
10 #include <vector> | |
11 | |
12 #include "base/containers/scoped_ptr_hash_map.h" | |
13 #include "base/memory/ref_counted.h" | |
14 #include "base/memory/scoped_ptr.h" | |
15 #include "base/synchronization/condition_variable.h" | |
16 #include "base/threading/simple_thread.h" | |
17 #include "cc/base/cc_export.h" | |
18 #include "cc/base/scoped_ptr_deque.h" | |
19 | |
20 namespace cc { | |
21 namespace internal { | |
22 | |
23 class CC_EXPORT Task : public base::RefCountedThreadSafe<Task> { | |
24 public: | |
25 typedef std::vector<scoped_refptr<Task> > Vector; | |
26 | |
27 virtual void RunOnWorkerThread(unsigned thread_index) = 0; | |
28 | |
29 void DidSchedule(); | |
30 void WillRun(); | |
31 void DidRun(); | |
32 | |
33 bool HasFinishedRunning() const; | |
34 | |
35 protected: | |
36 friend class base::RefCountedThreadSafe<Task>; | |
37 | |
38 Task(); | |
39 virtual ~Task(); | |
40 | |
41 bool did_schedule_; | |
42 bool did_run_; | |
43 }; | |
44 | |
45 } // namespace internal | |
46 } // namespace cc | |
47 | |
48 #if defined(COMPILER_GCC) | |
49 namespace BASE_HASH_NAMESPACE { | |
50 template <> struct hash<cc::internal::Task*> { | |
51 size_t operator()(cc::internal::Task* ptr) const { | |
52 return hash<size_t>()(reinterpret_cast<size_t>(ptr)); | |
53 } | |
54 }; | |
55 } // namespace BASE_HASH_NAMESPACE | |
56 #endif // COMPILER | |
57 | |
58 namespace cc { | |
59 namespace internal { | |
60 | |
61 // Dependencies are represented by edges in a task graph. A graph node | |
62 // store edges as a vector of dependents. Each graph node is assigned | |
63 // a priority and a run count that matches the number of dependencies. | |
64 class CC_EXPORT GraphNode { | |
65 public: | |
66 typedef std::vector<GraphNode*> Vector; | |
67 typedef base::ScopedPtrHashMap<Task*, GraphNode> Map; | |
68 | |
69 GraphNode(Task* task, unsigned priority); | |
70 ~GraphNode(); | |
71 | |
72 Task* task() { return task_; } | |
73 | |
74 void add_dependent(GraphNode* dependent) { | |
75 DCHECK(dependent); | |
76 dependents_.push_back(dependent); | |
77 } | |
78 const Vector& dependents() const { return dependents_; } | |
79 | |
80 unsigned priority() const { return priority_; } | |
81 | |
82 unsigned num_dependencies() const { return num_dependencies_; } | |
83 void add_dependency() { ++num_dependencies_; } | |
84 void remove_dependency() { | |
85 DCHECK(num_dependencies_); | |
86 --num_dependencies_; | |
87 } | |
88 | |
89 private: | |
90 Task* task_; | |
91 Vector dependents_; | |
92 unsigned priority_; | |
93 unsigned num_dependencies_; | |
94 | |
95 DISALLOW_COPY_AND_ASSIGN(GraphNode); | |
96 }; | |
97 | |
98 class TaskGraphRunner; | |
99 | |
100 // Opaque identifier that defines a namespace of tasks. | |
101 class CC_EXPORT NamespaceToken { | |
102 public: | |
103 NamespaceToken() : id_(0) {} | |
104 ~NamespaceToken() {} | |
105 | |
106 bool IsValid() const { | |
107 return id_ != 0; | |
108 } | |
109 | |
110 private: | |
111 friend class TaskGraphRunner; | |
112 | |
113 explicit NamespaceToken(int id) : id_(id) {} | |
114 | |
115 int id_; | |
116 }; | |
117 | |
118 // A worker thread pool that runs tasks provided by task graph. Destructor | |
119 // might block and should not be used on a thread that needs to be responsive. | |
120 class CC_EXPORT TaskGraphRunner : public base::DelegateSimpleThread::Delegate { | |
121 public: | |
122 typedef GraphNode::Map TaskGraph; | |
123 | |
124 TaskGraphRunner(size_t num_threads, const std::string& thread_name_prefix); | |
125 virtual ~TaskGraphRunner(); | |
126 | |
127 // Returns a unique token that can be used to pass a task graph to | |
128 // SetTaskGraph(). Valid tokens are always nonzero. | |
129 NamespaceToken GetNamespaceToken(); | |
130 | |
131 // Schedule running of tasks in |graph|. Tasks previously scheduled but | |
132 // no longer needed will be canceled unless already running. Canceled | |
133 // tasks are moved to |completed_tasks| without being run. The result | |
134 // is that once scheduled, a task is guaranteed to end up in the | |
135 // |completed_tasks| queue even if it later get canceled by another | |
136 // call to SetTaskGraph(). | |
137 void SetTaskGraph(NamespaceToken token, TaskGraph* graph); | |
138 | |
139 // Wait for all scheduled tasks to finish running. | |
140 void WaitForTasksToFinishRunning(NamespaceToken token); | |
141 | |
142 // Collect all completed tasks in |completed_tasks|. | |
143 void CollectCompletedTasks( | |
144 NamespaceToken token, Task::Vector* completed_tasks); | |
145 | |
146 private: | |
147 struct TaskNamespace { | |
148 typedef std::vector<TaskNamespace*> Vector; | |
149 | |
150 TaskNamespace(); | |
151 ~TaskNamespace(); | |
152 | |
153 // This set contains all pending tasks. | |
154 TaskGraph pending_tasks; | |
155 // This set contains all currently running tasks. | |
156 TaskGraph running_tasks; | |
157 // Completed tasks not yet collected by origin thread. | |
158 Task::Vector completed_tasks; | |
159 // Ordered set of tasks that are ready to run. | |
160 internal::GraphNode::Vector ready_to_run_tasks; | |
161 }; | |
162 | |
163 typedef base::ScopedPtrHashMap<int, TaskNamespace> TaskNamespaceMap; | |
164 | |
165 static bool CompareTaskPriority(const internal::GraphNode* a, | |
166 const internal::GraphNode* b) { | |
167 // In this system, numerically lower priority is run first. | |
168 if (a->priority() != b->priority()) | |
169 return a->priority() > b->priority(); | |
170 | |
171 // Run task with most dependents first when priority is the same. | |
172 return a->dependents().size() < b->dependents().size(); | |
173 } | |
174 | |
175 static bool CompareTaskNamespacePriority(const TaskNamespace* a, | |
176 const TaskNamespace* b) { | |
177 DCHECK(!a->ready_to_run_tasks.empty()); | |
178 DCHECK(!b->ready_to_run_tasks.empty()); | |
179 | |
180 // Compare based on task priority of the ready_to_run_tasks heap | |
181 // .front() will hold the max element of the heap, | |
182 // except after pop_heap, when max element is moved to .back(). | |
183 return CompareTaskPriority(a->ready_to_run_tasks.front(), | |
184 b->ready_to_run_tasks.front()); | |
185 } | |
186 | |
187 static bool HasFinishedRunningTasksInNamespace( | |
188 TaskNamespace* task_namespace) { | |
189 return task_namespace->pending_tasks.empty() && | |
190 task_namespace->running_tasks.empty(); | |
191 } | |
192 | |
193 // Overridden from base::DelegateSimpleThread: | |
194 virtual void Run() OVERRIDE; | |
195 | |
196 // This lock protects all members of this class. Do not read or modify | |
197 // anything without holding this lock. Do not block while holding this | |
198 // lock. | |
199 mutable base::Lock lock_; | |
200 | |
201 // Condition variable that is waited on by worker threads until new | |
202 // tasks are ready to run or shutdown starts. | |
203 base::ConditionVariable has_ready_to_run_tasks_cv_; | |
204 | |
205 // Condition variable that is waited on by origin threads until a | |
206 // namespace has finished running all associated tasks. | |
207 base::ConditionVariable has_namespaces_with_finished_running_tasks_cv_; | |
208 | |
209 // Provides a unique id to each NamespaceToken. | |
210 int next_namespace_id_; | |
211 | |
212 // This set contains all namespaces with pending, running or completed | |
213 // tasks not yet collected. | |
214 TaskNamespaceMap namespaces_; | |
215 | |
216 // Ordered set of task namespaces that have ready to run tasks. | |
217 TaskNamespace::Vector ready_to_run_namespaces_; | |
218 | |
219 // Provides each running thread loop with a unique index. First thread | |
220 // loop index is 0. | |
221 unsigned next_thread_index_; | |
222 | |
223 // Set during shutdown. Tells workers to exit when no more tasks | |
224 // are pending. | |
225 bool shutdown_; | |
226 | |
227 ScopedPtrDeque<base::DelegateSimpleThread> workers_; | |
228 | |
229 DISALLOW_COPY_AND_ASSIGN(TaskGraphRunner); | |
230 }; | |
231 | |
232 } // namespace internal | |
233 } // namespace cc | |
234 | |
235 #endif // CC_RESOURCES_TASK_GRAPH_RUNNER_H_ | |
OLD | NEW |