Motr  M0
io_sched.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 
34 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_UT
35 #include "lib/trace.h"
36 
37 #include "be/io_sched.h"
38 
39 #include "lib/memory.h" /* M0_ALLOC_ARR */
40 #include "lib/time.h" /* m0_time_now */
41 #include "lib/atomic.h" /* m0_atomic64 */
42 #include "lib/semaphore.h" /* m0_semaphore */
43 
44 #include "be/op.h" /* m0_be_op_init */
45 #include "be/io.h" /* m0_be_io_init */
46 
47 #include "ut/ut.h" /* M0_UT_ASSERT */
48 #include "ut/threads.h" /* M0_UT_THREADS_DEFINE */
49 #include "ut/stob.h" /* m0_ut_stob_linux_get */
50 #include "stob/stob.h" /* m0_stob_block_shift */
51 
52 enum {
58 };
59 
63 };
64 
68  struct m0_be_io *sis_io;
69  /* TODO dependencies etc. */
70 };
71 
73  /* number of different struct m0_be_io for the test */
74  int st_io_nr;
75  /* number of m0_be_io_sched_add() calls */
77  /* stob for I/O operations */
78  struct m0_stob *st_stob;
79  /* data for I/O operation */
80  uint64_t st_data;
81  /* seed for m0_rnd64() */
82  uint64_t st_seed;
83  /* callback execution queue */
85  /* st_states array size */
87  /* current pos in st_states */
89 
90  /* array of m0_be_io for the test */
91  struct m0_be_io *st_io;
92  /* array of m0_be_op for the array of m0_be_io */
93  struct m0_be_op *st_op;
94  /* circular buffer of m0_be_io ready to be used */
96  /* circular buffer of m0_be_op for the m0_be_io */
98  /*
99  * Current position in st_io_ready for add() operation.
100  * Absolute value.
101  * It is atomic because it is incremented in m0_be_op callbacks,
102  * which may be called from different threads (ioq threads in our case)
103  * at the same time.
104  */
106  /* The same for del() operation. */
110 };
111 
113 
115  struct m0_be_io *bio,
116  struct m0_be_op *op)
117 {
118  uint64_t pos;
119 
120  pos = m0_atomic64_add_return(&test->st_io_ready_pos_add, 1) - 1;
121  pos %= test->st_io_nr;
122  test->st_io_ready[pos] = bio;
123  test->st_op_ready[pos] = op;
124  m0_semaphore_up(&test->st_io_ready_sem);
125 }
126 
128  struct m0_be_io **bio,
129  struct m0_be_op **op)
130 {
131  uint64_t pos;
132  bool down;
133 
134  down = m0_semaphore_timeddown(&test->st_io_ready_sem,
135  m0_time_from_now(600, 0));
136  M0_ASSERT_INFO(down, "There is either bug in m0_be_io_sched "
137  "implementation or I/O on be_ut_io_sched_stob "
138  "timed out");
139  M0_ASSERT_INFO(m0_atomic64_get(&test->st_io_ready_pos_del) <
140  m0_atomic64_get(&test->st_io_ready_pos_add),
141  "pos_del=%" PRId64 " pos_add=%"PRId64,
142  m0_atomic64_get(&test->st_io_ready_pos_del),
143  m0_atomic64_get(&test->st_io_ready_pos_add));
144  pos = m0_atomic64_add_return(&test->st_io_ready_pos_del, 1) - 1;
145  pos %= test->st_io_nr;
146  *bio = test->st_io_ready[pos];
147  *op = test->st_op_ready[pos];
148 }
149 
150 /* atomically add io_state to states queue in the test */
152  struct be_ut_io_sched_io_state *state)
153 {
154  uint64_t pos;
155 
156  pos = m0_atomic64_add_return(test->st_states_pos, 1) - 1;
157  M0_UT_ASSERT(pos < test->st_states_nr);
158  test->st_states[pos] = *state;
159 }
160 
162 {
163  struct m0_be_io *bio = param;
165  struct be_ut_io_sched_io_state io_state = {
167  .sis_time = m0_time_now(),
168  .sis_io = bio,
169  };
170  be_ut_io_sched_io_state_add(test, &io_state);
172 }
173 
174 static void be_ut_io_sched_io_start_cb(struct m0_be_op *op, void *param)
175 {
176  struct m0_be_io *bio = param;
177  struct be_ut_io_sched_io_state io_state = {
179  .sis_time = m0_time_now(),
180  .sis_io = bio,
181  };
183 }
184 
185 static void be_ut_io_sched_thread(void *param)
186 {
187  struct be_ut_io_sched_test *test = param;
188  struct m0_be_io_sched *sched = &be_ut_io_sched_scheduler;
189  struct m0_be_io_credit iocred;
190  struct m0_be_io *bio;
191  struct m0_be_op *op;
192  struct m0_stob *stob = test->st_stob;
193  struct m0_ext ext;
194  m0_bcount_t len;
196  int rc;
197  int i;
198 
199  M0_ALLOC_ARR(test->st_io, test->st_io_nr);
200  M0_UT_ASSERT(test->st_io != NULL);
201  M0_ALLOC_ARR(test->st_op, test->st_io_nr);
202  M0_UT_ASSERT(test->st_op != NULL);
203  M0_ALLOC_ARR(test->st_io_ready, test->st_io_nr);
204  M0_UT_ASSERT(test->st_io_ready != NULL);
205  M0_ALLOC_ARR(test->st_op_ready, test->st_io_nr);
206  M0_UT_ASSERT(test->st_op_ready != NULL);
207  m0_semaphore_init(&test->st_io_ready_sem, 0);
208  m0_atomic64_set(&test->st_io_ready_pos_add, 0);
209  m0_atomic64_set(&test->st_io_ready_pos_del, 0);
210 
211  iocred = M0_BE_IO_CREDIT(1, sizeof(test->st_data), 1);
212  for (i = 0; i < test->st_io_nr; ++i) {
213  bio = &test->st_io[i];
214  op = &test->st_op[i];
215  m0_be_op_init(op);
217  bio, M0_BOS_ACTIVE);
219  bio, M0_BOS_DONE);
220  rc = m0_be_io_init(bio);
221  M0_UT_ASSERT(rc == 0);
222  rc = m0_be_io_allocate(bio, &iocred);
223  M0_UT_ASSERT(rc == 0);
226  }
227  for (i = 0; i < test->st_sched_add_nr; ++i) {
229  m0_be_io_reset(bio);
231  offset = m0_rnd64(&test->st_seed) %
233  m0_be_io_add(bio, stob, &test->st_data, offset,
234  sizeof(test->st_data));
236  len = m0_rnd64(&test->st_seed) % BE_UT_IO_SCHED_EXT_SIZE_MAX +
237  (m0_rnd64(&test->st_seed) & 0xff) + 1;
238  ext.e_end = m0_atomic64_add_return(test->st_ext_index, len);
239  ext.e_start = ext.e_end - len;
240  m0_be_io_sched_lock(sched);
241  m0_be_io_sched_add(sched, bio, &ext, op);
242  m0_be_io_sched_unlock(sched);
243  }
244  for (i = 0; i < test->st_io_nr; ++i) {
246  m0_be_io_deallocate(bio);
247  m0_be_io_fini(bio);
248  m0_be_op_fini(op);
249  }
250 
251  m0_semaphore_fini(&test->st_io_ready_sem);
252  m0_free(test->st_op_ready);
253  m0_free(test->st_io_ready);
254  m0_free(test->st_op);
255  m0_free(test->st_io);
256 }
257 
258 static void
260  int states_nr,
261  struct m0_atomic64 *states_pos)
262 {
263  int pos = m0_atomic64_get(states_pos);
264 
265  M0_UT_ASSERT(pos == states_nr);
266  /* TODO additional checks */
267 }
268 
270 
285 {
287  struct be_ut_io_sched_test *tests;
288  struct m0_be_io_sched_cfg cfg = {
289  .bisc_pos_start = 0x1234,
290  };
291  struct m0_be_io_sched *sched = &be_ut_io_sched_scheduler;
292  struct m0_atomic64 states_pos;
293  struct m0_atomic64 ext_index;
294  struct m0_stob *stob;
295  uint64_t seed = 0;
296  int states_nr;
297  int rc;
298  int i;
299 
301  M0_UT_ASSERT(tests != NULL);
303  M0_ALLOC_ARR(states, states_nr);
306  M0_UT_ASSERT(stob != NULL);
307  m0_atomic64_set(&states_pos, 0);
308  m0_atomic64_set(&ext_index, cfg.bisc_pos_start);
309  for (i = 0; i < BE_UT_IO_SCHED_THREAD_NR; ++i) {
310  tests[i] = (struct be_ut_io_sched_test){
311  .st_io_nr = BE_UT_IO_SCHED_IO_NR,
312  .st_sched_add_nr = BE_UT_IO_SCHED_ADD_NR,
313  .st_stob = stob,
314  .st_data = m0_rnd64(&seed),
315  .st_seed = i,
316  .st_states = states,
317  .st_states_nr = states_nr,
318  .st_states_pos = &states_pos,
319  .st_ext_index = &ext_index,
320  };
321  }
322 
323  M0_SET0(sched);
324  rc = m0_be_io_sched_init(sched, &cfg);
325  M0_UT_ASSERT(rc == 0);
327  M0_UT_THREADS_STOP(be_ut_io_sched);
328  m0_be_io_sched_fini(sched);
329 
330  be_ut_io_sched_states_check(states, states_nr, &states_pos);
331 
332  m0_ut_stob_put(stob, true);
333  m0_free(states);
334  m0_free(tests);
335 }
336 
338 #undef M0_TRACE_SUBSYSTEM
339 
340 /*
341  * Local variables:
342  * c-indentation-style: "K&R"
343  * c-basic-offset: 8
344  * tab-width: 8
345  * fill-column: 80
346  * scroll-step: 1
347  * End:
348  */
349 /*
350  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
351  */
static void be_ut_io_sched_states_check(struct be_ut_io_sched_io_state *states, int states_nr, struct m0_atomic64 *states_pos)
Definition: io_sched.c:259
static void be_ut_io_sched_io_completion_cb(struct m0_be_op *op, void *param)
Definition: io_sched.c:161
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
m0_bcount_t bisc_pos_start
Definition: io_sched.h:44
struct m0_be_io * st_io
Definition: io_sched.c:91
uint64_t st_seed
Definition: io_sched.c:82
m0_bindex_t e_end
Definition: ext.h:40
struct m0_atomic64 * st_states_pos
Definition: io_sched.c:88
#define NULL
Definition: misc.h:38
Definition: io.h:230
static void be_ut_io_sched_io_start_cb(struct m0_be_op *op, void *param)
Definition: io_sched.c:174
uint64_t m0_time_t
Definition: time.h:37
M0_INTERNAL bool m0_semaphore_timeddown(struct m0_semaphore *semaphore, const m0_time_t abs_timeout)
Definition: semaphore.c:75
static char * tests
Definition: st_kmain.c:52
struct m0_atomic64 st_io_ready_pos_del
Definition: io_sched.c:107
M0_UT_THREADS_DEFINE(be_ut_io_sched, &be_ut_io_sched_thread)
uint64_t m0_bindex_t
Definition: types.h:80
uint64_t m0_bcount_t
Definition: types.h:77
M0_INTERNAL void m0_be_op_callback_set(struct m0_be_op *op, m0_be_op_cb_t cb, void *param, enum m0_be_op_state state)
Definition: op.c:239
#define M0_SET0(obj)
Definition: misc.h:64
struct m0_atomic64 * st_ext_index
Definition: io_sched.c:109
op
Definition: libdemo.c:64
M0_INTERNAL void m0_be_io_configure(struct m0_be_io *bio, enum m0_stob_io_opcode opcode)
Definition: io.c:516
int i
Definition: dir.c:1033
M0_INTERNAL struct m0_stob * m0_ut_stob_linux_get(void)
Definition: stob.c:169
M0_INTERNAL void m0_be_io_fini(struct m0_be_io *bio)
Definition: io.c:224
struct be_ut_io_sched_io_state * st_states
Definition: io_sched.c:84
M0_INTERNAL int m0_be_io_sched_init(struct m0_be_io_sched *sched, struct m0_be_io_sched_cfg *cfg)
Definition: io_sched.c:51
static void be_ut_io_sched_io_ready_get(struct be_ut_io_sched_test *test, struct m0_be_io **bio, struct m0_be_op **op)
Definition: io_sched.c:127
M0_INTERNAL void * m0_be_io_user_data(struct m0_be_io *bio)
Definition: io.c:677
static void be_ut_io_sched_io_ready_add(struct be_ut_io_sched_test *test, struct m0_be_io *bio, struct m0_be_op *op)
Definition: io_sched.c:114
struct m0_atomic64 st_io_ready_pos_add
Definition: io_sched.c:105
Definition: stob.h:163
static struct m0_stob * stob
Definition: storage.c:39
m0_time_t m0_time_now(void)
Definition: time.c:134
M0_INTERNAL int m0_be_io_init(struct m0_be_io *bio)
Definition: io.c:175
static void be_ut_io_sched_thread(void *param)
Definition: io_sched.c:185
M0_INTERNAL void m0_be_io_sched_lock(struct m0_be_io_sched *sched)
Definition: io_sched.c:70
M0_INTERNAL int m0_semaphore_init(struct m0_semaphore *semaphore, unsigned value)
Definition: semaphore.c:38
M0_INTERNAL void m0_be_io_sched_fini(struct m0_be_io_sched *sched)
Definition: io_sched.c:64
struct m0_semaphore st_io_ready_sem
Definition: io_sched.c:108
static m0_bindex_t offset
Definition: dump.c:173
static void be_ut_io_sched_io_state_add(struct be_ut_io_sched_test *test, struct be_ut_io_sched_io_state *state)
Definition: io_sched.c:151
#define M0_BE_IO_CREDIT(reg_nr, reg_size, part_nr)
Definition: io.h:76
M0_INTERNAL void m0_ut_stob_put(struct m0_stob *stob, bool destroy)
Definition: stob.c:185
M0_INTERNAL void m0_be_io_user_data_set(struct m0_be_io *bio, void *data)
Definition: io.c:672
#define PRId64
Definition: types.h:57
static int64_t m0_atomic64_get(const struct m0_atomic64 *a)
M0_INTERNAL void m0_be_op_reset(struct m0_be_op *op)
Definition: op.c:152
enum be_ut_io_sched_io_op sis_op
Definition: io_sched.c:66
struct m0_be_op * st_op
Definition: io_sched.c:93
M0_INTERNAL void m0_be_io_sched_unlock(struct m0_be_io_sched *sched)
Definition: io_sched.c:75
M0_INTERNAL uint64_t m0_rnd64(uint64_t *seed)
Definition: misc.c:100
uint64_t st_data
Definition: io_sched.c:80
be_ut_io_sched_io_op
Definition: io_sched.c:60
Definition: ext.h:37
void m0_be_ut_io_sched(void)
Definition: io_sched.c:284
m0_bindex_t e_start
Definition: ext.h:39
struct m0_be_io * sis_io
Definition: io_sched.c:68
M0_INTERNAL int m0_be_io_allocate(struct m0_be_io *bio, struct m0_be_io_credit *iocred)
Definition: io.c:180
M0_INTERNAL void m0_semaphore_fini(struct m0_semaphore *semaphore)
Definition: semaphore.c:45
Definition: list.c:42
struct m0_be_io ** st_io_ready
Definition: io_sched.c:95
M0_INTERNAL void m0_be_io_deallocate(struct m0_be_io *bio)
Definition: io.c:215
m0_time_t m0_time_from_now(uint64_t secs, long ns)
Definition: time.c:96
M0_INTERNAL void m0_be_op_fini(struct m0_be_op *op)
Definition: stubs.c:92
M0_INTERNAL void m0_be_io_sched_add(struct m0_be_io_sched *sched, struct m0_be_io *io, struct m0_ext *ext, struct m0_be_op *op)
Definition: io_sched.c:176
#define M0_UT_THREADS_STOP(name)
Definition: threads.h:55
Definition: io.h:87
#define M0_ASSERT_INFO(cond, fmt,...)
#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:59
Definition: op.h:74
M0_INTERNAL void m0_be_op_init(struct m0_be_op *op)
Definition: stubs.c:87
void m0_free(void *data)
Definition: memory.c:146
M0_INTERNAL void m0_be_io_add(struct m0_be_io *bio, struct m0_stob *stob, void *ptr_user, m0_bindex_t offset_stob, m0_bcount_t size)
Definition: io.c:280
struct m0_stob * st_stob
Definition: io_sched.c:78
M0_INTERNAL void m0_be_io_reset(struct m0_be_io *bio)
Definition: io.c:651
int32_t rc
Definition: trigger_fop.h:47
static struct m0_sm_state_descr states[C_NR]
Definition: sm.c:512
#define M0_UT_ASSERT(a)
Definition: ut.h:46
static struct m0_be_io_sched be_ut_io_sched_scheduler
Definition: io_sched.c:112
static int64_t m0_atomic64_add_return(struct m0_atomic64 *a, int64_t d)
static void m0_atomic64_set(struct m0_atomic64 *a, int64_t num)
struct m0_be_op ** st_op_ready
Definition: io_sched.c:97