Motr  M0
op.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2015-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 
30 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_UT
31 #include "lib/trace.h"
32 
33 #include "be/op.h"
34 
35 #include "lib/memory.h" /* M0_ALLOC_PTR */
36 #include "lib/semaphore.h" /* m0_semaphore */
37 #include "ut/ut.h" /* M0_UT_ASSERT */
38 #include "ut/threads.h" /* M0_UT_THREADS_DEFINE */
39 
41 {
42  struct m0_be_op op = {};
43 
44  m0_be_op_init(&op);
48  m0_be_op_done(&op);
50  m0_be_op_fini(&op);
51 }
52 
62 };
63 
67 };
68 
73 };
74 
82  struct m0_be_op *bom_op;
83 };
84 
85 static void be_ut_op_mt_thread_func(void *param)
86 {
87  struct be_ut_op_mt_thread_cfg *cfg = param;
88  bool success;
89  bool done;
90  int i;
91 
92  M0_ENTRY("enter %d, wait4 %p", cfg->bom_cmd, cfg->bom_wait_before);
93  if (cfg->bom_wait_before != NULL)
95  M0_LOG(M0_DEBUG, "waited %d", cfg->bom_cmd);
96  switch (cfg->bom_cmd) {
97  case BE_UT_OP_MT_INIT:
98  m0_be_op_init(cfg->bom_op);
99  break;
100  case BE_UT_OP_MT_ACTIVE:
101  done = m0_be_op_is_done(cfg->bom_op);
102  M0_UT_ASSERT(!done);
103  m0_be_op_active(cfg->bom_op);
104  break;
105  case BE_UT_OP_MT_DONE:
106  done = m0_be_op_is_done(cfg->bom_op);
107  M0_UT_ASSERT(!done);
108  m0_be_op_done(cfg->bom_op);
109  break;
110  case BE_UT_OP_MT_FINI:
111  done = m0_be_op_is_done(cfg->bom_op);
113  m0_be_op_fini(cfg->bom_op);
114  break;
115  case BE_UT_OP_MT_WAIT1:
116  case BE_UT_OP_MT_WAIT2:
117  case BE_UT_OP_MT_WAIT3:
118  m0_be_op_wait(cfg->bom_op);
119  done = m0_be_op_is_done(cfg->bom_op);
121  break;
122  default:
123  M0_IMPOSSIBLE("invalid command %d", cfg->bom_cmd);
124  }
125  if (cfg->bom_try_down != NULL) {
126  success = m0_semaphore_trydown(cfg->bom_try_down);
127  M0_UT_ASSERT(success);
128  }
129  if (cfg->bom_wait_after != NULL)
131  for (i = 0; i < ARRAY_SIZE(cfg->bom_signal_to); ++i) {
132  if (cfg->bom_signal_to[i] != NULL) {
133  M0_LOG(M0_DEBUG, "signal to %p", cfg->bom_signal_to[i]);
135  }
136  }
137  M0_LEAVE();
138 }
139 
141 
154 void m0_be_ut_op_mt(void)
155 {
156  struct be_ut_op_mt_thread_cfg *cfg;
157  struct be_ut_op_mt_thread_cfg *src;
158  struct be_ut_op_mt_thread_cfg *dst;
159  struct be_ut_op_mt_dep *dep;
160  struct m0_semaphore trigger = {};
161  struct m0_semaphore completion = {};
162 #define DEP(src, type, dst) { .bod_src = src, .bod_type = type, .bod_dst = dst }
163  struct be_ut_op_mt_dep deps[] = {
173  };
174 #undef DEP
175  struct m0_be_op op = {};
176  int i;
177  int rc;
178 
180  M0_UT_ASSERT(cfg != NULL);
181  for (i = 0; i < BE_UT_OP_MT_CMD_NR; ++i) {
182  rc = m0_semaphore_init(&cfg[i].bom_barrier, 0);
183  M0_UT_ASSERT(rc == 0);
184  cfg[i].bom_cmd = i;
185  cfg[i].bom_op = &op;
186  }
187  rc = m0_semaphore_init(&trigger, 0);
188  M0_UT_ASSERT(rc == 0);
189  rc = m0_semaphore_init(&completion, 0);
190  M0_UT_ASSERT(rc == 0);
191  cfg[BE_UT_OP_MT_INIT].bom_wait_before = &trigger;
192  cfg[BE_UT_OP_MT_FINI].bom_signal_to[0] = &completion;
193  for (i = 0; i < ARRAY_SIZE(deps); ++i) {
194  dep = &deps[i];
195  src = &cfg[dep->bod_src];
196  dst = &cfg[dep->bod_dst];
197  if (src->bom_signal_to[0] == NULL) {
198  src->bom_signal_to[0] = &dst->bom_barrier;
199  } else if (src->bom_signal_to[1] == NULL) {
200  src->bom_signal_to[1] = &dst->bom_barrier;
201  } else {
202  M0_IMPOSSIBLE("invalid deps");
203  }
204  switch (dep->bod_type) {
206  M0_UT_ASSERT(dst->bom_wait_before == NULL);
207  dst->bom_wait_before = &dst->bom_barrier;
208  break;
210  M0_UT_ASSERT(dst->bom_wait_after == NULL);
211  dst->bom_wait_after = &dst->bom_barrier;
212  break;
213  default:
214  M0_IMPOSSIBLE("invalid dep type");
215  }
216  }
217  M0_UT_THREADS_START(be_ut_op_mt, BE_UT_OP_MT_CMD_NR, cfg);
218  m0_semaphore_up(&trigger);
219  m0_semaphore_down(&completion);
220  M0_UT_THREADS_STOP(be_ut_op_mt);
221 
222  m0_semaphore_fini(&completion);
223  m0_semaphore_fini(&trigger);
224  for (i = 0; i < BE_UT_OP_MT_CMD_NR; ++i)
225  m0_semaphore_fini(&cfg[i].bom_barrier);
226  m0_free(cfg);
227 }
228 
229 enum {
231 };
232 
233 /*
234  * op
235  * \__ set[0]
236  * \__ set[1]
237  * ...
238  * \__ set[BE_UT_OP_SET_USECASE_NR - 1]
239  */
241 {
242  struct m0_be_op op = {};
243  struct m0_be_op *set;
244  int i;
245 
247  M0_UT_ASSERT(set != NULL);
248  m0_be_op_init(&op);
250  for (i = 0; i < BE_UT_OP_SET_USECASE_NR; ++i) {
251  m0_be_op_init(&set[i]);
253  m0_be_op_set_add(&op, &set[i]);
255  }
256  for (i = 0; i < BE_UT_OP_SET_USECASE_NR / 2; ++i) {
257  m0_be_op_active(&set[i]);
259  }
260  for (i = 1; i < BE_UT_OP_SET_USECASE_NR / 2; ++i) {
261  m0_be_op_done(&set[i]);
263  }
264  for (i = BE_UT_OP_SET_USECASE_NR / 2;
265  i < BE_UT_OP_SET_USECASE_NR; ++i) {
266  m0_be_op_active(&set[i]);
268  m0_be_op_done(&set[i]);
270  }
271  m0_be_op_done(&set[0]);
273 
274  for (i = 0; i < BE_UT_OP_SET_USECASE_NR; ++i)
275  m0_be_op_fini(&set[i]);
276  m0_be_op_fini(&op);
277 
278  m0_free(set);
279 }
280 
281 enum {
286 };
287 
297 };
298 
299 static void be_ut_op_set_tree_swap(unsigned *a, unsigned *b)
300 {
301  unsigned t;
302 
303  t = *a;
304  *a = *b;
305  *b = t;
306 }
307 
308 static void be_ut_op_set_tree_random_shuffle(unsigned *arr,
309  unsigned nr,
310  bool keep_half_dist_order,
311  uint64_t *seed)
312 {
313  unsigned half_dist = nr / 2 + 1;
314  unsigned a;
315  unsigned b;
316  int i;
317  int j;
318 
319  for (i = 0; i < BE_UT_OP_SET_TREE_SHUFFLE_ITER; ++i) {
320  a = m0_rnd64(seed) % nr;
321  b = m0_rnd64(seed) % nr;
322  be_ut_op_set_tree_swap(&arr[a], &arr[b]);
323  }
324  if (keep_half_dist_order) {
325  for (i = 0; i < nr; ++i) {
326  for (j = i + 1; j < nr; ++j) {
327  if (arr[i] > arr[j] &&
328  (arr[i] + half_dist == arr[j] ||
329  arr[j] + half_dist == arr[i])) {
331  &arr[j]);
332  }
333  }
334  }
335  }
336 }
337 
338 static void be_ut_op_set_tree_do(struct m0_be_op *op,
339  struct m0_be_op *child,
340  enum be_ut_op_set_tree_cmd cmd)
341 {
342  bool done;
343 
344  switch (cmd) {
346  m0_be_op_init(op);
347  break;
349  m0_be_op_set_add(op, child);
350  break;
352  m0_be_op_fini(op);
353  break;
356  break;
358  m0_be_op_done(op);
359  break;
363  break;
366  M0_UT_ASSERT(!done);
367  break;
368  default:
369  M0_IMPOSSIBLE("impossible branch");
370  }
371 }
372 
374  enum be_ut_op_set_tree_cmd cmd,
375  int level,
376  int index,
377  uint64_t *seed)
378 {
379  enum be_ut_op_set_tree_cmd cmd2;
380  const int level_size = BE_UT_OP_SET_TREE_LEVEL_SIZE;
381  const int level_nr = BE_UT_OP_SET_TREE_LEVEL_NR;
382  unsigned order[BE_UT_OP_SET_TREE_LEVEL_SIZE * 2] = {};
383  unsigned i;
384  unsigned j;
385 
386  for (i = 0; i < ARRAY_SIZE(order); ++i)
387  order[i] = i;
388  if (cmd == BE_UT_OP_SET_TREE_STATES) {
391  }
392  if (cmd == BE_UT_OP_SET_TREE_STATES && level + 2 == level_nr) {
393  be_ut_op_set_tree_random_shuffle(order, level_size * 2 - 1,
394  true, seed);
395  for (i = 0; i < ARRAY_SIZE(order); ++i) {
396  j = index * level_size + order[i] % level_size + 1;
397  cmd2 = order[i] / level_size == 0 ?
400  be_ut_op_set_tree_do(&op[j], NULL, cmd2);
401  cmd2 = i < ARRAY_SIZE(order) - 1 ?
404  be_ut_op_set_tree_do(&op[index], NULL, cmd2);
405  }
406  } else {
407  if (level < level_nr - 1) {
408  /* only first half of order[] is used in this branch */
409  be_ut_op_set_tree_random_shuffle(order, level_size,
410  false, seed);
411  /*
412  * Order is interpreted as order of op processing
413  * on the current level.
414  */
415  for (i = 0; i < level_size; ++i) {
416  j = index * level_size + order[i] + 1;
417  if (cmd == BE_UT_OP_SET_TREE_SET_ADD) {
419  &op[j], cmd);
420  }
422  j, seed);
423  }
424  }
425  if (!M0_IN(cmd, (BE_UT_OP_SET_TREE_SET_ADD,
428  }
429  if (cmd == BE_UT_OP_SET_TREE_STATES) {
432  }
433 }
434 
435 /*
436  * op[0]
437  * \__ op[1]
438  * | \___ op[LEVEL_SIZE + 1]
439  * | | \___ op[LEVEL_SIZE + LEVEL_SIZE * LEVEL_SIZE + 1]
440  * | ...........
441  * | \___ op[LEVEL_SIZE + 2]
442  * | ...
443  * | \___ op[LEVEL_SIZE + LEVEL_SIZE]
444  * \__ op[2]
445  * | \___ op[LEVEL_SIZE + LEVEL_SIZE + 1]
446  * | \___ op[LEVEL_SIZE + LEVEL_SIZE + 2]
447  * | ...
448  * | \___ op[LEVEL_SIZE + LEVEL_SIZE + LEVEL_SIZE]
449  * \__ op[3]
450  * | \___ op[LEVEL_SIZE + 2 * LEVEL_SIZE + 1]
451  * | \___ op[LEVEL_SIZE + 2 * LEVEL_SIZE + 2]
452  * | ...
453  * | \___ op[LEVEL_SIZE + 2 * LEVEL_SIZE + LEVEL_SIZE]
454  * ...
455  * \__ op[LEVEL_SIZE]
456  * \___ op[LEVEL_SIZE + (LEVEL_SIZE - 1) * LEVEL_SIZE + 1]
457  * \___ op[LEVEL_SIZE + (LEVEL_SIZE - 1) * LEVEL_SIZE + 2]
458  * ...
459  * \___ op[LEVEL_SIZE + (LEVEL_SIZE - 1) * LEVEL_SIZE + LEVEL_SIZE]
460  */
462 {
463  struct m0_be_op *op;
464  unsigned op_nr;
465  unsigned op_per_lvl;
466  int level;
467  uint64_t seed = BE_UT_OP_SET_TREE_RNG_SEED;
468 
469  op_nr = 0;
470  op_per_lvl = 1;
471  for (level = 0; level < BE_UT_OP_SET_TREE_LEVEL_NR; ++level) {
472  op_nr += op_per_lvl;
473  op_per_lvl *= BE_UT_OP_SET_TREE_LEVEL_SIZE;
474  }
475  M0_ALLOC_ARR(op, op_nr);
476  M0_UT_ASSERT(op != NULL);
477 
482 
483  m0_free(op);
484 }
485 
486 #undef M0_TRACE_SUBSYSTEM
487 
490 /*
491  * Local variables:
492  * c-indentation-style: "K&R"
493  * c-basic-offset: 8
494  * tab-width: 8
495  * fill-column: 80
496  * scroll-step: 1
497  * End:
498  */
499 /*
500  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
501  */
static size_t nr
Definition: dump.c:1505
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
static void be_ut_op_set_tree_do(struct m0_be_op *op, struct m0_be_op *child, enum be_ut_op_set_tree_cmd cmd)
Definition: op.c:338
struct m0_semaphore bom_barrier
Definition: op.c:76
be_ut_op_mt_cmd
Definition: op.c:53
#define NULL
Definition: misc.h:38
static struct m0_bufvec dst
Definition: xform.c:61
M0_INTERNAL bool m0_semaphore_trydown(struct m0_semaphore *semaphore)
Definition: semaphore.c:60
M0_INTERNAL void m0_be_op_active(struct m0_be_op *op)
Definition: op.c:220
be_ut_op_set_tree_cmd
Definition: op.c:288
static void be_ut_op_set_tree_random_shuffle(unsigned *arr, unsigned nr, bool keep_half_dist_order, uint64_t *seed)
Definition: op.c:308
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
enum m0_trace_level level
Definition: trace.c:111
M0_INTERNAL void m0_be_op_done(struct m0_be_op *op)
Definition: op.c:227
enum be_ut_op_mt_cmd bod_src
Definition: op.c:70
M0_INTERNAL void m0_be_op_wait(struct m0_be_op *op)
Definition: op.c:286
op
Definition: libdemo.c:64
void m0_be_ut_op_set_tree(void)
Definition: op.c:461
M0_INTERNAL void m0_be_op_fini(struct m0_be_op *op)
Definition: op.c:107
#define M0_ENTRY(...)
Definition: trace.h:170
int i
Definition: dir.c:1033
enum be_ut_op_mt_cmd bod_dst
Definition: op.c:72
enum be_ut_op_mt_dep_type bod_type
Definition: op.c:71
static struct m0_thread t[8]
Definition: service_ut.c:1230
void m0_be_ut_op_usecase(void)
Definition: op.c:40
void m0_be_ut_op_mt(void)
Definition: op.c:154
void m0_be_ut_op_set_usecase(void)
Definition: op.c:240
M0_UT_THREADS_DEFINE(be_ut_op_mt, &be_ut_op_mt_thread_func)
M0_INTERNAL int m0_semaphore_init(struct m0_semaphore *semaphore, unsigned value)
Definition: semaphore.c:38
#define DEP(src, type, dst)
M0_INTERNAL void m0_be_op_init(struct m0_be_op *op)
Definition: op.c:94
enum be_ut_op_mt_cmd bom_cmd
Definition: op.c:81
struct m0_be_op * bom_op
Definition: op.c:82
M0_INTERNAL uint64_t m0_rnd64(uint64_t *seed)
Definition: misc.c:100
static void be_ut_op_mt_thread_func(void *param)
Definition: op.c:85
M0_INTERNAL void m0_semaphore_fini(struct m0_semaphore *semaphore)
Definition: semaphore.c:45
M0_INTERNAL void m0_be_op_set_add(struct m0_be_op *parent, struct m0_be_op *child)
Definition: op.c:297
#define M0_UT_THREADS_STOP(name)
Definition: threads.h:55
static void be_ut_op_set_tree_swap(unsigned *a, unsigned *b)
Definition: op.c:299
static unsigned done
Definition: storage.c:91
M0_INTERNAL void m0_semaphore_down(struct m0_semaphore *semaphore)
Definition: semaphore.c:49
struct m0_semaphore * bom_wait_before
Definition: op.c:78
#define M0_UT_THREADS_START(name, thread_nr, param_array)
Definition: threads.h:51
M0_INTERNAL void m0_semaphore_up(struct m0_semaphore *semaphore)
Definition: semaphore.c:65
Definition: op.h:74
struct m0_semaphore * bom_try_down
Definition: op.c:80
void m0_free(void *data)
Definition: memory.c:146
static void be_ut_op_set_tree_recursive(struct m0_be_op *op, enum be_ut_op_set_tree_cmd cmd, int level, int index, uint64_t *seed)
Definition: op.c:373
struct m0_semaphore * bom_wait_after
Definition: op.c:79
struct m0_semaphore * bom_signal_to[2]
Definition: op.c:77
struct m0_pdclust_src_addr src
Definition: fd.c:108
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
#define M0_UT_ASSERT(a)
Definition: ut.h:46
M0_INTERNAL bool m0_be_op_is_done(struct m0_be_op *op)
Definition: op.c:234
be_ut_op_mt_dep_type
Definition: op.c:64
#define M0_IMPOSSIBLE(fmt,...)