blob: 22ea7f651f9f736fa51464b5a0b533ed68131333 [file] [log] [blame]
Neels Hofmeyr25c97412021-11-13 23:19:33 +01001/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
2 * All Rights Reserved
3 *
4 * Author: Neels Janosch Hofmeyr <nhofmeyr@sysmocom.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <inttypes.h>
22
23#include <osmocom/core/utils.h>
24#include <osmocom/core/rate_ctr.h>
25#include <osmocom/core/logging.h>
26#include <osmocom/core/application.h>
27#include <osmocom/core/select.h>
28#include <osmocom/core/tdef.h>
29#include <osmocom/core/time_cc.h>
30
31enum my_ctrs {
32 CTR_CEIL,
33 CTR_ROUND,
34 CTR_FLOOR,
35};
36
37const struct rate_ctr_desc my_ctr_desc[] = {
38 [CTR_CEIL] = {"ceil", "testing round_threshold_usec = 1"},
39 [CTR_ROUND] = {"round", "testing round_threshold_usec = 0 = gran_usec/2"},
40 [CTR_FLOOR] = {"floor", "testing round_threshold_usec = gran_usec"},
41};
42
43const struct rate_ctr_group_desc my_ctrg_desc = {
44 "time_cc_test",
45 "Counters for osmo_time_cc test",
46 0,
47 ARRAY_SIZE(my_ctr_desc),
48 my_ctr_desc,
49};
50
51struct rate_ctr_group *my_ctrg;
52
53
54enum my_obj_timers {
55 T_GRAN = -23,
56 T_ROUND_THRESH = -24,
57 T_FORGET_SUM = -25,
58};
59
60struct osmo_tdef g_my_obj_tdefs[] = {
61 { .T = T_GRAN, .default_val = 0, .unit = OSMO_TDEF_MS, .desc = "flag_cc granularity, or zero for 1 second" },
62 { .T = T_ROUND_THRESH, .default_val = 0, .unit = OSMO_TDEF_MS,
63 .desc = "flag_cc rounding threshold, or zero for half a granularity" },
64 { .T = T_FORGET_SUM, .default_val = 0, .unit = OSMO_TDEF_MS,
65 .desc = "flag_cc inactivity forget period, or zero to not forget any timings" },
66 {}
67};
68
69
70struct my_obj {
71 struct osmo_time_cc flag_cc_ceil;
72 struct osmo_time_cc flag_cc_round;
73 struct osmo_time_cc flag_cc_floor;
74};
75
76void my_obj_init(struct my_obj *my_obj)
77{
78 osmo_time_cc_init(&my_obj->flag_cc_ceil);
79 my_obj->flag_cc_ceil.cfg = (struct osmo_time_cc_cfg){
80 .rate_ctr = rate_ctr_group_get_ctr(my_ctrg, CTR_CEIL),
81 .round_threshold_usec = 1,
82 .T_gran = T_GRAN,
83 .T_forget_sum = T_FORGET_SUM,
84 .T_defs = g_my_obj_tdefs,
85 };
86
87 osmo_time_cc_init(&my_obj->flag_cc_round);
88 my_obj->flag_cc_round.cfg = (struct osmo_time_cc_cfg){
89 .rate_ctr = rate_ctr_group_get_ctr(my_ctrg, CTR_ROUND),
90 .T_gran = T_GRAN,
91 .T_round_threshold = T_ROUND_THRESH,
92 .T_forget_sum = T_FORGET_SUM,
93 .T_defs = g_my_obj_tdefs,
94 };
95
96 osmo_time_cc_init(&my_obj->flag_cc_floor);
97 my_obj->flag_cc_floor.cfg = (struct osmo_time_cc_cfg){
98 .rate_ctr = rate_ctr_group_get_ctr(my_ctrg, CTR_FLOOR),
99 .round_threshold_usec = UINT64_MAX, /* always >= gran_usec */
100 .T_gran = T_GRAN,
101 .T_forget_sum = T_FORGET_SUM,
102 .T_defs = g_my_obj_tdefs,
103 };
104}
105
106void my_obj_event(struct my_obj *my_obj, bool flag)
107{
108 osmo_time_cc_set_flag(&my_obj->flag_cc_ceil, flag);
109 osmo_time_cc_set_flag(&my_obj->flag_cc_round, flag);
110 osmo_time_cc_set_flag(&my_obj->flag_cc_floor, flag);
111}
112
113void my_obj_destruct(struct my_obj *my_obj)
114{
115 osmo_time_cc_cleanup(&my_obj->flag_cc_ceil);
116 osmo_time_cc_cleanup(&my_obj->flag_cc_round);
117 osmo_time_cc_cleanup(&my_obj->flag_cc_floor);
118}
119
120static const struct log_info_cat log_categories[] = {
121};
122
123static const struct log_info log_info = {
124 .cat = log_categories,
125 .num_cat = ARRAY_SIZE(log_categories),
126};
127
128int main()
129{
130 void *ctx = talloc_named_const(NULL, 0, "time_cc_test");
131 struct timespec *now;
132 struct my_obj my_obj = {0};
133
134 osmo_init_logging2(ctx, &log_info);
135
136 /* enable override for CLOCK_MONOTONIC */
137 osmo_clock_override_enable(CLOCK_MONOTONIC, true);
138 now = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
139 now->tv_sec = 23000;
140 now->tv_nsec = 0;
141
142 /* enable override for osmo_gettimeofday(), for osmo_timer_schedule() */
143 osmo_gettimeofday_override = true;
144 osmo_gettimeofday_override_time = (struct timeval){23000, 0};
145
146 my_ctrg = rate_ctr_group_alloc(ctx, &my_ctrg_desc, 0);
147
148#define CHECK_RATE_CTRS(exp_ceil, exp_round, exp_floor) do { \
149 printf("%d CHECK_RATE_CTRS(" #exp_ceil ", " #exp_round ", " #exp_floor ")", \
150 my_obj.flag_cc_round.flag_state); \
151 while (osmo_select_main_ctx(1) > 0); \
152 if (exp_ceil != my_obj.flag_cc_ceil.cfg.rate_ctr->current \
153 || exp_round != my_obj.flag_cc_round.cfg.rate_ctr->current \
154 || exp_floor != my_obj.flag_cc_floor.cfg.rate_ctr->current) \
155 printf("\n ERROR on line %d: ctr_ceil=%"PRIu64" ctr_round=%"PRIu64" ctr_floor=%"PRIu64"\n", \
156 __LINE__, \
157 my_obj.flag_cc_ceil.cfg.rate_ctr->current, \
158 my_obj.flag_cc_round.cfg.rate_ctr->current, \
159 my_obj.flag_cc_floor.cfg.rate_ctr->current); \
160 else \
161 printf(" ok\n"); \
162 } while (0)
163
164#define ADD_MILLISECS_NO_SELECT(ms) do { \
165 osmo_clock_override_add(CLOCK_MONOTONIC, ms / 1000, (uint64_t)(ms % 1000) * 1000000); \
166 osmo_gettimeofday_override_add(ms / 1000, (uint64_t)(ms % 1000) * 1000); \
167 printf("%d ADD_MILLISECS(" #ms ") --> %ld.%03ld", my_obj.flag_cc_round.flag_state, \
168 now->tv_sec, now->tv_nsec/1000000); \
169 printf("\n"); \
170 } while (0)
171
172#define ADD_MILLISECS(ms) do { \
173 ADD_MILLISECS_NO_SELECT(ms); \
174 while (osmo_select_main_ctx(1) > 0); \
175 } while (0)
176
177#define FLAG(VAL) do { \
178 printf(" flag: %s -> %s\n", my_obj.flag_cc_round.flag_state ? "TRUE" : "FALSE", VAL ? "TRUE" : "FALSE"); \
179 my_obj_event(&my_obj, VAL); \
180 } while (0)
181
182 /*
183 * sum ^
184 * | ________
185 * | /
186 * | /
187 * | /
188 * 3*gran --+--------------------------------------+
189 * | /:
190 * | / :
191 * | - - - - - - - - - - - - - - - - - / :
192 * | /. :
193 * | / . :
194 * 2*gran --+--------------------------------+ . :
195 * | /: . :
196 * | / : . :
197 * | - - - - - - - - - -_________/ : . :
198 * | / . : . :
199 * | / . : . :
200 * 1*gran --+-----------------+ . : . :
201 * | /: . : . :
202 * | / : . : . :
203 * | - - - - - - -/ : . : . :
204 * | /. : . : . :
205 * | ....-------' . : . : . :
206 * 0 +----------------------------------------------------------> elapsed time
207 * . : . : . :
208 * _ _ _______ ____________
209 * flag: __| |_| |____| . : |_______|. : . : |__________
210 * f t f t f t . : f t. : . : f
211 * round_threshold_usec : . : . : . :
212 * = 1 usec: 0 1 . :2 . :3 . :4 = "ceil()"
213 * = 0 == gran_usec/2: 0 1 : 2 : 3 : = "round()"
214 * = gran_usec: 0 1 2 3 = "floor()"
215 */
216
217 printf("\n----------- cumulating time, without forget_sum\n\n");
218
219 my_obj_init(&my_obj);
220 CHECK_RATE_CTRS(0, 0, 0);
221
222 ADD_MILLISECS(100);
223 CHECK_RATE_CTRS(0, 0, 0);
224
225 FLAG(true);
226 /* flag has just turned true the first time */
227 CHECK_RATE_CTRS(0, 0, 0);
228 ADD_MILLISECS(1);
229 /* flag has been true for 0.001s */
230 CHECK_RATE_CTRS(1, 0, 0);
231 ADD_MILLISECS(99);
232 /* flag has been true for 0.1s */
233 CHECK_RATE_CTRS(1, 0, 0);
234 FLAG(false);
235 CHECK_RATE_CTRS(1, 0, 0);
236
237 ADD_MILLISECS(100);
238
239 CHECK_RATE_CTRS(1, 0, 0);
240 FLAG(true);
241 CHECK_RATE_CTRS(1, 0, 0);
242 ADD_MILLISECS(100);
243 /* flag has been true for 0.2s */
244 CHECK_RATE_CTRS(1, 0, 0);
245 FLAG(false);
246 CHECK_RATE_CTRS(1, 0, 0);
247
248 ADD_MILLISECS(300);
249
250 CHECK_RATE_CTRS(1, 0, 0);
251 FLAG(true);
252 CHECK_RATE_CTRS(1, 0, 0);
253 ADD_MILLISECS(299);
254 /* flag has been true for 0.499s */
255 CHECK_RATE_CTRS(1, 0, 0);
256 ADD_MILLISECS(1);
257 /* flag has been true for 0.5s */
258 CHECK_RATE_CTRS(1, 1, 0);
259 ADD_MILLISECS(499);
260 /* flag has been true for 0.999s */
261 CHECK_RATE_CTRS(1, 1, 0);
262 ADD_MILLISECS(1);
263 /* flag has been true for 1.0s */
264 CHECK_RATE_CTRS(1, 1, 1);
265 ADD_MILLISECS(1);
266 /* flag has been true for 1.001s */
267 CHECK_RATE_CTRS(2, 1, 1);
268 ADD_MILLISECS(299);
269 /* flag has been true for 1.3s */
270 CHECK_RATE_CTRS(2, 1, 1);
271 FLAG(false);
272 CHECK_RATE_CTRS(2, 1, 1);
273
274 ADD_MILLISECS(400);
275
276 CHECK_RATE_CTRS(2, 1, 1);
277 FLAG(true);
278 CHECK_RATE_CTRS(2, 1, 1);
279 ADD_MILLISECS(199);
280 /* flag has been true for 1.499s */
281 CHECK_RATE_CTRS(2, 1, 1);
282 ADD_MILLISECS(2);
283 /* flag has been true for 1.501s */
284 CHECK_RATE_CTRS(2, 2, 1);
285 ADD_MILLISECS(498);
286 /* flag has been true for 1.999s */
287 CHECK_RATE_CTRS(2, 2, 1);
288 ADD_MILLISECS(2);
289 /* flag has been true for 2.001s */
290 CHECK_RATE_CTRS(3, 2, 2);
291 ADD_MILLISECS(500);
292 /* flag has been true for 2.501s */
293 CHECK_RATE_CTRS(3, 3, 2);
294 ADD_MILLISECS(498);
295 /* flag has been true for 2.999s */
296 CHECK_RATE_CTRS(3, 3, 2);
297 ADD_MILLISECS(3);
298 /* flag has been true for 3.003s */
299 CHECK_RATE_CTRS(4, 3, 3);
300 ADD_MILLISECS(200);
301 /* flag has been true for 3.203s */
302 CHECK_RATE_CTRS(4, 3, 3);
303 FLAG(false);
304 CHECK_RATE_CTRS(4, 3, 3);
305
306 ADD_MILLISECS(4321);
307 CHECK_RATE_CTRS(4, 3, 3);
308
309 FLAG(true);
310 CHECK_RATE_CTRS(4, 3, 3);
311 ADD_MILLISECS(5678);
312 CHECK_RATE_CTRS(9, 9, 8);
313 FLAG(false);
314 CHECK_RATE_CTRS(9, 9, 8);
315
316 my_obj_destruct(&my_obj);
317 rate_ctr_group_reset(my_ctrg);
318
319 printf("\n----------- test forget_sum_usec\n\n");
320 osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, 10, OSMO_TDEF_S);
321
322 now->tv_sec = 23000;
323 now->tv_nsec = 0;
324 osmo_gettimeofday_override_time = (struct timeval){23000, 0};
325
326 my_obj_init(&my_obj);
327
328 CHECK_RATE_CTRS(0, 0, 0);
329
330 FLAG(true);
331 /* flag has just turned true the first time */
332 CHECK_RATE_CTRS(0, 0, 0);
333 ADD_MILLISECS(100);
334 /* flag has been true for 0.1s */
335 CHECK_RATE_CTRS(1, 0, 0);
336 FLAG(false);
337 CHECK_RATE_CTRS(1, 0, 0);
338
339 ADD_MILLISECS(1000);
340 /* 1 s of being false, forget_sum_usec has not yet occurred */
341 CHECK_RATE_CTRS(1, 0, 0);
342
343 ADD_MILLISECS(8999);
344 /* 9.999 s of being false, forget_sum_usec has not yet occurred */
345 CHECK_RATE_CTRS(1, 0, 0);
346
347 ADD_MILLISECS(1);
348 /* 10 s of being false, forget_sum_usec has occurred */
349 CHECK_RATE_CTRS(1, 0, 0);
350
351 FLAG(true);
352 CHECK_RATE_CTRS(1, 0, 0);
353 ADD_MILLISECS(1);
354 /* Since previous sums were forgotton, ceil() triggers again */
355 CHECK_RATE_CTRS(2, 0, 0);
356 /* If the sum had not been forgotten, adding 400 ms to the initial 100 ms would have triggered round(). Verify
357 * that this does not occur, since now full 500 ms are required */
358 ADD_MILLISECS(399);
359 CHECK_RATE_CTRS(2, 0, 0);
360 /* Adding another 100 ms will trigger round() */
361 ADD_MILLISECS(99);
362 CHECK_RATE_CTRS(2, 0, 0);
363 ADD_MILLISECS(1);
364 CHECK_RATE_CTRS(2, 1, 0);
365 /* If the sum had not been forgotten, adding 900 ms to the initial 100 ms would have triggered floor(). Verify
366 * that this does not occur, since now full 1000 ms are required. We already added 500 ms above. */
367 ADD_MILLISECS(400);
368 CHECK_RATE_CTRS(2, 1, 0);
369 /* Adding another 100 ms will trigger floor() */
370 ADD_MILLISECS(99);
371 CHECK_RATE_CTRS(2, 1, 0);
372 ADD_MILLISECS(1);
373 CHECK_RATE_CTRS(2, 1, 1);
374
375 /* Test that durations of false below forget_sum_usec never trigger a forget */
376 ADD_MILLISECS(300);
377 CHECK_RATE_CTRS(3, 1, 1);
378 /* internal counter is now at 0.3s above the last reported rate counter */
379 FLAG(false);
380 ADD_MILLISECS(9999);
381 FLAG(true);
382 ADD_MILLISECS(25);
383 FLAG(false);
384 ADD_MILLISECS(9999);
385 FLAG(true);
386 ADD_MILLISECS(25);
387 FLAG(false);
388 ADD_MILLISECS(9999);
389 FLAG(true);
390 ADD_MILLISECS(25);
391 FLAG(false);
392 ADD_MILLISECS(9999);
393 FLAG(true);
394 ADD_MILLISECS(25);
395 /* internal counter is now at 0.4s above the last reported rate counter */
396 CHECK_RATE_CTRS(3, 1, 1);
397 ADD_MILLISECS(100);
398 CHECK_RATE_CTRS(3, 2, 1);
399 ADD_MILLISECS(500);
400 CHECK_RATE_CTRS(3, 2, 2);
401
402 /* Test that repeated osmo_time_cc_set_flag(false) does not cancel a forget_sum_usec */
403 ADD_MILLISECS(300);
404 /* internal counter is now at 0.3s above the last reported rate counter */
405 CHECK_RATE_CTRS(4, 2, 2);
406 FLAG(false);
407 ADD_MILLISECS(5000);
408 /* Repeat 'false', must not affect forget_sum_usec */
409 FLAG(false);
410 ADD_MILLISECS(5000);
411 CHECK_RATE_CTRS(4, 2, 2);
412 /* 10 s have passed, forget_sum_usec has occurred.
413 * Hence ceil() will trigger again right away: */
414 FLAG(true);
415 ADD_MILLISECS(1);
416 CHECK_RATE_CTRS(5, 2, 2);
417 /* Adding 200 ms to the initial 300 ms would have triggered round(), but no more after forget_sum_usec */
418 ADD_MILLISECS(199);
419 CHECK_RATE_CTRS(5, 2, 2);
420 /* Adding another 300 ms will trigger round() */
421 ADD_MILLISECS(299);
422 CHECK_RATE_CTRS(5, 2, 2);
423 ADD_MILLISECS(1);
424 CHECK_RATE_CTRS(5, 3, 2);
425 /* Adding 700 ms to the initial 300 ms would have triggered ceil(), but no more after forget_sum_usec */
426 ADD_MILLISECS(200);
427 CHECK_RATE_CTRS(5, 3, 2);
428 /* Adding another 300 ms will trigger ceil() */
429 ADD_MILLISECS(299);
430 CHECK_RATE_CTRS(5, 3, 2);
431 ADD_MILLISECS(1);
432 CHECK_RATE_CTRS(5, 3, 3);
433
434 my_obj_destruct(&my_obj);
435 rate_ctr_group_reset(my_ctrg);
436
437
438 /* Verify correctness when select() lags and runs timer callbacks too late */
439 printf("\n----------- cumulating time, without forget_sum, when timer cb are invoked late\n\n");
440 osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, 0, OSMO_TDEF_S);
441 now->tv_sec = 23000;
442 now->tv_nsec = 0;
443 osmo_gettimeofday_override_time = (struct timeval){23000, 0};
444
445 my_obj_init(&my_obj);
446 CHECK_RATE_CTRS(0, 0, 0);
447
448 ADD_MILLISECS_NO_SELECT(100);
449 CHECK_RATE_CTRS(0, 0, 0);
450
451 FLAG(true);
452 /* flag has just turned true the first time */
453 CHECK_RATE_CTRS(0, 0, 0);
454 ADD_MILLISECS_NO_SELECT(100);
455 /* flag has been true for 0.1s */
456 CHECK_RATE_CTRS(1, 0, 0);
457 FLAG(false);
458 CHECK_RATE_CTRS(1, 0, 0);
459
460 ADD_MILLISECS_NO_SELECT(100);
461
462 CHECK_RATE_CTRS(1, 0, 0);
463 FLAG(true);
464 CHECK_RATE_CTRS(1, 0, 0);
465 ADD_MILLISECS_NO_SELECT(100);
466 /* flag has been true for 0.2s */
467 CHECK_RATE_CTRS(1, 0, 0);
468 FLAG(false);
469 CHECK_RATE_CTRS(1, 0, 0);
470
471 ADD_MILLISECS_NO_SELECT(300);
472
473 CHECK_RATE_CTRS(1, 0, 0);
474 FLAG(true);
475 CHECK_RATE_CTRS(1, 0, 0);
476 ADD_MILLISECS_NO_SELECT(799);
477 /* flag has been true for 0.999s */
478 CHECK_RATE_CTRS(1, 1, 0);
479 ADD_MILLISECS_NO_SELECT(1);
480 /* flag has been true for 1.0s */
481 CHECK_RATE_CTRS(1, 1, 1);
482 ADD_MILLISECS_NO_SELECT(300);
483 /* flag has been true for 1.3s */
484 CHECK_RATE_CTRS(2, 1, 1);
485 FLAG(false);
486 CHECK_RATE_CTRS(2, 1, 1);
487
488 ADD_MILLISECS_NO_SELECT(400);
489
490 CHECK_RATE_CTRS(2, 1, 1);
491 FLAG(true);
492 CHECK_RATE_CTRS(2, 1, 1);
493 ADD_MILLISECS_NO_SELECT(699);
494 /* flag has been true for 1.999s */
495 CHECK_RATE_CTRS(2, 2, 1);
496 ADD_MILLISECS_NO_SELECT(1);
497 /* flag has been true for 2.0s */
498 CHECK_RATE_CTRS(2, 2, 2);
499 ADD_MILLISECS_NO_SELECT(1);
500 /* flag has been true for 2.001s */
501 CHECK_RATE_CTRS(3, 2, 2);
502 ADD_MILLISECS_NO_SELECT(499);
503 /* flag has been true for 2.5s */
504 CHECK_RATE_CTRS(3, 3, 2);
505 ADD_MILLISECS_NO_SELECT(499);
506 /* flag has been true for 2.999s */
507 CHECK_RATE_CTRS(3, 3, 2);
508 ADD_MILLISECS_NO_SELECT(1);
509 /* flag has been true for 3.0s */
510 CHECK_RATE_CTRS(3, 3, 3);
511 ADD_MILLISECS_NO_SELECT(200);
512 /* flag has been true for 3.2s */
513 CHECK_RATE_CTRS(4, 3, 3);
514 FLAG(false);
515 CHECK_RATE_CTRS(4, 3, 3);
516
517 ADD_MILLISECS_NO_SELECT(4321);
518 CHECK_RATE_CTRS(4, 3, 3);
519
520 FLAG(true);
521 CHECK_RATE_CTRS(4, 3, 3);
522 ADD_MILLISECS_NO_SELECT(5678);
523 CHECK_RATE_CTRS(9, 9, 8);
524 FLAG(false);
525 CHECK_RATE_CTRS(9, 9, 8);
526
527 my_obj_destruct(&my_obj);
528 rate_ctr_group_reset(my_ctrg);
529
530
531 printf("\n----------- test forget_sum, when timer cb are invoked late\n\n");
532 osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, 10, OSMO_TDEF_S);
533
534 now->tv_sec = 23000;
535 now->tv_nsec = 0;
536 osmo_gettimeofday_override_time = (struct timeval){23000, 0};
537
538 my_obj_init(&my_obj);
539
540 CHECK_RATE_CTRS(0, 0, 0);
541
542 FLAG(true);
543 /* flag has just turned true the first time */
544 CHECK_RATE_CTRS(0, 0, 0);
545 ADD_MILLISECS_NO_SELECT(100);
546 /* flag has been true for 0.1s */
547 CHECK_RATE_CTRS(1, 0, 0);
548 FLAG(false);
549 CHECK_RATE_CTRS(1, 0, 0);
550
551 ADD_MILLISECS_NO_SELECT(1000);
552 /* 1 s of being false, forget_sum_usec has not yet occurred */
553 CHECK_RATE_CTRS(1, 0, 0);
554
555 ADD_MILLISECS_NO_SELECT(8999);
556 /* 9.999 s of being false, forget_sum_usec has not yet occurred */
557 CHECK_RATE_CTRS(1, 0, 0);
558
559 ADD_MILLISECS_NO_SELECT(1);
560 /* 10 s of being false, forget_sum_usec has occurred */
561 CHECK_RATE_CTRS(1, 0, 0);
562
563 FLAG(true);
564 CHECK_RATE_CTRS(1, 0, 0);
565 ADD_MILLISECS_NO_SELECT(1);
566 /* Since previous sums were forgotton, ceil() triggers again */
567 CHECK_RATE_CTRS(2, 0, 0);
568 /* If the sum had not been forgotten, adding 400 ms to the initial 100 ms would have triggered round(). Verify
569 * that this does not occur, since now full 500 ms are required */
570 ADD_MILLISECS_NO_SELECT(399);
571 CHECK_RATE_CTRS(2, 0, 0);
572 /* Adding another 100 ms will trigger round() */
573 ADD_MILLISECS_NO_SELECT(99);
574 CHECK_RATE_CTRS(2, 0, 0);
575 ADD_MILLISECS_NO_SELECT(1);
576 CHECK_RATE_CTRS(2, 1, 0);
577 /* If the sum had not been forgotten, adding 900 ms to the initial 100 ms would have triggered floor(). Verify
578 * that this does not occur, since now full 1000 ms are required. We already added 500 ms above. */
579 ADD_MILLISECS_NO_SELECT(400);
580 CHECK_RATE_CTRS(2, 1, 0);
581 /* Adding another 100 ms will trigger floor() */
582 ADD_MILLISECS_NO_SELECT(99);
583 CHECK_RATE_CTRS(2, 1, 0);
584 ADD_MILLISECS_NO_SELECT(1);
585 CHECK_RATE_CTRS(2, 1, 1);
586
587 /* Test that durations of false below forget_sum_usec never trigger a forget */
588 ADD_MILLISECS_NO_SELECT(300);
589 CHECK_RATE_CTRS(3, 1, 1);
590 /* internal counter is now at 0.3s above the last reported rate counter */
591 FLAG(false);
592 ADD_MILLISECS_NO_SELECT(9999);
593 FLAG(true);
594 ADD_MILLISECS_NO_SELECT(25);
595 FLAG(false);
596 ADD_MILLISECS_NO_SELECT(9999);
597 FLAG(true);
598 ADD_MILLISECS_NO_SELECT(25);
599 FLAG(false);
600 ADD_MILLISECS_NO_SELECT(9999);
601 FLAG(true);
602 ADD_MILLISECS_NO_SELECT(25);
603 FLAG(false);
604 ADD_MILLISECS_NO_SELECT(9999);
605 FLAG(true);
606 ADD_MILLISECS_NO_SELECT(25);
607 /* internal counter is now at 0.4s above the last reported rate counter */
608 CHECK_RATE_CTRS(3, 1, 1);
609 ADD_MILLISECS_NO_SELECT(100);
610 CHECK_RATE_CTRS(3, 2, 1);
611 ADD_MILLISECS_NO_SELECT(500);
612 CHECK_RATE_CTRS(3, 2, 2);
613
614 my_obj_destruct(&my_obj);
615 rate_ctr_group_reset(my_ctrg);
616
617
618#define SET_TDEFS(gran, round_thresh, forget_sum) do { \
619 osmo_tdef_set(g_my_obj_tdefs, T_GRAN, gran, OSMO_TDEF_MS); \
620 osmo_tdef_set(g_my_obj_tdefs, T_ROUND_THRESH, round_thresh, OSMO_TDEF_MS); \
621 osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, forget_sum, OSMO_TDEF_S); \
622 printf("T_defs: T_gran=%luusec T_round_threshold=%luusec T_forget_sum=%luusec\n", \
623 osmo_tdef_get(g_my_obj_tdefs, T_GRAN, OSMO_TDEF_US, -1), \
624 osmo_tdef_get(g_my_obj_tdefs, T_ROUND_THRESH, OSMO_TDEF_US, -1), \
625 osmo_tdef_get(g_my_obj_tdefs, T_FORGET_SUM, OSMO_TDEF_US, -1)); \
626 } while (0)
627
628 printf("\n----------- test T_defs\n\n");
629 now->tv_sec = 23000;
630 now->tv_nsec = 0;
631 osmo_gettimeofday_override_time = (struct timeval){23000, 0};
632
633 SET_TDEFS(100, 10, 0);
634
635 my_obj_init(&my_obj);
636 CHECK_RATE_CTRS(0, 0, 0);
637
638 ADD_MILLISECS(100);
639 CHECK_RATE_CTRS(0, 0, 0);
640
641 FLAG(true);
642 /* flag has just turned true the first time */
643 CHECK_RATE_CTRS(0, 0, 0);
644 ADD_MILLISECS(9);
645 /* flag has been true for 0.009s */
646 CHECK_RATE_CTRS(1, 0, 0);
647 ADD_MILLISECS(1);
648 /* flag has been true for 0.010s */
649 CHECK_RATE_CTRS(1, 1, 0);
650 ADD_MILLISECS(90);
651 /* flag has been true for 0.1s */
652 CHECK_RATE_CTRS(1, 1, 1);
653
654 SET_TDEFS(200, 190, 1);
655 /* gran is changed to 200ms, but still continues until the next scheduled event until the change is picked up.
656 * For ceil(), it is 1 ms ahead.
657 * For round(), it is 10 ms ahead.
658 * For floor(), it is at the next full (previous) gran 100 ms ahead.
659 * When T_defs change, all internal sums are reset to zero without reporting.
660 */
661 CHECK_RATE_CTRS(1, 1, 1);
662 ADD_MILLISECS(1);
663 /* 1ms elapsed: ceil() picks up the T_gran change, starts anew. */
664 /* elapsed: ceil 0 ms */
665 CHECK_RATE_CTRS(1, 1, 1);
666 ADD_MILLISECS(1);
667 /* elapsed: ceil 1 ms */
668 /* ceil() increments because flag has been true for more than 1 us after reset */
669 CHECK_RATE_CTRS(2, 1, 1);
670 ADD_MILLISECS(8);
671 /* 10 ms elapsed: round() picks up the T_gran change, starts anew */
672 /* elapsed: ceil 9 ms, round 0 ms */
673 CHECK_RATE_CTRS(2, 1, 1);
674 ADD_MILLISECS(90);
675 /* 100 ms elapsed: floor() picks up the T_gran change, starts anew */
676 /* elapsed: ceil 99 ms, round 90 ms, floor 0 ms */
677 CHECK_RATE_CTRS(2, 1, 1);
678 ADD_MILLISECS(99);
679 /* elapsed: ceil 198 ms, round 189 ms, floor 99 ms */
680 CHECK_RATE_CTRS(2, 1, 1);
681 ADD_MILLISECS(1);
682 /* elapsed: ceil 199 ms, round 190 ms, floor 100 ms */
683 CHECK_RATE_CTRS(2, 2, 1);
684 ADD_MILLISECS(1);
685 /* elapsed: ceil 200 ms, round 191 ms, floor 101 ms */
686 CHECK_RATE_CTRS(2, 2, 1);
687 ADD_MILLISECS(1);
688 /* elapsed: ceil 201 ms, round 192 ms, floor 102 ms */
689 CHECK_RATE_CTRS(3, 2, 1);
690 ADD_MILLISECS(98);
691 /* elapsed: ceil 299 ms, round 290 ms, floor 200 ms */
692 CHECK_RATE_CTRS(3, 2, 2);
693 ADD_MILLISECS(99);
694 /* elapsed: ceil 398 ms, round 389 ms, floor 299 ms */
695 CHECK_RATE_CTRS(3, 2, 2);
696 ADD_MILLISECS(1);
697 /* elapsed: ceil 399 ms, round 390 ms, floor 300 ms */
698 CHECK_RATE_CTRS(3, 3, 2);
699 ADD_MILLISECS(1);
700 /* elapsed: ceil 400 ms, round 391 ms, floor 301 ms */
701 CHECK_RATE_CTRS(3, 3, 2);
702 ADD_MILLISECS(1);
703 /* elapsed: ceil 401 ms, round 392 ms, floor 302 ms */
704 CHECK_RATE_CTRS(4, 3, 2);
705 ADD_MILLISECS(98);
706 /* elapsed: ceil 499 ms, round 490 ms, floor 400 ms */
707 CHECK_RATE_CTRS(4, 3, 3);
708
709
710 SET_TDEFS(100, 0, 0);
711 /* T_defs change, but they only get picked up upon the next event:
712 * For ceil(), it is 102 ms ahead.
713 * For round(), it is 100 ms ahead (thresh is still 190, currently at 90).
714 * For floor(), it is 200 ms ahead.
715 * When T_defs change, all internal sums are reset to zero without reporting.
716 */
717 CHECK_RATE_CTRS(4, 3, 3);
718 ADD_MILLISECS(100);
719 CHECK_RATE_CTRS(4, 3, 3);
720 /* round() picks up the new T_defs. Internal sum resets, nothing else happens yet.
721 * round() schedules the next event 50 ms ahead. */
722 ADD_MILLISECS(2);
723 CHECK_RATE_CTRS(4, 3, 3);
724 /* ceil() picks up the change, its next event is 1 ms ahead. */
725 ADD_MILLISECS(1);
726 /* ceil: 0.001
727 * round: 0.003
728 * floor: still 97 ms until it picks up the change */
729 CHECK_RATE_CTRS(5, 3, 3);
730 ADD_MILLISECS(46);
731 CHECK_RATE_CTRS(5, 3, 3);
732 ADD_MILLISECS(1);
733 /* round() has first counter trigger after T_defs change. */
734 CHECK_RATE_CTRS(5, 4, 3);
735 /* ceil: 0.048
736 * round: 0.050
737 * floor: still 50 ms until it picks up the change */
738 ADD_MILLISECS(50);
739 /* floor() picks up the change. nothing happens yet. */
740 /* ceil: 0.098
741 * round: 0.100
742 * floor: 0.0 */
743 ADD_MILLISECS(2);
744 /* ceil: 0.100
745 * round: 0.102
746 * floor: 0.002 */
747 CHECK_RATE_CTRS(5, 4, 3);
748 ADD_MILLISECS(1);
749 /* ceil: 0.101
750 * round: 0.103
751 * floor: 0.003 */
752 CHECK_RATE_CTRS(6, 4, 3);
753 ADD_MILLISECS(46);
754 /* ceil: 0.147
755 * round: 0.149
756 * floor: 0.049 */
757 CHECK_RATE_CTRS(6, 4, 3);
758 ADD_MILLISECS(1);
759 /* ceil: 0.148
760 * round: 0.150
761 * floor: 0.050 */
762 CHECK_RATE_CTRS(6, 5, 3);
763
764 my_obj_destruct(&my_obj);
765 rate_ctr_group_reset(my_ctrg);
766
767 return 0;
768}