diff options
author | Bastien Montagne <mont29> | 2019-10-30 14:23:45 +0300 |
---|---|---|
committer | Bastien Montagne <b.mont29@gmail.com> | 2019-10-30 14:23:45 +0300 |
commit | 29433da4c6e4b2da6f3fa3d1868c5039b4e6be70 (patch) | |
tree | d4419c5337f4d47557381d144d2c340f2f85e788 /source/blender/blenlib/BLI_task.h | |
parent | 3e7af19bf1debc18ce65e611711fb9d96421521e (diff) |
BLI_task: Add new generic `BLI_task_parallel_iterator()`.
This new function is part of the 'parallel for loops' functions. It
takes an iterator callback to generate items to be processed, in
addition to the usual 'process' func callback.
This allows to use common code from BLI_task for a wide range of custom
iteratiors, whithout having to re-invent the wheel of the whole tasks &
data chuncks handling.
This supports all settings features from `BLI_task_parallel_range()`,
including dynamic and static (if total number of items is knwon)
scheduling, TLS data and its finalize callback, etc.
One question here is whether we should provide usercode with a spinlock
by default, or enforce it to always handle its own sync mechanism.
I kept it, since imho it will be needed very often, and generating one
is pretty cheap even if unused...
----------
Additionaly, this commit converts (currently unused)
`BLI_task_parallel_listbase()` to use that generic code. This was done
mostly as proof of concept, but performance-wise it shows some
interesting data, roughly:
- Very light processing (that should not be threaded anyway) is several
times slower, which is expected due to more overhead in loop management
code.
- Heavier processing can be up to 10% quicker (probably thanks to the
switch from dynamic to static scheduling, which reduces a lot locking
to fill-in the per-tasks chunks of data). Similar speed-up in
non-threaded case comes as a surprise though, not sure what can
explain that.
While this conversion is not really needed, imho we should keep it
(instead of existing code for that function), it's easier to have
complex handling logic in as few places as possible, for maintaining and
for improving it.
Note: That work was initially done to allow for D5372 to be possible... Unfortunately that one proved to be not better than orig code on performances point of view.
Reviewed By: sergey
Differential Revision: https://developer.blender.org/D5371
Diffstat (limited to 'source/blender/blenlib/BLI_task.h')
-rw-r--r-- | source/blender/blenlib/BLI_task.h | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index 568d6c9a84a..7ef5e518cc8 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -198,11 +198,45 @@ void BLI_task_parallel_range(const int start, TaskParallelRangeFunc func, const TaskParallelSettings *settings); -typedef void (*TaskParallelListbaseFunc)(void *userdata, struct Link *iter, int index); +/* This data is shared between all tasks, its access needs thread lock or similar protection. */ +typedef struct TaskParallelIteratorStateShared { + /* Maximum amount of items to acquire at once. */ + int chunk_size; + /* Next item to be acquired. */ + void *next_item; + /* Index of the next item to be acquired. */ + int next_index; + /* Indicates that end of iteration has been reached. */ + bool is_finished; + /* Helper lock to protect access to this data in iterator getter callback, + * can be ignored (if the callback implements its own protection system, using atomics e.g.). + * Will be NULL when iterator is actually processed in a single thread. */ + SpinLock *spin_lock; +} TaskParallelIteratorStateShared; + +typedef void (*TaskParallelIteratorIterFunc)(void *__restrict userdata, + const TaskParallelTLS *__restrict tls, + void **r_next_item, + int *r_next_index, + bool *r_do_abort); + +typedef void (*TaskParallelIteratorFunc)(void *__restrict userdata, + void *item, + int index, + const TaskParallelTLS *__restrict tls); + +void BLI_task_parallel_iterator(void *userdata, + TaskParallelIteratorIterFunc iter_func, + void *init_item, + const int init_index, + const int tot_items, + TaskParallelIteratorFunc func, + const TaskParallelSettings *settings); + void BLI_task_parallel_listbase(struct ListBase *listbase, void *userdata, - TaskParallelListbaseFunc func, - const bool use_threading); + TaskParallelIteratorFunc func, + const TaskParallelSettings *settings); typedef struct MempoolIterData MempoolIterData; typedef void (*TaskParallelMempoolFunc)(void *userdata, MempoolIterData *iter); |