Motr  M0
st.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 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 
26 #ifndef __KERNEL__
27 #include <errno.h>
28 #include <sys/types.h>
29 #endif
30 
31 #include "motr/st/st.h"
32 #include "motr/st/st_misc.h"
33 #include "motr/st/st_assert.h"
34 
35 static struct m0_st_ctx ctx = {
36  .sx_cfg = {
37  .sc_nr_threads = 1,
38  .sc_run_selected = 0,
39  .sc_nr_rounds = 1,
40  .sc_mode = ST_SEQ_MODE,
41  .sc_pace = 0,
42  },
43  .sx_nr_all = 0,
44  .sx_nr_selected = 0,
45 };
46 
47 struct m0* st_get_motr(void)
48 {
49  return ctx.sx_instance.si_instance->m0c_motr;
50 }
51 
53 {
54  ctx.sx_instance.si_instance = instance;
55 }
56 
58 {
59  return ctx.sx_instance.si_instance;
60 }
61 
63 {
64  return ctx.sx_cfg;
65 }
66 
68 {
69  if (idx < 0 || idx >= ctx.sx_cfg.sc_nr_threads)
70  return NULL;
71 
72  return ctx.sx_worker_stats + idx;
73 }
74 
75 void st_set_tests(const char *tests)
76 {
77  ctx.sx_cfg.sc_tests = tests;
78 }
79 
80 const char* st_get_tests()
81 {
82  return ctx.sx_cfg.sc_tests;
83 }
84 
86 {
87  ctx.sx_cfg.sc_mode = mode;
88 }
89 
91 {
92  return ctx.sx_cfg.sc_mode;
93 }
94 
96 {
97  if (nr < ST_MAX_WORKER_NUM)
98  ctx.sx_cfg.sc_nr_threads = nr;
99  else
100  ctx.sx_cfg.sc_nr_threads = ST_MAX_WORKER_NUM;
101 }
102 
104 {
105  return ctx.sx_cfg.sc_nr_threads;
106 }
107 
108 int st_set_worker_tid(int idx, pid_t tid)
109 {
110  if (ctx.sx_worker_tids == NULL
111  || idx >= ctx.sx_cfg.sc_nr_threads)
112  return -EINVAL;
113 
114  ctx.sx_worker_tids[idx] = tid;
115 
116  return 0;
117 }
118 
119 int st_get_worker_idx(pid_t tid)
120 {
121  int i;
122 
123  if (ctx.sx_worker_tids == NULL)
124  return -ENOMEM;
125 
126  for (i = 0; i < ctx.sx_cfg.sc_nr_threads; i++) {
127  if (ctx.sx_worker_tids[i] == tid)
128  break;
129  }
130 
131  /* not found */
132  if (i == ctx.sx_cfg.sc_nr_threads)
133  return -EINVAL;
134 
135  return i;
136 }
137 
138 static struct st_suite *lookup_suite(const char *name)
139 {
140  int i;
141 
142  if (name == NULL)
143  return NULL;
144 
145  for (i = 0; i < ctx.sx_nr_all; ++i)
146  if (str_eq(ctx.sx_all[i]->ss_name, name))
147  return ctx.sx_all[i];
148  return NULL;
149 }
150 
151 static struct st_test *lookup_test(struct st_suite *s,
152  const char *t_name)
153 {
154  struct st_test *t;
155 
156  if (s == NULL || t_name == NULL)
157  return NULL;
158 
159  for (t = s->ss_tests; t->st_name != NULL; t++)
160  if (str_eq(t->st_name, t_name))
161  return t;
162 
163  return NULL;
164 }
165 
166 static int select_tests(const char *str)
167 {
168  char *s;
169  char *p;
170  char *token;
171  char *sub_token;
172  struct st_suite *suite;
173  struct st_test *test;
174 
175  s = str_dup(str);
176  if (s == NULL)
177  return -ENOMEM;
178  p = s;
179 
180  while (true) {
181  token = strsep(&p, ",");
182  if (token == NULL)
183  break;
184 
185  sub_token = strchr(token, ':');
186  if (sub_token != NULL)
187  *sub_token++ = '\0';
188 
189  suite = lookup_suite(token);
190  if (suite == NULL) continue;
191 
192  if (sub_token != NULL) {
193  test = lookup_test(suite, sub_token);
194  if (test == NULL) continue;
195 
196  test->st_enabled = 1;
197  } else {
198  /* All tests in this suite will be marked*/
199  test = suite->ss_tests;
200  while (test->st_name != NULL) {
201  test->st_enabled = 1;
202  test++;
203  }
204  }
205 
206  ctx.sx_selected[ctx.sx_nr_selected++] = suite;
207  }
208 
209  mem_free(s);
210  return 0;
211 }
212 
213 static int shuffle_tests(struct st_suite *suite)
214 {
215  int i;
216  int j;
217  int k;
218  int index;
219  int nr_tests;
220  int *order;
221  struct st_test t1;
222  struct st_test t2;
223 
224  /* Count the tests */
225  nr_tests = 0;
226  while (suite->ss_tests[nr_tests].st_name != NULL)
227  nr_tests++;
228 
229  MEM_ALLOC_ARR(order, nr_tests);
230  if (order == NULL)
231  return -ENOMEM;
232 
233  /* Produce a new order */
234  for (i = 0; i < nr_tests; ) {
235  index = generate_random(nr_tests);
236  for (j = 0; j < i; j++)
237  if (order[j] == index) break;
238 
239  if (i == j) {
240  order[i] = index;
241  i++;
242  }
243  /* will be a indefinite loop? In theory, no!*/
244  }
245 
246  /*
247  * Re-write the test order. As the number of tests in a
248  * suite is small (< 100), this shouldn't be a big issue
249  * for performance.
250  */
251  k = 0;
252  t1 = suite->ss_tests[0];
253  for (i = 0; i < nr_tests; i++){
254 
255  /* look for the test to be replaced*/
256  for (j = 0; j < nr_tests; j++)
257  if (order[j] == k) break;
258 
259  t2 = suite->ss_tests[j];
260  suite->ss_tests[j] = t1;
261  t1 = t2;
262  k = j;
263  }
264  mem_free(order);
265 
266  return 0;
267 }
268 
269 M0_UNUSED static inline const char *skipspaces(const char *str)
270 {
271  while (isspace(*str))
272  ++str;
273  return str;
274 }
275 
276 static const char padding[256] = { [0 ... 254] = ' ', [255] = '\0' };
277 
278 static void run_test(const struct st_test *test)
279 {
280  size_t len;
281  size_t pad_len;
282  size_t name_len;
283  size_t max_name_len;
284  uint64_t start;
285  uint64_t end;
286  uint64_t duration;
287 
288  console_printf(LOG_PREFIX " %s ", test->st_name);
289 
290  start = time_now();
291 
292  /*
293  * Turn on the cleaner so we have a chance to cleanup
294  * mess when an assert fails
295  */
297 
298  /* run the test */
299  test->st_proc();
300 
301  /* Turn off cleaner now */
303 
304  end = time_now();
305  duration = end - start;
306 
307  /* generate report */
308  name_len = strlen(test->st_name);
309  max_name_len = ctx.sx_max_name_len;
310 
311  len = (name_len > max_name_len)?name_len:max_name_len;
312  pad_len = len - name_len;
313  pad_len = (pad_len < ARRAY_SIZE(padding) - 1)?
314  pad_len:(ARRAY_SIZE(padding) - 1);
315 
316  console_printf("%.*s%4" PRIu64 ".%-2" PRIu64 " sec\n",
317  (int)pad_len, padding, time_seconds(duration),
319 }
320 
321 static int run_suite(struct st_suite *suite)
322 {
323  int rc = 0;
324  uint64_t start;
325  uint64_t end;
326  uint64_t duration;
327  const struct st_test *test;
328 
329  /* Change test order if random mode is enabled */
330  if (st_get_test_mode() == ST_RAND_MODE) {
331  rc = shuffle_tests(suite);
332  if (rc < 0)
333  return rc;
334  }
335 
336  /* Real test starts here*/
337  console_printf("\n%s\n", suite->ss_name);
338  start = time_now();
339 
340  /* suite initialisation */
341  if (suite->ss_init != NULL) {
342  rc = suite->ss_init();
343  if (rc != 0) {
344  console_printf("Client ST suite initialization failure.\n");
345  return rc;
346  }
347  }
348  /* run test and speed control */
349  for (test = suite->ss_tests; test->st_name != NULL; test++){
350  if (ctx.sx_cfg.sc_run_selected == 1
351  && test->st_enabled == 0)
352  continue;
353 
354  run_test(test);
355 
356  /* clean the mess left by this test*/
358  }
359 
360  /* suite finalisation */
361  if (suite->ss_fini != NULL) {
362  rc = suite->ss_fini();
363  if (rc != 0)
364  console_printf("Client ST suite finalization failure.\n");
365  }
366 
367  /* generate report */
368  end = time_now();
369  duration = end - start;
370 
371  console_printf(LOG_PREFIX " [ time: %" PRIu64 ".%-" PRIu64 " sec]\n",
374  return rc;
375 }
376 
377 static int run_suites(struct st_suite **suites, int nr_suites)
378 {
379  int i;
380  int rc;
381 
382  rc = 0;
383  for (i = 0; i < nr_suites && rc == 0; i++)
384  rc = run_suite(suites[i]);
385 
386  return rc;
387 }
388 
389 int st_run(const char *test_list_str)
390 {
391  int rc;
392  int worker_idx;
393  uint64_t start;
394  uint64_t end;
395  uint64_t duration;
396  uint64_t nr_asserts = 0;
397  uint64_t nr_failed_asserts = 0;
398  uint64_t csec;
399 
400  worker_idx = st_get_worker_idx(get_tid());
401  if (worker_idx < 0)
402  return worker_idx;
403 
404  /* Runs all test suites now*/
405  start = time_now();
406  ctx.sx_worker_stats[worker_idx].sws_nr_asserts = 0;
407  ctx.sx_worker_stats[worker_idx].sws_nr_failed_asserts = 0;
408 
409  if (test_list_str == NULL)
410  rc = run_suites(ctx.sx_all, ctx.sx_nr_all);
411  else {
412  ctx.sx_cfg.sc_run_selected = true;
413  select_tests(test_list_str);
414  rc = run_suites(ctx.sx_selected, ctx.sx_nr_selected);
415  }
416 
417  /* Generates report */
418  end = time_now();
419  duration = end - start;
420  csec = time_nanoseconds(duration) / TIME_ONE_MSEC / 10;
421  nr_asserts = ctx.sx_worker_stats[worker_idx].sws_nr_asserts;
422  nr_failed_asserts =
423  ctx.sx_worker_stats[worker_idx].sws_nr_failed_asserts;
424 
425  if (rc == 0)
426  console_printf("\nTime: %" PRIu64 ".%-2" PRIu64 " sec,"
427  " Asserts: %" PRIu64 ", "
428  " Failed Asserts: %" PRIu64
429  "\nClient tests Done\n",
430  time_seconds(duration), csec,
431  nr_asserts, nr_failed_asserts);
432  return nr_failed_asserts;
433 }
434 
435 void st_list(bool with_tests)
436 {
437  int i;
438  const struct st_test *t;
439 
440  for (i = 0; i < ctx.sx_nr_all; ++i) {
441  console_printf("%s\n", ctx.sx_all[i]->ss_name);
442  if (with_tests)
443  for (t = ctx.sx_all[i]->ss_tests; t->st_name != NULL; t++)
444  console_printf(" %s\n", t->st_name);
445  }
446 }
447 
448 int st_init(void)
449 {
450  /* Object ID allocator */
452 
453  /* allocate memory for test suites */
455  if (ctx.sx_all == NULL)
456  goto err_exit;
457 
458  MEM_ALLOC_ARR(ctx.sx_selected, ST_MAX_SUITE_NUM);
459  if (ctx.sx_selected == NULL)
460  goto err_exit;
461 
462  MEM_ALLOC_ARR(ctx.sx_worker_tids, ST_MAX_WORKER_NUM);
463  if (ctx.sx_worker_tids == NULL)
464  goto err_exit;
465 
466  MEM_ALLOC_ARR(ctx.sx_worker_stats, ST_MAX_WORKER_NUM);
467  if (ctx.sx_worker_stats == NULL)
468  goto err_exit;
469 
470  return 0;
471 
472 err_exit:
474 
475  if (ctx.sx_all != NULL)
476  mem_free(ctx.sx_all);
477 
478  if (ctx.sx_selected != NULL)
479  mem_free(ctx.sx_selected);
480 
481  if (ctx.sx_worker_tids != NULL)
482  mem_free(ctx.sx_worker_tids);
483 
484  if (ctx.sx_worker_stats != NULL)
485  mem_free(ctx.sx_worker_stats);
486 
487  return -ENOMEM;
488 }
489 
490 void st_fini(void)
491 {
493 
494  /* free memory */
495  mem_free(ctx.sx_all);
496  mem_free(ctx.sx_selected);
497 
498  return;
499 }
500 
501 int st_add(struct st_suite *suite)
502 {
503  int str_len;
504  size_t max_len;
505  struct st_test *t;
506 
507  if (ctx.sx_nr_all >= ST_MAX_SUITE_NUM)
508  return -EINVAL;
509 
510  /* check if tests in this suite have been correctly set*/
511  max_len = ctx.sx_max_name_len;
512  for (t = suite->ss_tests; t->st_name != NULL; t++){
513  if (t->st_proc == NULL)
514  return -EINVAL;
515 
516  str_len = strlen(t->st_name);
517  max_len = (str_len > max_len)?str_len:max_len;
518  }
519 
520  /* update ctx details*/
521  ctx.sx_all[ctx.sx_nr_all++] = suite;
522  ctx.sx_max_name_len = max_len;
523 
524  return 0;
525 }
526 
530 extern struct st_suite st_suite_idx;
531 extern struct st_suite st_suite_obj;
532 extern struct st_suite st_suite_m0_read;
533 extern struct st_suite st_suite_m0_write;
534 extern struct st_suite st_suite_osync;
535 extern struct st_suite st_suite_isync;
536 extern struct st_suite st_suite_layout;
537 extern struct st_suite st_suite_example;
538 extern struct st_suite st_suite_mt;
539 extern struct st_suite st_suite_cancel;
540 
542 {
551 #ifndef __KERNEL__
554 #endif
555 }
556 
557 /*
558  * Local variables:
559  * c-indentation-style: "K&R"
560  * c-basic-offset: 8
561  * tab-width: 8
562  * fill-column: 80
563  * scroll-step: 1
564  * End:
565  */
static struct m0_addb2_philter p
Definition: consumer.c:40
Definition: st.h:104
static size_t nr
Definition: dump.c:1505
struct st_worker_stat * st_get_worker_stat(int idx)
Definition: st.c:67
void st_cleaner_disable()
Definition: st_assert.c:348
struct st_test ss_tests[]
Definition: st.h:92
#define NULL
Definition: misc.h:38
static struct st_suite * lookup_suite(const char *name)
Definition: st.c:138
static struct st_test * lookup_test(struct st_suite *s, const char *t_name)
Definition: st.c:151
static char * tests
Definition: st_kmain.c:52
void st_cleaner_empty_bin()
Definition: st_assert.c:418
int st_run(const char *test_list_str)
Definition: st.c:389
struct st_suite st_suite_cancel
Definition: cancel.c:265
struct st_suite st_suite_m0_read
Definition: read.c:630
struct st_suite st_suite_mt
Definition: mt_fom.c:526
struct st_suite st_suite_isync
Definition: isync.c:520
Definition: st.h:73
void st_list(bool with_tests)
Definition: st.c:435
struct st_suite st_suite_example
Definition: example.c:244
int st_set_worker_tid(int idx, pid_t tid)
Definition: st.c:108
static void run_test(const struct st_test *test)
Definition: st.c:278
void st_set_instance(struct m0_client *instance)
Definition: st.c:52
struct tpool_test test[]
Definition: thread_pool.c:45
#define str_eq(a, b)
Definition: st_misc.h:58
int oid_allocator_fini(void)
Definition: oid.c:454
static void t2(int n)
Definition: thread.c:48
int st_get_nr_workers(void)
Definition: st.c:103
int i
Definition: dir.c:1033
#define PRIu64
Definition: types.h:58
void st_fini(void)
Definition: st.c:490
void st_set_nr_workers(int nr)
Definition: st.c:95
void st_add_suites()
Definition: st.c:541
struct st_suite st_suite_idx
Definition: idx.c:1322
const char * name
Definition: trace.c:110
struct m0 * st_get_motr(void)
Definition: st.c:47
int st_init(void)
Definition: st.c:448
Definition: st.h:151
static void duration(struct m0_addb2__context *ctx, const uint64_t *v, char *buf)
Definition: dump.c:503
Definition: st.h:83
const char * st_name
Definition: st.h:75
static struct m0_thread t[8]
Definition: service_ut.c:1230
Definition: instance.h:80
void st_set_tests(const char *tests)
Definition: st.c:75
int(* ss_fini)(void)
Definition: st.h:89
static int struct dentry int mode
Definition: dir.c:589
static void token(struct ff2c_context *ctx, struct ff2c_term *term, struct ff2c_token *tok)
Definition: parser.c:66
struct st_suite st_suite_obj
Definition: obj.c:735
void console_printf(const char *fmt,...)
Definition: st_misc.c:155
static void mem_free(const struct m0_be_btree *btree, struct m0_be_tx *tx, void *ptr)
Definition: btree.c:102
struct st_suite st_suite_osync
Definition: osync.c:466
struct st_suite st_suite_m0_write
Definition: write.c:716
int(* ss_init)(void)
Definition: st.h:88
uint64_t time_now(void)
Definition: st_misc.c:69
struct st_suite st_suite_layout
Definition: layout.c:1140
enum st_mode st_get_test_mode(void)
Definition: st.c:90
static M0_UNUSED const char * skipspaces(const char *str)
Definition: st.c:269
#define MEM_ALLOC_ARR(arr, nr)
Definition: st_misc.h:80
static int run_suite(struct st_suite *suite)
Definition: st.c:321
Definition: list.c:42
struct m0_client * st_get_instance()
Definition: st.c:57
Definition: st.h:99
int oid_allocator_init(void)
Definition: oid.c:426
static int start(struct m0_fom *fom)
Definition: trigger_fom.c:321
const char * st_get_tests()
Definition: st.c:80
static struct m0 instance
Definition: main.c:78
uint32_t generate_random(uint32_t max)
Definition: st_misc.c:164
const char * ss_name
Definition: st.h:85
#define LOG_PREFIX
uint64_t time_seconds(const uint64_t time)
Definition: st_misc.c:79
static int select_tests(const char *str)
Definition: st.c:166
static void t1(int n)
Definition: mutex.c:48
pid_t get_tid(void)
Definition: st_misc.c:150
int st_get_worker_idx(pid_t tid)
Definition: st.c:119
static int shuffle_tests(struct st_suite *suite)
Definition: st.c:213
struct st_cfg st_get_cfg()
Definition: st.c:62
Definition: nucleus.c:42
static const char padding[256]
Definition: st.c:276
#define str_dup(s)
Definition: st_misc.h:52
int st_add(struct st_suite *suite)
Definition: st.c:501
static struct m0_addb2_source * s
Definition: consumer.c:39
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
st_mode
Definition: st.h:98
uint64_t time_nanoseconds(const uint64_t time)
Definition: st_misc.c:84
void st_cleaner_enable()
Definition: st_assert.c:337
static int run_suites(struct st_suite **suites, int nr_suites)
Definition: st.c:377
void st_set_test_mode(enum st_mode mode)
Definition: st.c:85
#define M0_UNUSED
Definition: misc.h:380