Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2017-11-23 23:12:00 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2017-11-23 23:12:00 +0300
commitb84e6dfee4a82b4142651710cbe842f8d021a861 (patch)
tree78250ce98c1b1dbe68ba71bb77de73ef7d9b2437
parentff9eab7926da46d62cede2d3d061fcfe2531f622 (diff)
Add ability to use more than one mempool iterator simultaneously.
This will allow threaded tasks to 'consume' all mempool items in parallel tasks, each one working on a whole chunk at once (to reduce concurrency managing overhead).
-rw-r--r--source/blender/blenlib/BLI_mempool.h5
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c74
2 files changed, 75 insertions, 4 deletions
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index 0c754f551e0..b68ca6b1f2b 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -71,6 +71,8 @@ typedef struct BLI_mempool_iter {
BLI_mempool *pool;
struct BLI_mempool_chunk *curchunk;
unsigned int curindex;
+
+ struct BLI_mempool_chunk **curchunk_threaded_shared;
} BLI_mempool_iter;
/* flag */
@@ -87,6 +89,9 @@ enum {
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL();
void *BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BLI_mempool_iter *BLI_mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BLI_mempool_iter_threadsafe_free(BLI_mempool_iter *iter_arr) ATTR_NONNULL();
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index b02811616dd..c90f9e300b7 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -41,6 +41,8 @@
#include <string.h>
#include <stdlib.h>
+#include "atomic_ops.h"
+
#include "BLI_utildefines.h"
#include "BLI_mempool.h" /* own include */
@@ -553,7 +555,7 @@ void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
}
/**
- * Create a new mempool iterator, \a BLI_MEMPOOL_ALLOW_ITER flag must be set.
+ * Initialize a new mempool iterator, \a BLI_MEMPOOL_ALLOW_ITER flag must be set.
*/
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter)
{
@@ -562,6 +564,47 @@ void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter)
iter->pool = pool;
iter->curchunk = pool->chunks;
iter->curindex = 0;
+
+ iter->curchunk_threaded_shared = NULL;
+}
+
+/**
+ * Initialize an array of mempool iterators, \a BLI_MEMPOOL_ALLOW_ITER flag must be set.
+ *
+ * This is used in threaded code, to generate as much iterators as needed (each task should have its own),
+ * such that each iterator goes over its own single chunk, and only getting the next chunk to iterate over has to be
+ * protected against concurrency (which can be done in a lockless way).
+ *
+ * To be used when creating a task for each single item in the pool is totally overkill.
+ *
+ * See BLI_task_parallel_mempool implementation for detailed usage example.
+ */
+BLI_mempool_iter *BLI_mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter)
+{
+ BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
+
+ BLI_mempool_iter *iter_arr = MEM_mallocN(sizeof(*iter_arr) * num_iter, __func__);
+ BLI_mempool_chunk **curchunk_threaded_shared = MEM_mallocN(sizeof(void *), __func__);
+
+ BLI_mempool_iternew(pool, iter_arr);
+
+ *curchunk_threaded_shared = iter_arr->curchunk;
+ iter_arr->curchunk_threaded_shared = curchunk_threaded_shared;
+
+ for (size_t i = 1; i < num_iter; i++) {
+ iter_arr[i] = iter_arr[0];
+ *curchunk_threaded_shared = iter_arr[i].curchunk = (*curchunk_threaded_shared) ? (*curchunk_threaded_shared)->next : NULL;
+ }
+
+ return iter_arr;
+}
+
+void BLI_mempool_iter_threadsafe_free(BLI_mempool_iter *iter_arr)
+{
+ BLI_assert(iter_arr->curchunk_threaded_shared != NULL);
+
+ MEM_freeN(iter_arr->curchunk_threaded_shared);
+ MEM_freeN(iter_arr);
}
#if 0
@@ -571,15 +614,28 @@ static void *bli_mempool_iternext(BLI_mempool_iter *iter)
{
void *ret = NULL;
- if (!iter->curchunk || !iter->pool->totused) return NULL;
+ if (iter->curchunk == NULL || !iter->pool->totused) {
+ return ret;
+ }
ret = ((char *)CHUNK_DATA(iter->curchunk)) + (iter->pool->esize * iter->curindex);
iter->curindex++;
if (iter->curindex == iter->pool->pchunk) {
- iter->curchunk = iter->curchunk->next;
iter->curindex = 0;
+ if (iter->curchunk_threaded_shared) {
+ while (1) {
+ iter->curchunk = *iter->curchunk_threaded_shared;
+ if (iter->curchunk == NULL) {
+ break;
+ }
+ if (atomic_cas_ptr((void **)iter->curchunk_threaded_shared, iter->curchunk, iter->curchunk->next) == iter->curchunk) {
+ break;
+ }
+ }
+ }
+ iter->curchunk = iter->curchunk->next;
}
return ret;
@@ -620,8 +676,18 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
}
else {
iter->curindex = 0;
+ if (iter->curchunk_threaded_shared) {
+ for (iter->curchunk = *iter->curchunk_threaded_shared;
+ (iter->curchunk != NULL) &&
+ (atomic_cas_ptr((void **)iter->curchunk_threaded_shared, iter->curchunk, iter->curchunk->next) != iter->curchunk);
+ iter->curchunk = *iter->curchunk_threaded_shared);
+
+ if (UNLIKELY(iter->curchunk == NULL)) {
+ return (ret->freeword == FREEWORD) ? NULL : ret;
+ }
+ }
iter->curchunk = iter->curchunk->next;
- if (iter->curchunk == NULL) {
+ if (UNLIKELY(iter->curchunk == NULL)) {
return (ret->freeword == FREEWORD) ? NULL : ret;
}
curnode = CHUNK_DATA(iter->curchunk);