Motr  M0
ub.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2020 Seagate Technology LLC and/or its Affiliates
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * For any questions about this software or licensing,
17  * please email opensource@seagate.com or cortx-questions@seagate.com.
18  *
19  */
20 
21 
22 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_UT
23 #include "lib/trace.h"
24 
25 #include "fop/fom_long_lock.h"
26 #include "fop/fom_generic.h" /* m0_generic_conf, M0_FOPH_NR */
27 #include "reqh/reqh.h"
28 #include "reqh/reqh_service.h"
29 #include "rpc/rpc_opcodes.h" /* M0_UB_FOM_OPCODE */
30 #include "lib/memory.h" /* m0_free */
31 #include "lib/ub.h" /* M0_UB_ASSERT */
32 #include "ut/ut.h"
33 
34 static struct m0_reqh g_reqh;
35 static struct m0_reqh_service *g_svc;
36 /* 8 MB --- approximately twice the size of L3 cache on Motr team VMs. */
37 static char g_mem[8 * (1 << 20)];
38 static struct m0_mutex *g_mutexes;
39 static size_t g_mutexes_nr;
40 static struct m0_long_lock g_long_lock;
41 
43 enum {
45  ST_NR_FOMS = 20000,
46 
49 
52 
55 };
56 
58 enum scenario {
61 
64 
67 
70 
73 
76 
79 
81 };
82 
84 struct ub_fom {
86  struct m0_fom uf_gen;
87 
89  size_t uf_seqn;
90 
93 
96 };
97 
98 /* ----------------------------------------------------------------
99  * Ticks
100  * ---------------------------------------------------------------- */
101 
102 static void cpu_utilize(const struct ub_fom *mach);
103 
104 static void cpu_utilize_with_lock(struct ub_fom *mach, size_t lock_idx)
105 {
106  M0_PRE(lock_idx < g_mutexes_nr);
107 
108  m0_mutex_lock(&g_mutexes[lock_idx]);
109  cpu_utilize(mach);
110  m0_mutex_unlock(&g_mutexes[lock_idx]);
111 }
112 
114 static int mem_tick(struct m0_fom *fom)
115 {
116  cpu_utilize(container_of(fom, struct ub_fom, uf_gen));
117  /*
118  * Let request handler delete this fom.
119  *
120  * See `m0_fom_phase(fom) == M0_FOM_PHASE_FINISH' comment in
121  * fop/fom.h.
122  */
124  return M0_FSO_WAIT;
125 }
126 
128 static int mutex_tick(struct m0_fom *fom)
129 {
130  cpu_utilize_with_lock(container_of(fom, struct ub_fom, uf_gen), 0);
131 
133  return M0_FSO_WAIT;
134 }
135 
145 static int mutex_per_cpu_tick(struct m0_fom *fom)
146 {
147  struct ub_fom *m = container_of(fom, struct ub_fom, uf_gen);
148 
149  cpu_utilize_with_lock(m, m->uf_seqn % g_mutexes_nr);
150 
152  return M0_FSO_WAIT;
153 }
154 
156 static int long_lock_tick(struct m0_fom *fom)
157 {
158  enum {
159  REQ_LOCK = M0_FOM_PHASE_INIT,
160  GOT_LOCK = M0_FOPH_NR + 1
161  };
162  struct ub_fom *m;
163  int phase;
164  bool is_writer;
165  bool (*lock)(struct m0_long_lock *lock,
166  struct m0_long_lock_link *link, int next_phase);
167  void (*unlock)(struct m0_long_lock *lock,
168  struct m0_long_lock_link *link);
169 
170  m = container_of(fom, struct ub_fom, uf_gen);
171  is_writer = (m->uf_seqn % ST_WRITER_PERIOD == 0);
172  lock = is_writer ? m0_long_write_lock : m0_long_read_lock;
174 
175  phase = m0_fom_phase(fom);
176  if (phase == REQ_LOCK)
177  /* Initialise lock acquisition. */
178  return M0_FOM_LONG_LOCK_RETURN(lock(&g_long_lock, &m->uf_link,
179  GOT_LOCK));
180  M0_ASSERT(phase == GOT_LOCK);
181  cpu_utilize(m);
182  unlock(&g_long_lock, &m->uf_link);
183 
185  return M0_FSO_WAIT;
186 }
187 
189 static int block_tick(struct m0_fom *fom)
190 {
192  cpu_utilize_with_lock(container_of(fom, struct ub_fom, uf_gen), 0);
194 
196  return M0_FSO_WAIT;
197 }
198 
199 static size_t mem_mask(enum scenario test)
200 {
201  if (test == SC_MEM_B)
202  return 0xff; /* 256 bytes max */
203  else if (test == SC_MEM_MB)
204  return 0xfffff; /* 1 MB max */
205  else
206  return 0xffff; /* 64 KB max */
207 }
208 
209 static size_t cycles(enum scenario test)
210 {
212 }
213 
215 static void cpu_utilize(const struct ub_fom *mach)
216 {
217  volatile char x M0_UNUSED;
218  size_t left;
219  size_t start;
220  size_t len;
221  size_t i;
222 
223  M0_PRE(0 <= mach->uf_test && mach->uf_test < SC_NR);
224 
225  start = mach->uf_seqn % ARRAY_SIZE(g_mem);
226  len = min_check(ARRAY_SIZE(g_mem) - start,
227  start & mem_mask(mach->uf_test));
228  M0_ASSERT(start + len <= ARRAY_SIZE(g_mem));
229 
230  for (left = cycles(mach->uf_test); left > 0; --left) {
231  for (i = start; i < start + len; ++i) {
232  switch (mach->uf_seqn % 3) {
233  case 0:
234  g_mem[i] = (char)i; /* write */
235  break;
236  case 1:
237  x = g_mem[i]; /* read */
238  break;
239  default:
240  ++g_mem[i]; /* read and write */
241  }
242  }
243  }
244 }
245 
246 static int (*ticks[SC_NR])(struct m0_fom *fom) = {
247  [SC_MEM_B] = mem_tick,
248  [SC_MEM_KB] = mem_tick,
249  [SC_MEM_MB] = mem_tick,
250  [SC_MUTEX] = mutex_tick,
253  [SC_BLOCK] = block_tick
254 };
255 
256 /* ----------------------------------------------------------------
257  * Service operations
258  * ---------------------------------------------------------------- */
259 
261 {
262  M0_PRE(service != NULL);
263  return 0;
264 }
265 
267 {
268  M0_PRE(service != NULL);
269 }
270 
272 {
273  M0_PRE(service != NULL);
274  m0_free(service);
275 }
276 
277 static const struct m0_reqh_service_ops dummy_service_ops = {
279  .rso_stop = dummy_service_stop,
280  .rso_fini = dummy_service_fini
281 };
282 
284  const struct m0_reqh_service_type *stype)
285 {
286  struct m0_reqh_service *svc;
287 
288  M0_PRE(stype != NULL && service != NULL);
289 
290  M0_ALLOC_PTR(svc);
291  M0_UB_ASSERT(svc != NULL);
292 
293  svc->rs_type = stype;
294  svc->rs_ops = &dummy_service_ops;
295  *service = svc;
296 
297  return 0;
298 }
299 
300 static const struct m0_reqh_service_type_ops _stype_ops = {
302 };
303 
305  .rst_name = "ub-fom-service",
306  .rst_ops = &_stype_ops,
307  .rst_level = M0_RS_LEVEL_NORMAL,
308 };
309 
310 /* ----------------------------------------------------------------
311  * FOM operations
312  * ---------------------------------------------------------------- */
313 
314 static void ub_fom_fini(struct m0_fom *fom)
315 {
316  struct ub_fom *m = container_of(fom, struct ub_fom, uf_gen);
317 
318  m0_long_lock_link_fini(&m->uf_link);
319  m0_fom_fini(fom);
320  m0_free(m);
321 }
322 
323 static int ub_fom_tick(struct m0_fom *fom)
324 {
325  struct ub_fom *m = container_of(fom, struct ub_fom, uf_gen);
326 
327  IS_IN_ARRAY(m->uf_test, ticks);
328  return ticks[m->uf_test](fom);
329 }
330 
331 static size_t ub_fom_home_locality(const struct m0_fom *fom)
332 {
333  static size_t locality = 0;
334 
335  M0_PRE(fom != NULL);
336  return locality++;
337 }
338 
339 static const struct m0_fom_ops ub_fom_ops = {
340  .fo_fini = ub_fom_fini,
341  .fo_tick = ub_fom_tick,
342  .fo_home_locality = ub_fom_home_locality
343 };
344 
345 static struct m0_fom_type ub_fom_type;
346 
347 static const struct m0_fom_type_ops ub_fom_type_ops = {
348  .fto_create = NULL
349 };
350 
351 static void ub_fom_create(struct m0_fom **out, struct m0_reqh *reqh,
352  size_t seqn, enum scenario test)
353 {
354  struct ub_fom *m;
355 
356  M0_ALLOC_PTR(m);
357  M0_UB_ASSERT(m != NULL);
358 
359  *out = &m->uf_gen;
361 
362  m->uf_seqn = seqn;
363  m->uf_test = test;
364  m0_long_lock_link_init(&m->uf_link, *out, NULL);
365 }
366 
367 static void
368 reqh_fom_add(struct m0_reqh *reqh, size_t seqn, enum scenario test)
369 {
370  struct m0_fom *fom;
371 
372  ub_fom_create(&fom, reqh, seqn, test);
373 
376  m0_fom_queue(fom);
378 }
379 
381 static void reqh_test(struct m0_reqh *reqh, enum scenario test)
382 {
383  size_t seqn;
384 
385  M0_LOG(M0_DEBUG, "scenario #%u", test);
386 
387  for (seqn = 0; seqn < ST_NR_FOMS; ++seqn)
388  reqh_fom_add(reqh, seqn, test);
389 
391 }
392 
393 #define _UB_ROUND_DEFINE(name, test) \
394 static void name(int iter) \
395 { \
396  reqh_test(&g_reqh, test); \
397 } \
398 struct __ ## name ## _semicolon_catcher
399 
400 _UB_ROUND_DEFINE(ub_fom_mem_b, SC_MEM_B);
401 _UB_ROUND_DEFINE(ub_fom_mem_kb, SC_MEM_KB);
402 _UB_ROUND_DEFINE(ub_fom_mem_mb, SC_MEM_MB);
403 _UB_ROUND_DEFINE(ub_fom_mutex, SC_MUTEX);
404 _UB_ROUND_DEFINE(ub_fom_mutex_per_cpu, SC_MUTEX_PER_CPU);
405 _UB_ROUND_DEFINE(ub_fom_long_lock, SC_LONG_LOCK);
406 #ifndef ENABLE_PROFILER
407 _UB_ROUND_DEFINE(ub_fom_block, SC_BLOCK);
408 #endif
409 
410 #undef _UB_ROUND_DEFINE
411 
412 /* ---------------------------------------------------------------- */
413 
414 static int _init(const char *opts M0_UNUSED)
415 {
416  size_t i;
417  int rc;
418 
420  M0_UB_ASSERT(rc == 0);
421 
424 
425  /* This benchmark doesn't need network, database and some other
426  * subsystems for its operation. Simplistic initialisation
427  * is justified. */
429  .rhia_dtm = (void *)1,
430  .rhia_db = NULL,
431  .rhia_mdstore = (void *)1,
432  .rhia_fid = &g_process_fid);
433  M0_UB_ASSERT(rc == 0);
435 
437  M0_UB_ASSERT(rc == 0);
439 
441  M0_UB_ASSERT(rc == 0);
442 
443  for (i = 0; i < ARRAY_SIZE(g_mem); ++i)
444  g_mem[i] = (char)i; /* dummy values */
445 
449  for (i = 0; i < g_mutexes_nr; ++i)
451 
453  return 0;
454 }
455 
456 static void _fini(void)
457 {
458  size_t i;
459 
461  for (i = 0; i < g_mutexes_nr; ++i)
464 
472 }
473 
475  .us_name = "fom-ub",
476  .us_init = _init,
477  .us_fini = _fini,
478  .us_run = {
479  { .ub_name = "mem-bytes",
480  .ub_iter = 1,
481  .ub_round = ub_fom_mem_b },
482  { .ub_name = "mem-KB",
483  .ub_iter = 1,
484  .ub_round = ub_fom_mem_kb },
485  { .ub_name = "mem-MB",
486  .ub_iter = 1,
487  .ub_round = ub_fom_mem_mb },
488  { .ub_name = "shared-mutex",
489  .ub_iter = 1,
490  .ub_round = ub_fom_mutex },
491  { .ub_name = "mutex-per-locality",
492  .ub_iter = 1,
493  .ub_round = ub_fom_mutex_per_cpu },
494  { .ub_name = "long-lock",
495  .ub_iter = 1,
496  .ub_round = ub_fom_long_lock },
497 #ifndef ENABLE_PROFILER
498  { .ub_name = "block",
499  .ub_iter = 1,
500  .ub_round = ub_fom_block },
501 #endif
502  { .ub_name = NULL}
503  }
504 };
505 
506 #undef M0_TRACE_SUBSYSTEM
M0_INTERNAL void m0_long_lock_fini(struct m0_long_lock *lock)
static struct m0_mutex lock
Definition: transmit.c:326
M0_INTERNAL void m0_long_lock_link_init(struct m0_long_lock_link *link, struct m0_fom *fom, struct m0_long_lock_addb2 *addb2)
Definition: fom_long_lock.c:66
static int ub_fom_tick(struct m0_fom *fom)
Definition: ub.c:323
#define M0_PRE(cond)
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
M0_INTERNAL int m0_reqh_service_start(struct m0_reqh_service *service)
Definition: reqh_service.c:343
M0_INTERNAL void m0_reqh_services_terminate(struct m0_reqh *reqh)
Definition: reqh.c:675
enum scenario uf_test
Definition: ub.c:92
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
size_t uf_seqn
Definition: ub.c:89
int(* rso_start)(struct m0_reqh_service *service)
Definition: reqh_service.h:360
static int dummy_service_allocate(struct m0_reqh_service **service, const struct m0_reqh_service_type *stype)
Definition: ub.c:283
M0_INTERNAL void m0_reqh_service_stop(struct m0_reqh_service *service)
Definition: reqh_service.c:402
M0_INTERNAL void m0_fom_block_enter(struct m0_fom *fom)
Definition: fom.c:538
#define M0_FOM_LONG_LOCK_RETURN(rc)
#define NULL
Definition: misc.h:38
static struct m0_addb2_mach * m
Definition: consumer.c:38
static size_t locality(const struct m0_fom *fom)
Definition: rm_foms.c:269
#define M0_UB_ASSERT(cond)
Definition: ub.h:37
static bool x
Definition: sm.c:168
#define M0_REQH_INIT(reqh,...)
Definition: reqh.h:262
Definition: ub.c:66
static void _fini(void)
Definition: ub.c:456
#define M0_LOG(level,...)
Definition: trace.h:167
M0_INTERNAL void m0_reqh_service_prepare_to_stop(struct m0_reqh_service *service)
Definition: reqh_service.c:375
#define min_check(a, b)
Definition: arith.h:88
int(* fto_create)(struct m0_fop *fop, struct m0_fom **out, struct m0_reqh *reqh)
Definition: fom.h:650
static struct m0_long_lock g_long_lock
Definition: ub.c:40
static struct m0_addb2_mach * mach
Definition: storage.c:42
static int block_tick(struct m0_fom *fom)
Definition: ub.c:189
static int left
Definition: locality.c:280
M0_INTERNAL void m0_long_write_unlock(struct m0_long_lock *lock, struct m0_long_lock_link *link)
#define container_of(ptr, type, member)
Definition: misc.h:33
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
M0_INTERNAL void m0_reqh_fini(struct m0_reqh *reqh)
Definition: reqh.c:320
struct m0_rwlock rh_rwlock
Definition: reqh.h:143
const struct m0_sm_conf m0_generic_conf
Definition: fom_generic.c:838
static void ub_fom_create(struct m0_fom **out, struct m0_reqh *reqh, size_t seqn, enum scenario test)
Definition: ub.c:351
struct tpool_test test[]
Definition: thread_pool.c:45
int m0_reqh_service_type_register(struct m0_reqh_service_type *rstype)
Definition: reqh_service.c:473
m0_fom_phase
Definition: fom.h:372
static void cpu_utilize_with_lock(struct ub_fom *mach, size_t lock_idx)
Definition: ub.c:104
M0_INTERNAL void m0_reqh_shutdown_wait(struct m0_reqh *reqh)
Definition: reqh.c:647
static void dummy_service_stop(struct m0_reqh_service *service)
Definition: ub.c:266
static void reqh_test(struct m0_reqh *reqh, enum scenario test)
Definition: ub.c:381
static size_t cycles(enum scenario test)
Definition: ub.c:209
void m0_fom_init(struct m0_fom *fom, const struct m0_fom_type *fom_type, const struct m0_fom_ops *ops, struct m0_fop *fop, struct m0_fop *reply, struct m0_reqh *reqh)
Definition: fom.c:1372
M0_INTERNAL bool m0_long_write_lock(struct m0_long_lock *lk, struct m0_long_lock_link *link, int next_phase)
int i
Definition: dir.c:1033
static void cpu_utilize(const struct ub_fom *mach)
Definition: ub.c:215
Definition: ub.c:60
static const struct socktype stype[]
Definition: sock.c:1156
struct m0_ub_set m0_fom_ub
Definition: ub.c:474
static int long_lock_tick(struct m0_fom *fom)
Definition: ub.c:156
scenario
Definition: ub.c:58
void m0_fom_fini(struct m0_fom *fom)
Definition: fom.c:1324
#define M0_ASSERT(cond)
const char * us_name
Definition: ub.h:76
static const struct m0_fom_type_ops ub_fom_type_ops
Definition: ub.c:347
static int(* ticks[SC_NR])(struct m0_fom *fom)
Definition: ub.c:246
const char * rst_name
Definition: reqh_service.h:447
M0_INTERNAL void m0_reqh_service_fini(struct m0_reqh_service *service)
Definition: reqh_service.c:457
M0_INTERNAL void m0_long_lock_link_fini(struct m0_long_lock_link *link)
Definition: fom_long_lock.c:76
Definition: ub.c:80
static int mutex_per_cpu_tick(struct m0_fom *fom)
Definition: ub.c:145
Definition: ub.c:63
M0_INTERNAL void m0_fom_type_init(struct m0_fom_type *type, uint64_t id, const struct m0_fom_type_ops *ops, const struct m0_reqh_service_type *svc_type, const struct m0_sm_conf *sm)
Definition: fom.c:1596
M0_INTERNAL void m0_fom_block_leave(struct m0_fom *fom)
Definition: fom.c:582
static int mutex_tick(struct m0_fom *fom)
Definition: ub.c:128
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
M0_INTERNAL uint64_t m0_reqh_nr_localities(const struct m0_reqh *reqh)
Definition: reqh.c:723
Definition: ub.c:84
M0_INTERNAL int m0_reqh_service_allocate(struct m0_reqh_service **out, const struct m0_reqh_service_type *stype, struct m0_reqh_context *rctx)
Definition: reqh_service.c:185
Definition: reqh.h:94
Definition: dump.c:103
M0_INTERNAL void m0_reqh_service_init(struct m0_reqh_service *service, struct m0_reqh *reqh, const struct m0_fid *fid)
Definition: reqh_service.c:428
M0_INTERNAL void m0_reqh_idle_wait(struct m0_reqh *reqh)
Definition: reqh.c:606
static void reqh_fom_add(struct m0_reqh *reqh, size_t seqn, enum scenario test)
Definition: ub.c:368
static int dummy_service_start(struct m0_reqh_service *service)
Definition: ub.c:260
static struct m0_mutex * g_mutexes
Definition: ub.c:38
M0_INTERNAL int m0_reqh_state_get(struct m0_reqh *reqh)
Definition: reqh.c:398
M0_INTERNAL void m0_long_lock_init(struct m0_long_lock *lock)
Definition: fom.h:481
static struct m0_reqh_service * g_svc
Definition: ub.c:35
M0_INTERNAL void m0_reqh_start(struct m0_reqh *reqh)
Definition: reqh.c:711
static size_t mem_mask(enum scenario test)
Definition: ub.c:199
struct m0_reqh reqh
Definition: rm_foms.c:48
static size_t ub_fom_home_locality(const struct m0_fom *fom)
Definition: ub.c:331
int(* rsto_service_allocate)(struct m0_reqh_service **service, const struct m0_reqh_service_type *stype)
Definition: reqh_service.h:435
#define _UB_ROUND_DEFINE(name, test)
Definition: ub.c:393
static struct m0_reqh g_reqh
Definition: ub.c:34
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
struct m0_fom uf_gen
Definition: ub.c:86
Definition: list.c:42
static struct m0_fom_type ub_fom_type
Definition: ub.c:345
static const struct m0_reqh_service_type_ops _stype_ops
Definition: ub.c:300
static struct m0_net_test_service svc
Definition: service.c:34
static int _init(const char *opts M0_UNUSED)
Definition: ub.c:414
static int start(struct m0_fom *fom)
Definition: trigger_fom.c:321
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
M0_INTERNAL void m0_rwlock_read_lock(struct m0_rwlock *lock)
Definition: rwlock.c:52
#define IS_IN_ARRAY(idx, array)
Definition: misc.h:311
M0_INTERNAL void m0_fom_queue(struct m0_fom *fom)
Definition: fom.c:624
static char g_mem[8 *(1<< 20)]
Definition: ub.c:37
void(* fo_fini)(struct m0_fom *fom)
Definition: fom.h:657
Definition: ub.c:69
M0_INTERNAL void m0_rwlock_read_unlock(struct m0_rwlock *lock)
Definition: rwlock.c:57
M0_INTERNAL void m0_long_read_unlock(struct m0_long_lock *lock, struct m0_long_lock_link *link)
#define out(...)
Definition: gen.c:41
M0_INTERNAL bool m0_long_read_lock(struct m0_long_lock *lk, struct m0_long_lock_link *link, int next_phase)
void m0_fom_phase_set(struct m0_fom *fom, int phase)
Definition: fom.c:1688
static size_t g_mutexes_nr
Definition: ub.c:39
struct m0_long_lock_link uf_link
Definition: ub.c:95
static void dummy_service_fini(struct m0_reqh_service *service)
Definition: ub.c:271
Definition: ub.c:45
void m0_free(void *data)
Definition: memory.c:146
Definition: mutex.h:47
Definition: ub.c:78
void m0_reqh_service_type_unregister(struct m0_reqh_service_type *rstype)
Definition: reqh_service.c:490
static struct m0_reqh_service * service[REQH_IN_UT_MAX]
Definition: long_lock_ut.c:46
int32_t rc
Definition: trigger_fop.h:47
static const struct m0_fom_ops ub_fom_ops
Definition: ub.c:339
#define ARRAY_SIZE(a)
Definition: misc.h:45
struct m0_fid g_process_fid
Definition: ut.c:689
Definition: ub.h:74
static void unlock(struct m0_long_lock *lock, struct m0_long_lock_link *link, bool check_ownership)
struct m0_reqh_service_type ub_fom_stype
Definition: ub.c:304
static int mem_tick(struct m0_fom *fom)
Definition: ub.c:114
static void ub_fom_fini(struct m0_fom *fom)
Definition: ub.c:314
static const struct m0_reqh_service_ops dummy_service_ops
Definition: ub.c:277
#define M0_UNUSED
Definition: misc.h:380