Blender  V3.3
BLI_task_performance_test.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0 */
2 
4 #include "testing/testing.h"
5 
6 #include "atomic_ops.h"
7 
8 #define GHASH_INTERNAL_API
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "BLI_utildefines.h"
13 
14 #include "BLI_listbase.h"
15 #include "BLI_mempool.h"
16 #include "BLI_task.h"
17 
18 #include "PIL_time.h"
19 
20 #define NUM_RUN_AVERAGED 100
21 
23 {
24  /* NOTE: this is taken from BLI_ghashutil_uinthash(), don't want to depend on external code that
25  * might change here... */
26  num += ~(num << 16);
27  num ^= (num >> 5);
28  num += (num << 3);
29  num ^= (num >> 13);
30  num += ~(num << 9);
31  num ^= (num >> 17);
32 
33  /* Make final number in [65 - 16385] range. */
34  return ((num & 255) << 6) + 1;
35 }
36 
37 /* *** Parallel iterations over double-linked list items. *** */
38 
39 static void task_listbase_light_iter_func(void *UNUSED(userdata),
40  void *item,
41  int index,
42  const TaskParallelTLS *__restrict UNUSED(tls))
43 
44 {
45  LinkData *data = (LinkData *)item;
46 
47  data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + index);
48 }
49 
50 static void task_listbase_light_membarrier_iter_func(void *userdata,
51  void *item,
52  int index,
53  const TaskParallelTLS *__restrict UNUSED(tls))
54 
55 {
56  LinkData *data = (LinkData *)item;
57  int *count = (int *)userdata;
58 
59  data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + index);
61 }
62 
63 static void task_listbase_heavy_iter_func(void *UNUSED(userdata),
64  void *item,
65  int index,
66  const TaskParallelTLS *__restrict UNUSED(tls))
67 
68 {
69  LinkData *data = (LinkData *)item;
70 
71  /* 'Random' number of iterations. */
72  const uint num = gen_pseudo_random_number((uint)index);
73 
74  for (uint i = 0; i < num; i++) {
75  data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + ((i % 2) ? -index : index));
76  }
77 }
78 
79 static void task_listbase_heavy_membarrier_iter_func(void *userdata,
80  void *item,
81  int index,
82  const TaskParallelTLS *__restrict UNUSED(tls))
83 
84 {
85  LinkData *data = (LinkData *)item;
86  int *count = (int *)userdata;
87 
88  /* 'Random' number of iterations. */
89  const uint num = gen_pseudo_random_number((uint)index);
90 
91  for (uint i = 0; i < num; i++) {
92  data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + ((i % 2) ? -index : index));
93  }
95 }
96 
97 static void task_listbase_test_do(ListBase *list,
98  const int items_num,
99  int *items_tmp_num,
100  const char *id,
102  const bool use_threads,
103  const bool check_items_tmp_num)
104 {
105  TaskParallelSettings settings;
107  settings.use_threading = use_threads;
108 
109  double averaged_timing = 0.0;
110  for (int i = 0; i < NUM_RUN_AVERAGED; i++) {
111  const double init_time = PIL_check_seconds_timer();
112  BLI_task_parallel_listbase(list, items_tmp_num, func, &settings);
113  averaged_timing += PIL_check_seconds_timer() - init_time;
114 
115  /* Those checks should ensure us all items of the listbase were processed once, and only once -
116  * as expected. */
117  if (check_items_tmp_num) {
118  EXPECT_EQ(*items_tmp_num, 0);
119  }
120  LinkData *item;
121  int j;
122  for (j = 0, item = (LinkData *)list->first; j < items_num && item != nullptr;
123  j++, item = item->next) {
124  EXPECT_EQ(POINTER_AS_INT(item->data), j);
125  item->data = POINTER_FROM_INT(0);
126  }
127  EXPECT_EQ(items_num, j);
128 
129  *items_tmp_num = items_num;
130  }
131 
132  printf("\t%s: done in %fs on average over %d runs\n",
133  id,
134  averaged_timing / NUM_RUN_AVERAGED,
136 }
137 
138 static void task_listbase_test(const char *id, const int count, const bool use_threads)
139 {
140  printf("\n========== STARTING %s ==========\n", id);
141 
142  ListBase list = {nullptr, nullptr};
143  LinkData *items_buffer = (LinkData *)MEM_calloc_arrayN(count, sizeof(*items_buffer), __func__);
144 
146 
147  int items_num = 0;
148  for (int i = 0; i < count; i++) {
149  BLI_addtail(&list, &items_buffer[i]);
150  items_num++;
151  }
152  int items_tmp_num = items_num;
153 
154  task_listbase_test_do(&list,
155  items_num,
156  &items_tmp_num,
157  "Light iter",
159  use_threads,
160  false);
161 
162  task_listbase_test_do(&list,
163  items_num,
164  &items_tmp_num,
165  "Light iter with mem barrier",
167  use_threads,
168  true);
169 
170  task_listbase_test_do(&list,
171  items_num,
172  &items_tmp_num,
173  "Heavy iter",
175  use_threads,
176  false);
177 
178  task_listbase_test_do(&list,
179  items_num,
180  &items_tmp_num,
181  "Heavy iter with mem barrier",
183  use_threads,
184  true);
185 
186  MEM_freeN(items_buffer);
188 
189  printf("========== ENDED %s ==========\n\n", id);
190 }
191 
192 TEST(task, ListBaseIterNoThread10k)
193 {
194  task_listbase_test("ListBase parallel iteration - Single thread - 10000 items", 10000, false);
195 }
196 
197 TEST(task, ListBaseIter10k)
198 {
199  task_listbase_test("ListBase parallel iteration - Threaded - 10000 items", 10000, true);
200 }
201 
202 TEST(task, ListBaseIterNoThread100k)
203 {
204  task_listbase_test("ListBase parallel iteration - Single thread - 100000 items", 100000, false);
205 }
206 
207 TEST(task, ListBaseIter100k)
208 {
209  task_listbase_test("ListBase parallel iteration - Threaded - 100000 items", 100000, true);
210 }
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
unsigned int uint
Definition: BLI_sys_types.h:67
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
void(* TaskParallelIteratorFunc)(void *__restrict userdata, void *item, int index, const TaskParallelTLS *__restrict tls)
Definition: BLI_task.h:229
void BLI_task_parallel_listbase(struct ListBase *listbase, void *userdata, TaskParallelIteratorFunc func, const TaskParallelSettings *settings)
static void task_listbase_light_membarrier_iter_func(void *userdata, void *item, int index, const TaskParallelTLS *__restrict UNUSED(tls))
#define NUM_RUN_AVERAGED
static void task_listbase_test_do(ListBase *list, const int items_num, int *items_tmp_num, const char *id, TaskParallelIteratorFunc func, const bool use_threads, const bool check_items_tmp_num)
static uint gen_pseudo_random_number(uint num)
TEST(task, ListBaseIterNoThread10k)
static void task_listbase_heavy_iter_func(void *UNUSED(userdata), void *item, int index, const TaskParallelTLS *__restrict UNUSED(tls))
static void task_listbase_heavy_membarrier_iter_func(void *userdata, void *item, int index, const TaskParallelTLS *__restrict UNUSED(tls))
static void task_listbase_test(const char *id, const int count, const bool use_threads)
static void task_listbase_light_iter_func(void *UNUSED(userdata), void *item, int index, const TaskParallelTLS *__restrict UNUSED(tls))
void BLI_threadapi_init(void)
Definition: threads.cc:125
void BLI_threadapi_exit(void)
Definition: threads.cc:130
#define POINTER_FROM_INT(i)
#define UNUSED(x)
#define POINTER_AS_INT(i)
Read Guarded memory(de)allocation.
Platform independent time functions.
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
struct blender::compositor::@179::@181 task
unsigned int uint32_t
Definition: stdint.h:80
void * data
Definition: DNA_listBase.h:26
struct LinkData * next
Definition: DNA_listBase.h:25
void * first
Definition: DNA_listBase.h:31
double PIL_check_seconds_timer(void)
Definition: time.c:64