Motr  M0
time.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2013-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 #include "lib/time.h" /* m0_time_t */
24 
25 #include "lib/arith.h" /* max_check */
26 #include "lib/assert.h" /* M0_PRE */
27 #include "lib/atomic.h" /* m0_atomic64 */
28 #include "lib/semaphore.h" /* m0_semaphore */
29 #include "lib/thread.h" /* m0_thread */
30 #include "lib/trace.h" /* M0_LOG */
31 #include "lib/ub.h" /* m0_ub_set */
32 
33 #include "ut/ut.h" /* M0_UT_ASSERT */
34 
35 enum {
37  TIME_VALUES_NR = 0x10000,
39  DIFF_ACCEPTED = 2000000,
40 };
41 
42 struct time_test {
45  int64_t tt_prev_index;
46 };
47 
51 };
52 
55 static struct m0_atomic64 time_index;
56 static unsigned long err_nr;
59 static void time_test_simple(void)
60 {
61  m0_time_t t1, t2, t3;
62  int rc;
63 
64  t1 = m0_time(1, 0);
65  t2 = m0_time(2, 0);
66  M0_UT_ASSERT(t2 > t1);
69 
70  t1 = m0_time(1234, 0);
72 
73  t1 = m0_time_now();
74  t2 = t1;
75  M0_UT_ASSERT(t1 != 0);
76 
77  t1 = m0_time(1234, 987654321);
78  M0_UT_ASSERT(t1 == 1234987654321);
79 
80  t2 = t1;
81  M0_UT_ASSERT(t2 == t1);
82 
83  t2 = m0_time(1235, 987654322);
84  M0_UT_ASSERT(t2 > t1);
85 
86  t3 = m0_time_sub(t2, t1);
87  M0_UT_ASSERT(t3 == 1000000001);
88 
89  t2 = m0_time(1, 500000000);
90  t3 = m0_time_add(t1, t2);
91  M0_UT_ASSERT(t3 == 1236487654321);
92 
93  t2 = m0_time(0, M0_TIME_ONE_SECOND / 100);
94  rc = m0_nanosleep(t2, &t1);
95  M0_UT_ASSERT(rc == 0);
96 
97  t1 = m0_time(1234, 987654321);
100 
101  t2 = m0_time(1, 500000000);
104 
107 }
108 
109 static void time_thread(int thread_index)
110 {
111  struct time_test_thread *th = &time_threads[thread_index];
112  int64_t prev_index = -1;
113  int64_t index;
114 
116  while ((index = m0_atomic64_add_return(&time_index, 1)) <=
117  TIME_VALUES_NR) {
118  m0_mb();
119  time_values[--index] = (struct time_test) {
120  .tt_now = m0_time_now(),
121  .tt_thread_index = thread_index,
122  .tt_prev_index = prev_index,
123  };
124  prev_index = index;
125  m0_mb();
126  }
127 }
128 
129 static m0_time_t tv(int index)
130 {
131  M0_ASSERT(index >= -1 && index < TIME_VALUES_NR);
132  return index == -1 ? 0 : time_values[index].tt_now;
133 }
134 
136 {
137  M0_ASSERT(index >= 0 && index < TIME_VALUES_NR);
138  return tv(time_values[index].tt_prev_index);
139 }
140 
141 /*
142  * [a], [b], [c] - sequential time measurements for some thread.
143  * prev[index] - previous measurement for thread that have measurement #'index'
144  * The following statements should be true if time is monotonic:
145  * - [a] <= [b]
146  * - [b] <= [c]
147  * - for each measurement [i] in range (b, c): prev[i] <= [c]
148  * - for each measurement [i] in range (b, c): [a] <= [i]
149  */
150 static void time_test_check(int64_t a, int64_t b, int64_t c)
151 {
152  int i;
153 
154  M0_PRE(b != -1 && c != -1);
155  M0_UT_ASSERT(tv(a) <= tv(b) && tv(b) <= tv(c));
156  for (i = b + 1; i <= c - 1; ++i) {
157  /* check if m0_time_now() is out-of-sync and record mistiming */
158  err_max = max3(err_max, tv_prev(i) > tv(c) ?
159  tv_prev(i) - tv(c) : err_max,
160  tv(a) > tv(i) ?
161  tv(a) - tv(i) : err_max);
162  err_nr += tv_prev(i) > tv(c);
163  err_nr += tv(a) > tv(i);
165  M0_UT_ASSERT(tv(a) <= tv(i) + DIFF_ACCEPTED);
166  }
167 }
168 
169 static void time_test_mt_nr(int threads_nr)
170 {
171  static struct time_test_thread *th;
172  int i;
173  int rc;
174  int64_t b;
175  int64_t c;
176  bool checked[THREADS_NR_MAX] = { };
177 
179  err_nr = 0;
180  err_max = 0;
181  /* start time_thread()s */
182  for (i = 0; i < threads_nr; ++i) {
183  th = &time_threads[i];
184  rc = m0_semaphore_init(&th->tth_start, 0);
185  M0_UT_ASSERT(rc == 0);
186  rc = M0_THREAD_INIT(&th->tth_thread, int, NULL, &time_thread, i,
187  "#%d_time_thread", i);
188  M0_UT_ASSERT(rc == 0);
189  }
190  /* barrier with all time_thread()s */
191  for (i = 0; i < threads_nr; ++i)
193  /* wait until all threads finished */
194  for (i = 0; i < threads_nr; ++i) {
195  th = &time_threads[i];
196  rc = m0_thread_join(&th->tth_thread);
197  M0_UT_ASSERT(rc == 0);
200  }
202  /* check monotony of m0_time_now() results */
203  for (i = TIME_VALUES_NR - 1; i >= 0; --i) {
204  if (checked[time_values[i].tt_thread_index])
205  continue;
207  b = i;
208  while (1) {
209  c = b;
211  if (b == -1)
212  break;
213  time_test_check(time_values[b].tt_prev_index, b, c);
214  }
215  }
216  if (err_nr != 0) {
217  M0_LOG(M0_DEBUG, "time UT: threads = %d, samples = %d, "
218  "number of out-of-sync errors = %lu, "
219  "maximum out-of-sync error = %lu ns",
220  threads_nr, TIME_VALUES_NR,
221  err_nr, (unsigned long) err_max);
222  } else {
223  M0_LOG(M0_DEBUG, "time UT: threads = %d, "
224  "no out-of-sync errors found", threads_nr);
225  }
226 }
227 
228 void m0_ut_time_test(void)
229 {
230  int t;
231 
233  for (t = 1; t <= THREADS_NR_MAX; ++t)
235 }
236 
237 enum { UB_TIME_ITER = 0x1000000 };
238 
239 static void ub_time_round(int unused)
240 {
241  (void) m0_time_now();
242 }
243 
245  .us_name = "time-ub",
246  .us_init = NULL,
247  .us_fini = NULL,
248  .us_run = {
249  { .ub_name = "now",
250  .ub_iter = UB_TIME_ITER,
251  .ub_round = ub_time_round },
252  { .ub_name = NULL }
253  }
254 };
255 
256 /*
257  * Local variables:
258  * c-indentation-style: "K&R"
259  * c-basic-offset: 8
260  * tab-width: 8
261  * fill-column: 80
262  * scroll-step: 1
263  * End:
264  */
static void time_test_check(int64_t a, int64_t b, int64_t c)
Definition: time.c:150
int tt_thread_index
Definition: time.c:44
#define M0_PRE(cond)
#define NULL
Definition: misc.h:38
int m0_thread_join(struct m0_thread *q)
Definition: kthread.c:169
struct m0_semaphore tth_start
Definition: time.c:50
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
static void time_thread(int thread_index)
Definition: time.c:109
uint64_t m0_time_t
Definition: time.h:37
#define M0_LOG(level,...)
Definition: trace.h:167
static m0_time_t tv(int index)
Definition: time.c:129
struct m0_ub_set m0_time_ub
Definition: time.c:244
#define M0_THREAD_INIT(thread, TYPE, init, func, arg, namefmt,...)
Definition: thread.h:139
m0_time_t m0_time(uint64_t secs, long ns)
Definition: time.c:41
static void t2(int n)
Definition: thread.c:48
int i
Definition: dir.c:1033
void m0_ut_time_test(void)
Definition: time.c:228
#define max3(a, b, c)
Definition: arith.h:104
static void ub_time_round(int unused)
Definition: time.c:239
#define M0_ASSERT(cond)
const char * us_name
Definition: ub.h:76
m0_time_t m0_time_now(void)
Definition: time.c:134
static struct m0_addb2_callback c
Definition: consumer.c:41
static struct m0_thread t[8]
Definition: service_ut.c:1230
void m0_thread_fini(struct m0_thread *q)
Definition: thread.c:92
M0_INTERNAL int m0_semaphore_init(struct m0_semaphore *semaphore, unsigned value)
Definition: semaphore.c:38
static unsigned long err_nr
Definition: time.c:56
m0_time_t m0_time_add(const m0_time_t t1, const m0_time_t t2)
Definition: time.c:47
static int64_t m0_atomic64_get(const struct m0_atomic64 *a)
static void m0_mb(void)
static struct time_test time_values[TIME_VALUES_NR]
Definition: time.c:53
static m0_time_t tv_prev(int index)
Definition: time.c:135
M0_INTERNAL void m0_semaphore_fini(struct m0_semaphore *semaphore)
Definition: semaphore.c:45
int64_t tt_prev_index
Definition: time.c:45
m0_time_t m0_time_sub(const m0_time_t t1, const m0_time_t t2)
Definition: time.c:65
m0_time_t tt_now
Definition: time.c:43
static unsigned checked
Definition: storage.c:298
static struct m0_atomic64 time_index
Definition: time.c:55
static void t1(int n)
Definition: mutex.c:48
static void time_test_mt_nr(int threads_nr)
Definition: time.c:169
M0_INTERNAL void m0_semaphore_down(struct m0_semaphore *semaphore)
Definition: semaphore.c:49
M0_INTERNAL void m0_semaphore_up(struct m0_semaphore *semaphore)
Definition: semaphore.c:65
static m0_time_t err_max
Definition: time.c:57
static void t3(int n)
Definition: thread.c:59
struct m0_thread tth_thread
Definition: time.c:49
static void time_test_simple(void)
Definition: time.c:59
int32_t rc
Definition: trigger_fop.h:47
static struct time_test_thread time_threads[THREADS_NR_MAX]
Definition: time.c:54
Definition: ub.h:74
#define M0_UT_ASSERT(a)
Definition: ut.h:46
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)
Definition: time.c:42
int m0_nanosleep(const m0_time_t req, m0_time_t *rem)
Definition: ktime.c:73