<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/26230">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add osmo_time_cc, moved from osmo-bsc<br><br>Related: SYS#4878<br>Related: Ica9f908a1a30f334a24c59471affa11225117e12 (osmo-bsc)<br>Change-Id: Iabb17a08e6e1a86f168cdb008fba05ecd4776bdd<br>---<br>M include/Makefile.am<br>A include/osmocom/core/time_cc.h<br>M src/Makefile.am<br>A src/time_cc.c<br>M tests/Makefile.am<br>M tests/testsuite.at<br>A tests/time_cc/time_cc_test.c<br>A tests/time_cc/time_cc_test.ok<br>8 files changed, 1,523 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/30/26230/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/Makefile.am b/include/Makefile.am</span><br><span>index 49402d0..e3246cf 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -60,6 +60,7 @@</span><br><span>                        osmocom/core/utils.h \</span><br><span>                        osmocom/core/write_queue.h \</span><br><span>                        osmocom/core/sockaddr_str.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/core/time_cc.h \</span><br><span>                        osmocom/core/use_count.h \</span><br><span>                        osmocom/crypt/auth.h \</span><br><span>                        osmocom/crypt/gprs_cipher.h \</span><br><span>diff --git a/include/osmocom/core/time_cc.h b/include/osmocom/core/time_cc.h</span><br><span>new file mode 100644</span><br><span>index 0000000..36fdee4</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/core/time_cc.h</span><br><span>@@ -0,0 +1,187 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file time_cc.h</span><br><span style="color: hsl(120, 100%, 40%);">+ * Report the cumulative counter of time for which a flag is true as rate counter.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+/* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \defgroup time_cc  Cumulative counter of time as rate counter.</span><br><span style="color: hsl(120, 100%, 40%);">+ * @{</span><br><span style="color: hsl(120, 100%, 40%);">+ * \file time_cc.h</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_tdef;</span><br><span style="color: hsl(120, 100%, 40%);">+struct rate_ctr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Configuration for osmo_time_cc.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Report the cumulative counter of time for which a flag is true as rate counter.</span><br><span style="color: hsl(120, 100%, 40%);">+ * For example, for each second that the flag is true, increment a rate counter.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The flag to be monitored is reported by osmo_time_cc_set_flag().</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The granularity defines how much time one rate counter increment represents:</span><br><span style="color: hsl(120, 100%, 40%);">+ * the default configuration is gran_usec = 1000000, i.e. one rate counter increment represents one second.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Reporting as rate counter is configurable by round_threshold_usec and forget_sum_usec, examples:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * round_threshold_usec:</span><br><span style="color: hsl(120, 100%, 40%);">+ * - To get "ceil()" behavior, set round_threshold_usec = 1. This increments the rate counter for each gran_usec period</span><br><span style="color: hsl(120, 100%, 40%);">+ *   where the flag was seen true, even if it was true for only a very short fraction of a gran_usec period.</span><br><span style="color: hsl(120, 100%, 40%);">+ * - To get "round()" behavior, set round_threshold_usec = half of gran_usec. The rate counter increments when the flag</span><br><span style="color: hsl(120, 100%, 40%);">+ *   has been true for 0.5 of a gran_usec (and then again at 1.5 * gran_usec) of 'true' flag. round_threshold_usec = 0</span><br><span style="color: hsl(120, 100%, 40%);">+ *   is a special value that means to use half of gran_usec.</span><br><span style="color: hsl(120, 100%, 40%);">+ * - To get "floor()" behavior, set round_threshold_usec >= gran_usec. The rate counter increments when reaching full</span><br><span style="color: hsl(120, 100%, 40%);">+ *   gran_usec periods of the flag being true.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * forget_sum_usec:</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is a tradeoff between the accuracy of the reported rate counter and making sure that the events reported are not</span><br><span style="color: hsl(120, 100%, 40%);">+ * irrelevantly long ago.</span><br><span style="color: hsl(120, 100%, 40%);">+ * - To keep sub-granularity-period surplus time forever, set forget_sum_usec = 0.</span><br><span style="color: hsl(120, 100%, 40%);">+ * - To keep surplus time for up to a minute, set forget_sum_usec = 60000000 (60 seconds).</span><br><span style="color: hsl(120, 100%, 40%);">+ * - To get rid of "leftover" time (almost) immediately after the flag goes false, set forget_sum_usec = 1.</span><br><span style="color: hsl(120, 100%, 40%);">+ * - If gran_usec is set to one second and forget_sum_usec is set to one minute, the reported rate counter has a</span><br><span style="color: hsl(120, 100%, 40%);">+ *   possible inaccuracy of 1/60th, but makes sure that no timings older than a minute affect the current reports.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Reporting modes in detail:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The rate_ctr increments when the cumulative counter passes round_threshold_usec (default: half of gran_usec).</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *                        sum ^</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                                          ________</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                                         /</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                                        /</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                                       /</span><br><span style="color: hsl(120, 100%, 40%);">+ *                   3*gran --+--------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                                     /:</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                                    / :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            | - - - - - - - - - - - - - - - - - /  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                                  /.  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                                 / .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                   2*gran --+--------------------------------+  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                               /:  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                              / :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            | - - - - - - - - - -_________/  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                   /         .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                  /          .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                   1*gran --+-----------------+           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |                /:           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |               / :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            | - - - - - - -/  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            |             /.  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            | ....-------' .  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                         0  +------------------------------------------------------------------------> elapsed time</span><br><span style="color: hsl(120, 100%, 40%);">+ *                                           .  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                               _   _      _______         ____________</span><br><span style="color: hsl(120, 100%, 40%);">+ *                   flag:    __| |_| |____| .  :  |_______|.  :  .  :  |__________</span><br><span style="color: hsl(120, 100%, 40%);">+ *                            f t f t f    t .  :  f       t.  :  .  :  f</span><br><span style="color: hsl(120, 100%, 40%);">+ *   round_threshold_usec       :            .  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 = 1 usec:  0  1           .  :2          .  :3 .  :4  = "ceil()"</span><br><span style="color: hsl(120, 100%, 40%);">+ *       = 0 == gran_usec/2:  0              1  :           2  :  3  :   = "round()"</span><br><span style="color: hsl(120, 100%, 40%);">+ *             >= gran_usec:  0                 1              2     3   = "floor()"</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_time_cc_cfg {</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! Granularity in microseconds: nr of microseconds that one rate_ctr increment represents. A typical value is</span><br><span style="color: hsl(120, 100%, 40%);">+         * gran_usec = 1000000, meaning one rate counter increment represents one second. When zero, use 1000000. */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint64_t gran_usec;</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! Nr of microseconds above n * gran_usec at which to trigger a counter increment. When zero, use half a</span><br><span style="color: hsl(120, 100%, 40%);">+      * gran_usec. */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint64_t round_threshold_usec;</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! Forget counted sub-gran time after the flag was false for this long. */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint64_t forget_sum_usec;</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! Rate counter to report to, or NULL to not use it. */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct rate_ctr *rate_ctr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Update gran_usec from this T timer value, or zero to not use any T timer. */</span><br><span style="color: hsl(120, 100%, 40%);">+      int T_gran;</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! Update round_threshold_usec from this T timer value, or zero to not use any T timer. */</span><br><span style="color: hsl(120, 100%, 40%);">+   int T_round_threshold;</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! Update forget_sum_usec from this T timer value, or zero to not use any T timer. */</span><br><span style="color: hsl(120, 100%, 40%);">+        int T_forget_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! Look up T_gran and T_forget_sum in this list of timers, or NULL to not use any T timers. */</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_tdef *T_defs;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Report the cumulative counter of time for which a flag is true as rate counter.</span><br><span style="color: hsl(120, 100%, 40%);">+ * See also osmo_time_cc_cfg for details on configuring.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Usage:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *     struct my_obj {</span><br><span style="color: hsl(120, 100%, 40%);">+ *             struct osmo_time_cc flag_cc;</span><br><span style="color: hsl(120, 100%, 40%);">+ *     };</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *     void my_obj_init(struct my_obj *my_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+ *     {</span><br><span style="color: hsl(120, 100%, 40%);">+ *             osmo_time_cc_init(&my_obj->flag_cc);</span><br><span style="color: hsl(120, 100%, 40%);">+ *             my_obj->flag_cc.cfg = (struct osmo_time_cc_cfg){</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             .gran_usec = 1000000,</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             .forget_sum_usec = 60000000,</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             .rate_ctr = rate_ctr_group_get_ctr(my_ctrg, MY_CTR_IDX),</span><br><span style="color: hsl(120, 100%, 40%);">+ *                     };</span><br><span style="color: hsl(120, 100%, 40%);">+ *             // optional: set initial flag state, default is 'false':</span><br><span style="color: hsl(120, 100%, 40%);">+ *             // osmo_time_cc_set_flag(&my_obj->flag_cc, false);</span><br><span style="color: hsl(120, 100%, 40%);">+ *     }</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *     void my_obj_event(struct my_obj *my_obj, bool flag)</span><br><span style="color: hsl(120, 100%, 40%);">+ *     {</span><br><span style="color: hsl(120, 100%, 40%);">+ *             osmo_time_cc_set_flag(&my_obj->flag_cc, flag);</span><br><span style="color: hsl(120, 100%, 40%);">+ *     }</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *     void my_obj_destruct(struct my_obj *my_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+ *     {</span><br><span style="color: hsl(120, 100%, 40%);">+ *             osmo_time_cc_cleanup(&my_obj->flag_cc);</span><br><span style="color: hsl(120, 100%, 40%);">+ *     }</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_time_cc {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_time_cc_cfg cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        bool flag_state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! Overall cumulative sum. Does not get reset for the entire lifetime of an osmo_time_cc.</span><br><span style="color: hsl(120, 100%, 40%);">+     * (Informational only, not used by the osmo_time_cc implementation.) */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint64_t total_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_timer_list timer;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! CLOCK_MONOTONIC reading in microseconds, at the time when the osmo_time_cc instance started counting. */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint64_t start_time;</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! CLOCK_MONOTONIC reading in microseconds, at the time when the osmo_time_cc last evaluated the flag state and</span><br><span style="color: hsl(120, 100%, 40%);">+       * possibly added to the cumulated sum. */</span><br><span style="color: hsl(120, 100%, 40%);">+    uint64_t last_counted_time;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Internal cumulative counter of time that flag_state was true. It may get reset to zero regularly, depending</span><br><span style="color: hsl(120, 100%, 40%);">+        * on cfg.forget_sum_usec. This is the basis for incrementing cfg.rate_ctr. */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint64_t sum;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The amount of time that already reported cfg.rate_ctr increments account for. This may be ahead of or behind</span><br><span style="color: hsl(120, 100%, 40%);">+       * 'sum', depending on cfg.round_threshold_usec. */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint64_t reported_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_time_cc_init(struct osmo_time_cc *tc);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_time_cc_set_flag(struct osmo_time_cc *tc, bool flag);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_time_cc_cleanup(struct osmo_time_cc *tc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! @} */</span><br><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index 328d2c7..6875aa5 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -26,6 +26,7 @@</span><br><span>                        isdnhdlc.c \</span><br><span>                         tdef.c \</span><br><span>                     thread.c \</span><br><span style="color: hsl(120, 100%, 40%);">+                    time_cc.c \</span><br><span>                          sockaddr_str.c \</span><br><span>                     use_count.c \</span><br><span>                        exec.c \</span><br><span>diff --git a/src/time_cc.c b/src/time_cc.c</span><br><span>new file mode 100644</span><br><span>index 0000000..72e3892</span><br><span>--- /dev/null</span><br><span>+++ b/src/time_cc.c</span><br><span>@@ -0,0 +1,225 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file foo.c</span><br><span style="color: hsl(120, 100%, 40%);">+ * Report the cumulative counter of time for which a flag is true as rate counter.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+/* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \addtogroup time_cc</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Report the cumulative counter of time for which a flag is true as rate counter.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Useful for reporting cumulative time counters as defined in 3GPP TS 52.402, for example allAvailableSDCCHAllocated,</span><br><span style="color: hsl(120, 100%, 40%);">+ * allAvailableTCHAllocated, availablePDCHAllocatedTime.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * For a usage example, see the description of struct osmo_time_cc.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @{</span><br><span style="color: hsl(120, 100%, 40%);">+ * \file time_cc.c</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <limits.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/time_cc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define GRAN_USEC(TIME_CC) ((TIME_CC)->cfg.gran_usec ? : 1000000)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ROUND_THRESHOLD_USEC(TIME_CC) ((TIME_CC)->cfg.round_threshold_usec ? \</span><br><span style="color: hsl(120, 100%, 40%);">+                                      OSMO_MIN((TIME_CC)->cfg.round_threshold_usec, GRAN_USEC(TIME_CC)) \</span><br><span style="color: hsl(120, 100%, 40%);">+                                        : (GRAN_USEC(TIME_CC) / 2))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static uint64_t time_now_usec()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct timespec tp;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_clock_gettime(CLOCK_MONOTONIC, &tp))</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     return (uint64_t)tp.tv_sec * 1000000 + tp.tv_nsec / 1000;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_time_cc_forget_sum(struct osmo_time_cc *tc, uint64_t now);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_time_cc_update_from_tdef(struct osmo_time_cc *tc, uint64_t now)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    bool do_forget_sum = false;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!tc->cfg.T_defs)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (tc->cfg.T_gran) {</span><br><span style="color: hsl(120, 100%, 40%);">+              uint64_t was = GRAN_USEC(tc);</span><br><span style="color: hsl(120, 100%, 40%);">+         tc->cfg.gran_usec = osmo_tdef_get(tc->cfg.T_defs, tc->cfg.T_gran, OSMO_TDEF_US, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (was != GRAN_USEC(tc))</span><br><span style="color: hsl(120, 100%, 40%);">+                     do_forget_sum = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tc->cfg.T_round_threshold)</span><br><span style="color: hsl(120, 100%, 40%);">+             tc->cfg.round_threshold_usec = osmo_tdef_get(tc->cfg.T_defs, tc->cfg.T_round_threshold,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                           OSMO_TDEF_US, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (tc->cfg.T_forget_sum) {</span><br><span style="color: hsl(120, 100%, 40%);">+                uint64_t was = tc->cfg.forget_sum_usec;</span><br><span style="color: hsl(120, 100%, 40%);">+            tc->cfg.forget_sum_usec = osmo_tdef_get(tc->cfg.T_defs, tc->cfg.T_forget_sum, OSMO_TDEF_US, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (tc->cfg.forget_sum_usec && was != tc->cfg.forget_sum_usec)</span><br><span style="color: hsl(120, 100%, 40%);">+                  do_forget_sum = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (do_forget_sum && tc->sum)</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_time_cc_forget_sum(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_time_cc_schedule_timer(struct osmo_time_cc *tc, uint64_t now);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Clear out osmo_timer and internal counting state of struct osmo_time_cc. The .cfg remains unaffected. After calling,</span><br><span style="color: hsl(120, 100%, 40%);">+ * the osmo_time_cc instance can be used again to accumulate state as if it had just been initialized. */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_time_cc_cleanup(struct osmo_time_cc *tc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_del(&tc->timer);</span><br><span style="color: hsl(120, 100%, 40%);">+    *tc = (struct osmo_time_cc){</span><br><span style="color: hsl(120, 100%, 40%);">+          .cfg = tc->cfg,</span><br><span style="color: hsl(120, 100%, 40%);">+    };</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_time_cc_start(struct osmo_time_cc *tc, uint64_t now)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_time_cc_cleanup(tc);</span><br><span style="color: hsl(120, 100%, 40%);">+     tc->start_time = now;</span><br><span style="color: hsl(120, 100%, 40%);">+      tc->last_counted_time = now;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_time_cc_update_from_tdef(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_time_cc_schedule_timer(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_time_cc_count_time(struct osmo_time_cc *tc, uint64_t now)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uint64_t time_delta;</span><br><span style="color: hsl(120, 100%, 40%);">+  tc->last_counted_time = now;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!tc->flag_state)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Flag is currently true, cumulate the elapsed time */</span><br><span style="color: hsl(120, 100%, 40%);">+       time_delta = now - tc->last_counted_time;</span><br><span style="color: hsl(120, 100%, 40%);">+  tc->total_sum += time_delta;</span><br><span style="color: hsl(120, 100%, 40%);">+       tc->sum += time_delta;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_time_cc_report(struct osmo_time_cc *tc, uint64_t now)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uint64_t delta;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint64_t n;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!tc->cfg.rate_ctr)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* We report a sum "rounded up", ahead of time. If the granularity period has not yet elapsed after the last</span><br><span style="color: hsl(120, 100%, 40%);">+         * reporting, do not report again yet. */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tc->reported_sum > tc->sum)</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       delta = tc->sum - tc->reported_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* elapsed full periods */</span><br><span style="color: hsl(120, 100%, 40%);">+    n = delta / GRAN_USEC(tc);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* If the delta has passed round_threshold (normally half of gran_usec), increment. */</span><br><span style="color: hsl(120, 100%, 40%);">+        delta -= n * GRAN_USEC(tc);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (delta >= ROUND_THRESHOLD_USEC(tc))</span><br><span style="color: hsl(120, 100%, 40%);">+             n++;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!n)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* integer sanity, since rate_ctr_add() takes an int argument. */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (n > INT_MAX)</span><br><span style="color: hsl(120, 100%, 40%);">+           n = INT_MAX;</span><br><span style="color: hsl(120, 100%, 40%);">+  rate_ctr_add(tc->cfg.rate_ctr, n);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Store the increments of gran_usec that were counted. */</span><br><span style="color: hsl(120, 100%, 40%);">+    tc->reported_sum += n * GRAN_USEC(tc);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_time_cc_forget_sum(struct osmo_time_cc *tc, uint64_t now)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ tc->reported_sum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      tc->sum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tc->last_counted_time < now)</span><br><span style="color: hsl(120, 100%, 40%);">+                tc->last_counted_time = now;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Initialize struct osmo_time_cc. Call this once before use, and before setting up the .cfg items. */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_time_cc_init(struct osmo_time_cc *tc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     *tc = (struct osmo_time_cc){0};</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Report state to be recorded by osmo_time_cc instance. Setting an unchanged state repeatedly has no effect. */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_time_cc_set_flag(struct osmo_time_cc *tc, bool flag)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    uint64_t now = time_now_usec();</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!tc->start_time)</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_time_cc_start(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+  /* No flag change == no effect */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (flag == tc->flag_state)</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Sum up elapsed time, report increments for that. */</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_time_cc_count_time(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_time_cc_report(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+ tc->flag_state = flag;</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_time_cc_schedule_timer(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_time_cc_timer_cb(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_time_cc *tc = data;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint64_t now = time_now_usec();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_time_cc_update_from_tdef(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tc->flag_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_time_cc_count_time(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_time_cc_report(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (tc->cfg.forget_sum_usec && tc->sum</span><br><span style="color: hsl(120, 100%, 40%);">+              && (now >= tc->last_counted_time + tc->cfg.forget_sum_usec)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_time_cc_forget_sum(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_time_cc_schedule_timer(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Figure out the next time we should do anything, if the flag state remains unchanged. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_time_cc_schedule_timer(struct osmo_time_cc *tc, uint64_t now)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    uint64_t next_event = UINT64_MAX;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_time_cc_update_from_tdef(tc, now);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* If it is required, when will the next forget_sum happen? */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (tc->cfg.forget_sum_usec && !tc->flag_state && tc->sum > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          uint64_t next_forget_time = tc->last_counted_time + tc->cfg.forget_sum_usec;</span><br><span style="color: hsl(120, 100%, 40%);">+            next_event = OSMO_MIN(next_event, next_forget_time);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Next rate_ctr increment? */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (tc->flag_state && tc->cfg.rate_ctr) {</span><br><span style="color: hsl(120, 100%, 40%);">+               uint64_t next_inc = now + (tc->reported_sum - tc->sum) + ROUND_THRESHOLD_USEC(tc);</span><br><span style="color: hsl(120, 100%, 40%);">+              next_event = OSMO_MIN(next_event, next_inc);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* No event coming up? */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (next_event == UINT64_MAX)</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (next_event <= now)</span><br><span style="color: hsl(120, 100%, 40%);">+             next_event = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          next_event -= now;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_timer_setup(&tc->timer, osmo_time_cc_timer_cb, tc);</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_timer_del(&tc->timer);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_timer_schedule(&tc->timer, next_event / 1000000, next_event % 1000000);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! @} */</span><br><span>diff --git a/tests/Makefile.am b/tests/Makefile.am</span><br><span>index b72619f..5201056 100644</span><br><span>--- a/tests/Makefile.am</span><br><span>+++ b/tests/Makefile.am</span><br><span>@@ -42,6 +42,7 @@</span><br><span>              bsslap/bsslap_test                                     \</span><br><span>             bssmap_le/bssmap_le_test                               \</span><br><span>             it_q/it_q_test                                         \</span><br><span style="color: hsl(120, 100%, 40%);">+              time_cc/time_cc_test                                   \</span><br><span>             gsm48/rest_octets_test                                 \</span><br><span>             base64/base64_test                                     \</span><br><span>             $(NULL)</span><br><span>@@ -324,6 +325,9 @@</span><br><span> it_q_it_q_test_SOURCES = it_q/it_q_test.c</span><br><span> it_q_it_q_test_LDADD = $(LDADD)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+time_cc_time_cc_test_SOURCES = time_cc/time_cc_test.c</span><br><span style="color: hsl(120, 100%, 40%);">+time_cc_time_cc_test_LDADD = $(LDADD)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # The `:;' works around a Bash 3.2 bug when the output is not writeable.</span><br><span> $(srcdir)/package.m4: $(top_srcdir)/configure.ac</span><br><span>       :;{ \</span><br><span>@@ -413,6 +417,7 @@</span><br><span>       bsslap/bsslap_test.ok \</span><br><span>              bssmap_le/bssmap_le_test.ok \</span><br><span>        it_q/it_q_test.ok \</span><br><span style="color: hsl(120, 100%, 40%);">+           time_cc/time_cc.ok \</span><br><span>         gsm48/rest_octets_test.ok \</span><br><span>          base64/base64_test.ok \</span><br><span>              $(NULL)</span><br><span>@@ -609,6 +614,8 @@</span><br><span>           >$(srcdir)/bssmap_le/bssmap_le_test.ok</span><br><span>    it_q/it_q_test \</span><br><span>             >$(srcdir)/it_q/it_q_test.ok</span><br><span style="color: hsl(120, 100%, 40%);">+       time_cc/time_cc_test \</span><br><span style="color: hsl(120, 100%, 40%);">+                >$(srcdir)/time_cc/time_cc_test.ok</span><br><span> </span><br><span> check-local: atconfig $(TESTSUITE)</span><br><span>      [ -e /proc/cpuinfo ] && cat /proc/cpuinfo</span><br><span>diff --git a/tests/testsuite.at b/tests/testsuite.at</span><br><span>index 6ac5970..975b51e 100644</span><br><span>--- a/tests/testsuite.at</span><br><span>+++ b/tests/testsuite.at</span><br><span>@@ -452,3 +452,9 @@</span><br><span> cat $abs_srcdir/base64/base64_test.ok > expout</span><br><span> AT_CHECK([$abs_top_builddir/tests/base64/base64_test], [0], [expout], [ignore])</span><br><span> AT_CLEANUP</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AT_SETUP([time_cc])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_KEYWORDS([time_cc])</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/time_cc/time_cc_test.ok > expout</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CHECK([$abs_top_builddir/tests/time_cc/time_cc_test], [0], [expout], [ignore])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CLEANUP</span><br><span>diff --git a/tests/time_cc/time_cc_test.c b/tests/time_cc/time_cc_test.c</span><br><span>new file mode 100644</span><br><span>index 0000000..22ea7f6</span><br><span>--- /dev/null</span><br><span>+++ b/tests/time_cc/time_cc_test.c</span><br><span>@@ -0,0 +1,768 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Janosch Hofmeyr <nhofmeyr@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/time_cc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum my_ctrs {</span><br><span style="color: hsl(120, 100%, 40%);">+    CTR_CEIL,</span><br><span style="color: hsl(120, 100%, 40%);">+     CTR_ROUND,</span><br><span style="color: hsl(120, 100%, 40%);">+    CTR_FLOOR,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct rate_ctr_desc my_ctr_desc[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        [CTR_CEIL] =    {"ceil", "testing round_threshold_usec = 1"},</span><br><span style="color: hsl(120, 100%, 40%);">+     [CTR_ROUND] =   {"round", "testing round_threshold_usec = 0 = gran_usec/2"},</span><br><span style="color: hsl(120, 100%, 40%);">+      [CTR_FLOOR] =   {"floor", "testing round_threshold_usec = gran_usec"},</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct rate_ctr_group_desc my_ctrg_desc = {</span><br><span style="color: hsl(120, 100%, 40%);">+   "time_cc_test",</span><br><span style="color: hsl(120, 100%, 40%);">+     "Counters for osmo_time_cc test",</span><br><span style="color: hsl(120, 100%, 40%);">+   0,</span><br><span style="color: hsl(120, 100%, 40%);">+    ARRAY_SIZE(my_ctr_desc),</span><br><span style="color: hsl(120, 100%, 40%);">+      my_ctr_desc,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct rate_ctr_group *my_ctrg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum my_obj_timers {</span><br><span style="color: hsl(120, 100%, 40%);">+ T_GRAN = -23,</span><br><span style="color: hsl(120, 100%, 40%);">+ T_ROUND_THRESH = -24,</span><br><span style="color: hsl(120, 100%, 40%);">+ T_FORGET_SUM = -25,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_tdef g_my_obj_tdefs[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+      { .T = T_GRAN, .default_val = 0, .unit = OSMO_TDEF_MS, .desc = "flag_cc granularity, or zero for 1 second" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { .T = T_ROUND_THRESH, .default_val = 0, .unit = OSMO_TDEF_MS,</span><br><span style="color: hsl(120, 100%, 40%);">+                .desc = "flag_cc rounding threshold, or zero for half a granularity" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { .T = T_FORGET_SUM, .default_val = 0, .unit = OSMO_TDEF_MS,</span><br><span style="color: hsl(120, 100%, 40%);">+          .desc = "flag_cc inactivity forget period, or zero to not forget any timings" },</span><br><span style="color: hsl(120, 100%, 40%);">+    {}</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct my_obj {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_time_cc flag_cc_ceil;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_time_cc flag_cc_round;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_time_cc flag_cc_floor;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void my_obj_init(struct my_obj *my_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_time_cc_init(&my_obj->flag_cc_ceil);</span><br><span style="color: hsl(120, 100%, 40%);">+      my_obj->flag_cc_ceil.cfg = (struct osmo_time_cc_cfg){</span><br><span style="color: hsl(120, 100%, 40%);">+              .rate_ctr = rate_ctr_group_get_ctr(my_ctrg, CTR_CEIL),</span><br><span style="color: hsl(120, 100%, 40%);">+                .round_threshold_usec = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+            .T_gran = T_GRAN,</span><br><span style="color: hsl(120, 100%, 40%);">+             .T_forget_sum = T_FORGET_SUM,</span><br><span style="color: hsl(120, 100%, 40%);">+         .T_defs = g_my_obj_tdefs,</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_time_cc_init(&my_obj->flag_cc_round);</span><br><span style="color: hsl(120, 100%, 40%);">+     my_obj->flag_cc_round.cfg = (struct osmo_time_cc_cfg){</span><br><span style="color: hsl(120, 100%, 40%);">+             .rate_ctr = rate_ctr_group_get_ctr(my_ctrg, CTR_ROUND),</span><br><span style="color: hsl(120, 100%, 40%);">+               .T_gran = T_GRAN,</span><br><span style="color: hsl(120, 100%, 40%);">+             .T_round_threshold = T_ROUND_THRESH,</span><br><span style="color: hsl(120, 100%, 40%);">+          .T_forget_sum = T_FORGET_SUM,</span><br><span style="color: hsl(120, 100%, 40%);">+         .T_defs = g_my_obj_tdefs,</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_time_cc_init(&my_obj->flag_cc_floor);</span><br><span style="color: hsl(120, 100%, 40%);">+     my_obj->flag_cc_floor.cfg = (struct osmo_time_cc_cfg){</span><br><span style="color: hsl(120, 100%, 40%);">+             .rate_ctr = rate_ctr_group_get_ctr(my_ctrg, CTR_FLOOR),</span><br><span style="color: hsl(120, 100%, 40%);">+               .round_threshold_usec = UINT64_MAX, /* always >= gran_usec */</span><br><span style="color: hsl(120, 100%, 40%);">+              .T_gran = T_GRAN,</span><br><span style="color: hsl(120, 100%, 40%);">+             .T_forget_sum = T_FORGET_SUM,</span><br><span style="color: hsl(120, 100%, 40%);">+         .T_defs = g_my_obj_tdefs,</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void my_obj_event(struct my_obj *my_obj, bool flag)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_time_cc_set_flag(&my_obj->flag_cc_ceil, flag);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_time_cc_set_flag(&my_obj->flag_cc_round, flag);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_time_cc_set_flag(&my_obj->flag_cc_floor, flag);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void my_obj_destruct(struct my_obj *my_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_time_cc_cleanup(&my_obj->flag_cc_ceil);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_time_cc_cleanup(&my_obj->flag_cc_round);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_time_cc_cleanup(&my_obj->flag_cc_floor);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct log_info_cat log_categories[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct log_info log_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+     .cat = log_categories,</span><br><span style="color: hsl(120, 100%, 40%);">+        .num_cat = ARRAY_SIZE(log_categories),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int main()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   void *ctx = talloc_named_const(NULL, 0, "time_cc_test");</span><br><span style="color: hsl(120, 100%, 40%);">+    struct timespec *now;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct my_obj my_obj = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_init_logging2(ctx, &log_info);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* enable override for CLOCK_MONOTONIC */</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_clock_override_enable(CLOCK_MONOTONIC, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    now = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);</span><br><span style="color: hsl(120, 100%, 40%);">+       now->tv_sec = 23000;</span><br><span style="color: hsl(120, 100%, 40%);">+       now->tv_nsec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* enable override for osmo_gettimeofday(), for osmo_timer_schedule() */</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_gettimeofday_override = true;</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_gettimeofday_override_time = (struct timeval){23000, 0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       my_ctrg = rate_ctr_group_alloc(ctx, &my_ctrg_desc, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CHECK_RATE_CTRS(exp_ceil, exp_round, exp_floor) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+          printf("%d CHECK_RATE_CTRS(" #exp_ceil ", " #exp_round ", " #exp_floor ")", \</span><br><span style="color: hsl(120, 100%, 40%);">+                my_obj.flag_cc_round.flag_state); \</span><br><span style="color: hsl(120, 100%, 40%);">+            while (osmo_select_main_ctx(1) > 0); \</span><br><span style="color: hsl(120, 100%, 40%);">+             if (exp_ceil != my_obj.flag_cc_ceil.cfg.rate_ctr->current \</span><br><span style="color: hsl(120, 100%, 40%);">+                    || exp_round != my_obj.flag_cc_round.cfg.rate_ctr->current \</span><br><span style="color: hsl(120, 100%, 40%);">+               || exp_floor != my_obj.flag_cc_floor.cfg.rate_ctr->current) \</span><br><span style="color: hsl(120, 100%, 40%);">+                  printf("\n     ERROR on line %d: ctr_ceil=%"PRIu64" ctr_round=%"PRIu64" ctr_floor=%"PRIu64"\n", \</span><br><span style="color: hsl(120, 100%, 40%);">+                            __LINE__, \</span><br><span style="color: hsl(120, 100%, 40%);">+                           my_obj.flag_cc_ceil.cfg.rate_ctr->current, \</span><br><span style="color: hsl(120, 100%, 40%);">+                               my_obj.flag_cc_round.cfg.rate_ctr->current, \</span><br><span style="color: hsl(120, 100%, 40%);">+                              my_obj.flag_cc_floor.cfg.rate_ctr->current); \</span><br><span style="color: hsl(120, 100%, 40%);">+              else \</span><br><span style="color: hsl(120, 100%, 40%);">+                        printf(" ok\n"); \</span><br><span style="color: hsl(120, 100%, 40%);">+  } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define ADD_MILLISECS_NO_SELECT(ms) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_clock_override_add(CLOCK_MONOTONIC, ms / 1000, (uint64_t)(ms % 1000) * 1000000); \</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_gettimeofday_override_add(ms / 1000, (uint64_t)(ms % 1000) * 1000); \</span><br><span style="color: hsl(120, 100%, 40%);">+            printf("%d ADD_MILLISECS(" #ms ") --> %ld.%03ld", my_obj.flag_cc_round.flag_state, \</span><br><span style="color: hsl(120, 100%, 40%);">+                  now->tv_sec, now->tv_nsec/1000000); \</span><br><span style="color: hsl(120, 100%, 40%);">+            printf("\n"); \</span><br><span style="color: hsl(120, 100%, 40%);">+     } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define ADD_MILLISECS(ms) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+               ADD_MILLISECS_NO_SELECT(ms); \</span><br><span style="color: hsl(120, 100%, 40%);">+                while (osmo_select_main_ctx(1) > 0); \</span><br><span style="color: hsl(120, 100%, 40%);">+     } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define FLAG(VAL) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+               printf("  flag: %s -> %s\n", my_obj.flag_cc_round.flag_state ? "TRUE" : "FALSE", VAL ? "TRUE" : "FALSE"); \</span><br><span style="color: hsl(120, 100%, 40%);">+              my_obj_event(&my_obj, VAL); \</span><br><span style="color: hsl(120, 100%, 40%);">+     } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+     *                        sum ^</span><br><span style="color: hsl(120, 100%, 40%);">+        *                            |                                          ________</span><br><span style="color: hsl(120, 100%, 40%);">+      *                            |                                         /</span><br><span style="color: hsl(120, 100%, 40%);">+      *                            |                                        /</span><br><span style="color: hsl(120, 100%, 40%);">+       *                            |                                       /</span><br><span style="color: hsl(120, 100%, 40%);">+        *                   3*gran --+--------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |                                     /:</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |                                    / :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            | - - - - - - - - - - - - - - - - - /  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |                                  /.  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |                                 / .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                   2*gran --+--------------------------------+  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |                               /:  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |                              / :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            | - - - - - - - - - -_________/  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |                   /         .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |                  /          .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                   1*gran --+-----------------+           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |                /:           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |               / :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            | - - - - - - -/  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            |             /.  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                            | ....-------' .  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+     *                         0  +----------------------------------------------------------> elapsed time</span><br><span style="color: hsl(120, 100%, 40%);">+     *                                           .  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                               _   _      _______         ____________</span><br><span style="color: hsl(120, 100%, 40%);">+       *                   flag:    __| |_| |____| .  :  |_______|.  :  .  :  |__________</span><br><span style="color: hsl(120, 100%, 40%);">+    *                            f t f t f    t .  :  f       t.  :  .  :  f</span><br><span style="color: hsl(120, 100%, 40%);">+      *   round_threshold_usec       :            .  :           .  :  .  :</span><br><span style="color: hsl(120, 100%, 40%);">+         *                 = 1 usec:  0  1           .  :2          .  :3 .  :4  = "ceil()"</span><br><span style="color: hsl(120, 100%, 40%);">+  *       = 0 == gran_usec/2:  0              1  :           2  :  3  :   = "round()"</span><br><span style="color: hsl(120, 100%, 40%);">+         *              = gran_usec:  0                 1              2     3   = "floor()"</span><br><span style="color: hsl(120, 100%, 40%);">+         */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("\n----------- cumulating time, without forget_sum\n\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  my_obj_init(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(100);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has just turned true the first time */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flag has been true for 0.001s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(99);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* flag has been true for 0.1s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(100);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(100);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 0.2s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(300);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(299);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 0.499s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flag has been true for 0.5s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(499);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 0.999s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flag has been true for 1.0s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flag has been true for 1.001s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(299);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 1.3s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(400);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(199);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 1.499s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(2);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flag has been true for 1.501s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(498);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 1.999s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(2);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flag has been true for 2.001s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(3, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(500);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 2.501s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(3, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(498);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 2.999s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(3, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(3);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flag has been true for 3.003s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(200);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 3.203s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(4321);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(5678);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(9, 9, 8);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(9, 9, 8);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   my_obj_destruct(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr_group_reset(my_ctrg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      printf("\n----------- test forget_sum_usec\n\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, 10, OSMO_TDEF_S);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       now->tv_sec = 23000;</span><br><span style="color: hsl(120, 100%, 40%);">+       now->tv_nsec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_gettimeofday_override_time = (struct timeval){23000, 0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       my_obj_init(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has just turned true the first time */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(100);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 0.1s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(1000);</span><br><span style="color: hsl(120, 100%, 40%);">+  /* 1 s of being false, forget_sum_usec has not yet occurred */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(8999);</span><br><span style="color: hsl(120, 100%, 40%);">+  /* 9.999 s of being false, forget_sum_usec has not yet occurred */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* 10 s of being false, forget_sum_usec has occurred */</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Since previous sums were forgotton, ceil() triggers again */</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECK_RATE_CTRS(2, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* If the sum had not been forgotten, adding 400 ms to the initial 100 ms would have triggered round(). Verify</span><br><span style="color: hsl(120, 100%, 40%);">+         * that this does not occur, since now full 500 ms are required */</span><br><span style="color: hsl(120, 100%, 40%);">+    ADD_MILLISECS(399);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Adding another 100 ms will trigger round() */</span><br><span style="color: hsl(120, 100%, 40%);">+      ADD_MILLISECS(99);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(2, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(2, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* If the sum had not been forgotten, adding 900 ms to the initial 100 ms would have triggered floor(). Verify</span><br><span style="color: hsl(120, 100%, 40%);">+         * that this does not occur, since now full 1000 ms are required. We already added 500 ms above. */</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(400);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Adding another 100 ms will trigger floor() */</span><br><span style="color: hsl(120, 100%, 40%);">+      ADD_MILLISECS(99);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(2, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test that durations of false below forget_sum_usec never trigger a forget */</span><br><span style="color: hsl(120, 100%, 40%);">+       ADD_MILLISECS(300);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(3, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* internal counter is now at 0.3s above the last reported rate counter */</span><br><span style="color: hsl(120, 100%, 40%);">+    FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS(9999);</span><br><span style="color: hsl(120, 100%, 40%);">+  FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(25);</span><br><span style="color: hsl(120, 100%, 40%);">+    FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS(9999);</span><br><span style="color: hsl(120, 100%, 40%);">+  FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(25);</span><br><span style="color: hsl(120, 100%, 40%);">+    FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS(9999);</span><br><span style="color: hsl(120, 100%, 40%);">+  FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(25);</span><br><span style="color: hsl(120, 100%, 40%);">+    FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS(9999);</span><br><span style="color: hsl(120, 100%, 40%);">+  FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(25);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* internal counter is now at 0.4s above the last reported rate counter */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(3, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(100);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(3, 2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(500);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(3, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test that repeated osmo_time_cc_set_flag(false) does not cancel a forget_sum_usec */</span><br><span style="color: hsl(120, 100%, 40%);">+       ADD_MILLISECS(300);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* internal counter is now at 0.3s above the last reported rate counter */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(4, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS(5000);</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Repeat 'false', must not affect forget_sum_usec */</span><br><span style="color: hsl(120, 100%, 40%);">+ FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS(5000);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(4, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* 10 s have passed, forget_sum_usec has occurred.</span><br><span style="color: hsl(120, 100%, 40%);">+     * Hence ceil() will trigger again right away: */</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(5, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Adding 200 ms to the initial 300 ms would have triggered round(), but no more after forget_sum_usec */</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(199);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(5, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Adding another 300 ms will trigger round() */</span><br><span style="color: hsl(120, 100%, 40%);">+      ADD_MILLISECS(299);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(5, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(5, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Adding 700 ms to the initial 300 ms would have triggered ceil(), but no more after forget_sum_usec */</span><br><span style="color: hsl(120, 100%, 40%);">+      ADD_MILLISECS(200);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(5, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Adding another 300 ms will trigger ceil() */</span><br><span style="color: hsl(120, 100%, 40%);">+       ADD_MILLISECS(299);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(5, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(5, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   my_obj_destruct(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr_group_reset(my_ctrg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Verify correctness when select() lags and runs timer callbacks too late */</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("\n----------- cumulating time, without forget_sum, when timer cb are invoked late\n\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, 0, OSMO_TDEF_S);</span><br><span style="color: hsl(120, 100%, 40%);">+  now->tv_sec = 23000;</span><br><span style="color: hsl(120, 100%, 40%);">+       now->tv_nsec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_gettimeofday_override_time = (struct timeval){23000, 0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       my_obj_init(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(100);</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has just turned true the first time */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(100);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* flag has been true for 0.1s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(100);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(100);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* flag has been true for 0.2s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(300);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(799);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* flag has been true for 0.999s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 1.0s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(300);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* flag has been true for 1.3s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(400);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(699);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* flag has been true for 1.999s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 2.0s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(2, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 2.001s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(3, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(499);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* flag has been true for 2.5s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(3, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(499);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* flag has been true for 2.999s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(3, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has been true for 3.0s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(3, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(200);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* flag has been true for 3.2s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(4321);</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(5678);</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(9, 9, 8);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(9, 9, 8);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   my_obj_destruct(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr_group_reset(my_ctrg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("\n----------- test forget_sum, when timer cb are invoked late\n\n");</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, 10, OSMO_TDEF_S);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       now->tv_sec = 23000;</span><br><span style="color: hsl(120, 100%, 40%);">+       now->tv_nsec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_gettimeofday_override_time = (struct timeval){23000, 0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       my_obj_init(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has just turned true the first time */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(100);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* flag has been true for 0.1s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(1000);</span><br><span style="color: hsl(120, 100%, 40%);">+        /* 1 s of being false, forget_sum_usec has not yet occurred */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(8999);</span><br><span style="color: hsl(120, 100%, 40%);">+        /* 9.999 s of being false, forget_sum_usec has not yet occurred */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* 10 s of being false, forget_sum_usec has occurred */</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Since previous sums were forgotton, ceil() triggers again */</span><br><span style="color: hsl(120, 100%, 40%);">+       CHECK_RATE_CTRS(2, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* If the sum had not been forgotten, adding 400 ms to the initial 100 ms would have triggered round(). Verify</span><br><span style="color: hsl(120, 100%, 40%);">+         * that this does not occur, since now full 500 ms are required */</span><br><span style="color: hsl(120, 100%, 40%);">+    ADD_MILLISECS_NO_SELECT(399);</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(2, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Adding another 100 ms will trigger round() */</span><br><span style="color: hsl(120, 100%, 40%);">+      ADD_MILLISECS_NO_SELECT(99);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(2, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* If the sum had not been forgotten, adding 900 ms to the initial 100 ms would have triggered floor(). Verify</span><br><span style="color: hsl(120, 100%, 40%);">+         * that this does not occur, since now full 1000 ms are required. We already added 500 ms above. */</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(400);</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(2, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Adding another 100 ms will trigger floor() */</span><br><span style="color: hsl(120, 100%, 40%);">+      ADD_MILLISECS_NO_SELECT(99);</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(2, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test that durations of false below forget_sum_usec never trigger a forget */</span><br><span style="color: hsl(120, 100%, 40%);">+       ADD_MILLISECS_NO_SELECT(300);</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(3, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* internal counter is now at 0.3s above the last reported rate counter */</span><br><span style="color: hsl(120, 100%, 40%);">+    FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS_NO_SELECT(9999);</span><br><span style="color: hsl(120, 100%, 40%);">+        FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(25);</span><br><span style="color: hsl(120, 100%, 40%);">+  FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS_NO_SELECT(9999);</span><br><span style="color: hsl(120, 100%, 40%);">+        FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(25);</span><br><span style="color: hsl(120, 100%, 40%);">+  FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS_NO_SELECT(9999);</span><br><span style="color: hsl(120, 100%, 40%);">+        FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(25);</span><br><span style="color: hsl(120, 100%, 40%);">+  FLAG(false);</span><br><span style="color: hsl(120, 100%, 40%);">+  ADD_MILLISECS_NO_SELECT(9999);</span><br><span style="color: hsl(120, 100%, 40%);">+        FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS_NO_SELECT(25);</span><br><span style="color: hsl(120, 100%, 40%);">+  /* internal counter is now at 0.4s above the last reported rate counter */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(3, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(100);</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(3, 2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS_NO_SELECT(500);</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(3, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   my_obj_destruct(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr_group_reset(my_ctrg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define SET_TDEFS(gran, round_thresh, forget_sum) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_tdef_set(g_my_obj_tdefs, T_GRAN, gran, OSMO_TDEF_MS); \</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_tdef_set(g_my_obj_tdefs, T_ROUND_THRESH, round_thresh, OSMO_TDEF_MS); \</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, forget_sum, OSMO_TDEF_S); \</span><br><span style="color: hsl(120, 100%, 40%);">+               printf("T_defs: T_gran=%luusec T_round_threshold=%luusec T_forget_sum=%luusec\n", \</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_tdef_get(g_my_obj_tdefs, T_GRAN, OSMO_TDEF_US, -1), \</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_tdef_get(g_my_obj_tdefs, T_ROUND_THRESH, OSMO_TDEF_US, -1), \</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_tdef_get(g_my_obj_tdefs, T_FORGET_SUM, OSMO_TDEF_US, -1)); \</span><br><span style="color: hsl(120, 100%, 40%);">+      } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("\n----------- test T_defs\n\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    now->tv_sec = 23000;</span><br><span style="color: hsl(120, 100%, 40%);">+       now->tv_nsec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_gettimeofday_override_time = (struct timeval){23000, 0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       SET_TDEFS(100, 10, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      my_obj_init(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(100);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   FLAG(true);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flag has just turned true the first time */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(9);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flag has been true for 0.009s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flag has been true for 0.010s */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(90);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* flag has been true for 0.1s */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(1, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   SET_TDEFS(200, 190, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       /* gran is changed to 200ms, but still continues until the next scheduled event until the change is picked up.</span><br><span style="color: hsl(120, 100%, 40%);">+         * For ceil(), it is 1 ms ahead.</span><br><span style="color: hsl(120, 100%, 40%);">+       * For round(), it is 10 ms ahead.</span><br><span style="color: hsl(120, 100%, 40%);">+     * For floor(), it is at the next full (previous) gran 100 ms ahead.</span><br><span style="color: hsl(120, 100%, 40%);">+   * When T_defs change, all internal sums are reset to zero without reporting.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(1, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* 1ms elapsed: ceil() picks up the T_gran change, starts anew. */</span><br><span style="color: hsl(120, 100%, 40%);">+    /* elapsed: ceil 0 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+      CHECK_RATE_CTRS(1, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* elapsed: ceil 1 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+      /* ceil() increments because flag has been true for more than 1 us after reset */</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(8);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* 10 ms elapsed: round() picks up the T_gran change, starts anew */</span><br><span style="color: hsl(120, 100%, 40%);">+  /* elapsed: ceil 9 ms, round 0 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(90);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* 100 ms elapsed: floor() picks up the T_gran change, starts anew */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* elapsed: ceil 99 ms, round 90 ms, floor 0 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(99);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* elapsed: ceil 198 ms, round 189 ms, floor 99 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(2, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* elapsed: ceil 199 ms, round 190 ms, floor 100 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(2, 2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* elapsed: ceil 200 ms, round 191 ms, floor 101 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(2, 2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* elapsed: ceil 201 ms, round 192 ms, floor 102 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(3, 2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(98);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* elapsed: ceil 299 ms, round 290 ms, floor 200 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(3, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(99);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* elapsed: ceil 398 ms, round 389 ms, floor 299 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(3, 2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* elapsed: ceil 399 ms, round 390 ms, floor 300 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(3, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* elapsed: ceil 400 ms, round 391 ms, floor 301 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(3, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* elapsed: ceil 401 ms, round 392 ms, floor 302 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(4, 3, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(98);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* elapsed: ceil 499 ms, round 490 ms, floor 400 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+        CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ SET_TDEFS(100, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* T_defs change, but they only get picked up upon the next event:</span><br><span style="color: hsl(120, 100%, 40%);">+     * For ceil(), it is 102 ms ahead.</span><br><span style="color: hsl(120, 100%, 40%);">+     * For round(), it is 100 ms ahead (thresh is still 190, currently at 90).</span><br><span style="color: hsl(120, 100%, 40%);">+     * For floor(), it is 200 ms ahead.</span><br><span style="color: hsl(120, 100%, 40%);">+    * When T_defs change, all internal sums are reset to zero without reporting.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(100);</span><br><span style="color: hsl(120, 100%, 40%);">+   CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* round() picks up the new T_defs. Internal sum resets, nothing else happens yet.</span><br><span style="color: hsl(120, 100%, 40%);">+     * round() schedules the next event 50 ms ahead. */</span><br><span style="color: hsl(120, 100%, 40%);">+   ADD_MILLISECS(2);</span><br><span style="color: hsl(120, 100%, 40%);">+     CHECK_RATE_CTRS(4, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* ceil() picks up the change, its next event is 1 ms ahead. */</span><br><span style="color: hsl(120, 100%, 40%);">+       ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* ceil: 0.001</span><br><span style="color: hsl(120, 100%, 40%);">+         * round: 0.003</span><br><span style="color: hsl(120, 100%, 40%);">+        * floor: still 97 ms until it picks up the change */</span><br><span style="color: hsl(120, 100%, 40%);">+ CHECK_RATE_CTRS(5, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(46);</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(5, 3, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* round() has first counter trigger after T_defs change. */</span><br><span style="color: hsl(120, 100%, 40%);">+  CHECK_RATE_CTRS(5, 4, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* ceil: 0.048</span><br><span style="color: hsl(120, 100%, 40%);">+         * round: 0.050</span><br><span style="color: hsl(120, 100%, 40%);">+        * floor: still 50 ms until it picks up the change */</span><br><span style="color: hsl(120, 100%, 40%);">+ ADD_MILLISECS(50);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* floor() picks up the change. nothing happens yet. */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* ceil: 0.098</span><br><span style="color: hsl(120, 100%, 40%);">+         * round: 0.100</span><br><span style="color: hsl(120, 100%, 40%);">+        * floor: 0.0 */</span><br><span style="color: hsl(120, 100%, 40%);">+      ADD_MILLISECS(2);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* ceil: 0.100</span><br><span style="color: hsl(120, 100%, 40%);">+         * round: 0.102</span><br><span style="color: hsl(120, 100%, 40%);">+        * floor: 0.002 */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(5, 4, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* ceil: 0.101</span><br><span style="color: hsl(120, 100%, 40%);">+         * round: 0.103</span><br><span style="color: hsl(120, 100%, 40%);">+        * floor: 0.003 */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(6, 4, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(46);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* ceil: 0.147</span><br><span style="color: hsl(120, 100%, 40%);">+         * round: 0.149</span><br><span style="color: hsl(120, 100%, 40%);">+        * floor: 0.049 */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(6, 4, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+     ADD_MILLISECS(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* ceil: 0.148</span><br><span style="color: hsl(120, 100%, 40%);">+         * round: 0.150</span><br><span style="color: hsl(120, 100%, 40%);">+        * floor: 0.050 */</span><br><span style="color: hsl(120, 100%, 40%);">+    CHECK_RATE_CTRS(6, 5, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   my_obj_destruct(&my_obj);</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr_group_reset(my_ctrg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/time_cc/time_cc_test.ok b/tests/time_cc/time_cc_test.ok</span><br><span>new file mode 100644</span><br><span>index 0000000..ccf84d9</span><br><span>--- /dev/null</span><br><span>+++ b/tests/time_cc/time_cc_test.ok</span><br><span>@@ -0,0 +1,328 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+----------- cumulating time, without forget_sum</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(100) --> 23000.100</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.101</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(99) --> 23000.200</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(100) --> 23000.300</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(100) --> 23000.400</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(300) --> 23000.700</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(299) --> 23000.999</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23001.000</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(499) --> 23001.499</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23001.500</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23001.501</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(299) --> 23001.800</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(400) --> 23002.200</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(199) --> 23002.399</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(2) --> 23002.401</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 2, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(498) --> 23002.899</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 2, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(2) --> 23002.901</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(500) --> 23003.401</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(498) --> 23003.899</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(3) --> 23003.902</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(200) --> 23004.102</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(4321) --> 23008.423</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(5678) --> 23014.101</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(9, 9, 8) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(9, 9, 8) ok</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+----------- test forget_sum_usec</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(100) --> 23000.100</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(1000) --> 23001.100</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(8999) --> 23010.099</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(1) --> 23010.100</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23010.101</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(399) --> 23010.500</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(99) --> 23010.599</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23010.600</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(400) --> 23011.000</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(99) --> 23011.099</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23011.100</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(300) --> 23011.400</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(9999) --> 23021.399</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(25) --> 23021.424</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(9999) --> 23031.423</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(25) --> 23031.448</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(9999) --> 23041.447</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(25) --> 23041.472</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(9999) --> 23051.471</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(25) --> 23051.496</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(100) --> 23051.596</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 2, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(500) --> 23052.096</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(300) --> 23052.396</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(5000) --> 23057.396</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(5000) --> 23062.396</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(4, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23062.397</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(199) --> 23062.596</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(299) --> 23062.895</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23062.896</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(200) --> 23063.096</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(299) --> 23063.395</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23063.396</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+----------- cumulating time, without forget_sum, when timer cb are invoked late</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(100) --> 23000.100</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(100) --> 23000.200</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(100) --> 23000.300</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(100) --> 23000.400</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(300) --> 23000.700</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(799) --> 23001.499</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23001.500</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(300) --> 23001.800</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(400) --> 23002.200</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(699) --> 23002.899</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 2, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23002.900</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23002.901</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(499) --> 23003.400</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(499) --> 23003.899</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23003.900</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(200) --> 23004.100</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(4321) --> 23008.421</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(5678) --> 23014.099</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(9, 9, 8) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(9, 9, 8) ok</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+----------- test forget_sum, when timer cb are invoked late</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(100) --> 23000.100</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(1000) --> 23001.100</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(8999) --> 23010.099</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(1) --> 23010.100</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23010.101</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(399) --> 23010.500</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(99) --> 23010.599</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23010.600</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(400) --> 23011.000</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(99) --> 23011.099</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23011.100</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(300) --> 23011.400</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(9999) --> 23021.399</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(25) --> 23021.424</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(9999) --> 23031.423</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(25) --> 23031.448</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(9999) --> 23041.447</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(25) --> 23041.472</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: TRUE -> FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(9999) --> 23051.471</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(25) --> 23051.496</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(100) --> 23051.596</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 2, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(500) --> 23052.096</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+----------- test T_defs</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+T_defs: T_gran=100000usec T_round_threshold=10000usec T_forget_sum=0usec</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+0 ADD_MILLISECS(100) --> 23000.100</span><br><span style="color: hsl(120, 100%, 40%);">+0 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+  flag: FALSE -> TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(0, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(9) --> 23000.109</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 0, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.110</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 1, 0) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(90) --> 23000.200</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+T_defs: T_gran=200000usec T_round_threshold=190000usec T_forget_sum=1000000usec</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.201</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(1, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.202</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(8) --> 23000.210</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(90) --> 23000.300</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(99) --> 23000.399</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 1, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.400</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 2, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.401</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(2, 2, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.402</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 2, 1) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(98) --> 23000.500</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(99) --> 23000.599</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 2, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.600</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.601</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(3, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.602</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 2) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(98) --> 23000.700</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+T_defs: T_gran=100000usec T_round_threshold=0usec T_forget_sum=0usec</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(100) --> 23000.800</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(2) --> 23000.802</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(4, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.803</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(46) --> 23000.849</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 3, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.850</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 4, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(50) --> 23000.900</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(2) --> 23000.902</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(5, 4, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.903</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(6, 4, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(46) --> 23000.949</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(6, 4, 3) ok</span><br><span style="color: hsl(120, 100%, 40%);">+1 ADD_MILLISECS(1) --> 23000.950</span><br><span style="color: hsl(120, 100%, 40%);">+1 CHECK_RATE_CTRS(6, 5, 3) ok</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/26230">change 26230</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/libosmocore/+/26230"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Iabb17a08e6e1a86f168cdb008fba05ecd4776bdd </div>
<div style="display:none"> Gerrit-Change-Number: 26230 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>