Blender V4.3
COM_WorkScheduler.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "COM_WorkScheduler.h"
6
7#include "COM_CPUDevice.h"
8
9#include "MEM_guardedalloc.h"
10
11#include "BLI_task.h"
12#include "BLI_threads.h"
13#include "BLI_vector.hh"
14
15#include "BKE_global.hh"
16
17namespace blender::compositor {
18
19enum class ThreadingModel {
23 Queue,
25 Task
26};
27
37
38static ThreadLocal(CPUDevice *) g_thread_device;
39static struct {
40 struct {
45
48 bool initialized = false;
51 } queue;
52
53 struct {
56
59
60/* -------------------------------------------------------------------- */
65{
66 CPUDevice device(0);
67 device.execute(package);
68}
69
72/* -------------------------------------------------------------------- */
76static void *threading_model_queue_execute(void *data)
77{
78 CPUDevice *device = (CPUDevice *)data;
79 WorkPackage *work;
80 BLI_thread_local_set(g_thread_device, device);
81 while ((work = (WorkPackage *)BLI_thread_queue_pop(g_work_scheduler.queue.queue))) {
82 device->execute(work);
83 }
84
85 return nullptr;
86}
87
89{
90 BLI_thread_queue_push(g_work_scheduler.queue.queue, package);
91}
92
94{
98 g_work_scheduler.queue.devices.size());
99 for (Device &device : g_work_scheduler.queue.devices) {
100 BLI_threadpool_insert(&g_work_scheduler.queue.threads, &device);
101 }
102}
103
108
110{
112 BLI_threadpool_end(&g_work_scheduler.queue.threads);
114 g_work_scheduler.queue.queue = nullptr;
115}
116
118{
119 /* Reinitialize if number of threads doesn't match. */
120 if (g_work_scheduler.queue.devices.size() != num_cpu_threads) {
121 g_work_scheduler.queue.devices.clear();
122 if (g_work_scheduler.queue.initialized) {
123 BLI_thread_local_delete(g_thread_device);
124 g_work_scheduler.queue.initialized = false;
125 }
126 }
127
128 /* Initialize CPU threads. */
129 if (!g_work_scheduler.queue.initialized) {
130 for (int index = 0; index < num_cpu_threads; index++) {
131 g_work_scheduler.queue.devices.append_as(index);
132 }
133 BLI_thread_local_create(g_thread_device);
134 g_work_scheduler.queue.initialized = true;
135 }
136}
138{
139 /* deinitialize CPU threads */
140 if (g_work_scheduler.queue.initialized) {
141 g_work_scheduler.queue.devices.clear_and_shrink();
142
143 BLI_thread_local_delete(g_thread_device);
144 g_work_scheduler.queue.initialized = false;
145 }
146}
147
150/* -------------------------------------------------------------------- */
154static void threading_model_task_execute(TaskPool *__restrict /*pool*/, void *task_data)
155{
156 WorkPackage *package = static_cast<WorkPackage *>(task_data);
157 CPUDevice device(BLI_task_parallel_thread_id(nullptr));
158 BLI_thread_local_set(g_thread_device, &device);
159 device.execute(package);
160}
161
163{
165 g_work_scheduler.task.pool, threading_model_task_execute, package, false, nullptr);
166}
167
169{
170 BLI_thread_local_create(g_thread_device);
172}
173
178
180{
182 g_work_scheduler.task.pool = nullptr;
183 BLI_thread_local_delete(g_thread_device);
184}
185
188/* -------------------------------------------------------------------- */
193{
194 switch (COM_threading_model()) {
197 break;
198 }
199
202 break;
203 }
204
207 break;
208 }
209 }
210}
211
213{
214 switch (COM_threading_model()) {
216 /* Nothing to do. */
217 break;
218
221 break;
222
225 break;
226 }
227}
228
230{
231 switch (COM_threading_model()) {
233 /* Nothing to do. */
234 break;
235
238 break;
239
242 break;
243 }
244}
245
247{
248 switch (COM_threading_model()) {
250 /* Nothing to do. */
251 break;
252
255 break;
256
259 break;
260 }
261}
262
264{
265 g_work_scheduler.num_cpu_threads = num_cpu_threads;
266 switch (COM_threading_model()) {
268 g_work_scheduler.num_cpu_threads = 1;
269 /* Nothing to do. */
270 break;
273 break;
274
276 /* Nothing to do. */
277 break;
278 }
279}
280
282{
283 switch (COM_threading_model()) {
285 /* Nothing to do. */
286 break;
287
290 break;
291
293 /* Nothing to do. */
294 break;
295 }
296}
297
299{
300 return g_work_scheduler.num_cpu_threads;
301}
302
304{
306 return 0;
307 }
308
309 CPUDevice *device = (CPUDevice *)BLI_thread_local_get(g_thread_device);
310 return device->thread_id();
311}
312
315} // namespace blender::compositor
@ TASK_PRIORITY_HIGH
Definition BLI_task.h:57
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:471
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:394
int BLI_task_parallel_thread_id(const TaskParallelTLS *tls)
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:431
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:450
void BLI_thread_queue_push(ThreadQueue *queue, void *work)
Definition threads.cc:644
void * BLI_thread_queue_pop(ThreadQueue *queue)
Definition threads.cc:655
#define BLI_thread_local_create(name)
#define BLI_thread_local_set(name, value)
ThreadQueue * BLI_thread_queue_init(void)
Definition threads.cc:618
#define BLI_thread_local_delete(name)
void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot)
Definition threads.cc:121
void BLI_thread_queue_free(ThreadQueue *queue)
Definition threads.cc:632
#define BLI_thread_local_get(name)
void BLI_threadpool_end(struct ListBase *threadbase)
Definition threads.cc:234
#define ThreadLocal(type)
void BLI_thread_queue_nowait(ThreadQueue *queue)
Definition threads.cc:770
void BLI_thread_queue_wait_finish(ThreadQueue *queue)
Definition threads.cc:781
void BLI_threadpool_insert(struct ListBase *threadbase, void *callerdata)
Definition threads.cc:184
Read Guarded memory(de)allocation.
class representing a CPU device.
void execute(WorkPackage *work) override
execute a WorkPackage
Abstract class for device implementations to be used by the Compositor. devices are queried,...
Definition COM_Device.h:20
static void threading_model_task_execute(TaskPool *__restrict, void *task_data)
static void threading_model_queue_deinitialize()
constexpr ThreadingModel COM_threading_model()
static void threading_model_single_thread_execute(WorkPackage *package)
static void threading_model_queue_stop()
ListBase threads
list of all thread for every CPUDevice in cpudevices a thread exists.
static void threading_model_queue_initialize(const int num_cpu_threads)
static void threading_model_queue_schedule(WorkPackage *package)
static void threading_model_task_stop()
static struct blender::compositor::@172 g_work_scheduler
static void threading_model_queue_start()
static void * threading_model_queue_execute(void *data)
struct blender::compositor::@172::@174 task
static void threading_model_task_start()
static void threading_model_task_finish()
static void threading_model_queue_finish()
Vector< CPUDevice > devices
list of all CPUDevices. for every hardware thread an instance of CPUDevice is created
static void threading_model_task_schedule(WorkPackage *package)
ThreadQueue * queue
all scheduled work for the cpu
contains data about work that can be scheduled
static void start()
Start the execution this methods will start the WorkScheduler. Inside this method all threads are ini...
static void schedule(WorkPackage *package)
schedule a chunk of a group to be calculated. An execution group schedules a chunk in the WorkSchedul...
static void deinitialize()
deinitialize the WorkScheduler free all allocated resources
static void finish()
wait for all work to be completed.
static void stop()
stop the execution All created thread by the start method are destroyed.
static void initialize(int num_cpu_threads)
initialize the WorkScheduler