Related: SYS#4878 Depends: Iabb17a08e6e1a86f168cdb008fba05ecd4776bdd (libosmocore) Change-Id: Ica9f908a1a30f334a24c59471affa11225117e12changes/31/26231/4
parent
7f7c83a7de
commit
d13ef633d2
@ -1,157 +0,0 @@ |
||||
/* Report the cumulative counter of time for which a flag is true as rate counter. */ |
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <osmocom/core/timer.h> |
||||
|
||||
struct osmo_tdef; |
||||
struct rate_ctr; |
||||
|
||||
/*! Configuration for time_cc.
|
||||
* Report the cumulative counter of time for which a flag is true as rate counter. |
||||
* For example, for each second that the flag is true, increment a rate counter. |
||||
* |
||||
* The flag to be monitored is reported by time_cc_set_flag(). |
||||
* |
||||
* The granularity defines how much time one rate counter increment represents: |
||||
* the default configuration is gran_usec = 1000000, i.e. one rate counter increment represents one second. |
||||
* |
||||
* Reporting as rate counter is configurable by round_threshold_usec and forget_sum_usec, examples: |
||||
* |
||||
* round_threshold_usec: |
||||
* - To get "ceil()" behavior, set round_threshold_usec = 1. This increments the rate counter for each gran_usec period |
||||
* where the flag was seen true, even if it was true for only a very short fraction of a gran_usec period. |
||||
* - To get "round()" behavior, set round_threshold_usec = half of gran_usec. The rate counter increments when the flag |
||||
* 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 |
||||
* is a special value that means to use half of gran_usec. |
||||
* - To get "floor()" behavior, set round_threshold_usec >= gran_usec. The rate counter increments when reaching full |
||||
* gran_usec periods of the flag being true. |
||||
* |
||||
* forget_sum_usec: |
||||
* This is a tradeoff between the accuracy of the reported rate counter and making sure that the events reported are not |
||||
* irrelevantly long ago. |
||||
* - To keep sub-granularity-period surplus time forever, set forget_sum_usec = 0. |
||||
* - To keep surplus time for up to a minute, set forget_sum_usec = 60000000 (60 seconds). |
||||
* - To get rid of "leftover" time (almost) immediately after the flag goes false, set forget_sum_usec = 1. |
||||
* - If gran_usec is set to one second and forget_sum_usec is set to one minute, the reported rate counter has a |
||||
* possible inaccuracy of 1/60th, but makes sure that no timings older than a minute affect the current reports. |
||||
* |
||||
* Reporting modes in detail: |
||||
* |
||||
* The rate_ctr increments when the cumulative counter passes round_threshold_usec (default: half of gran_usec). |
||||
* |
||||
* sum ^ |
||||
* | ________ |
||||
* | / |
||||
* | / |
||||
* | / |
||||
* 3*gran --+--------------------------------------+ |
||||
* | /: |
||||
* | / : |
||||
* | - - - - - - - - - - - - - - - - - / : |
||||
* | /. : |
||||
* | / . : |
||||
* 2*gran --+--------------------------------+ . : |
||||
* | /: . : |
||||
* | / : . : |
||||
* | - - - - - - - - - -_________/ : . : |
||||
* | / . : . : |
||||
* | / . : . : |
||||
* 1*gran --+-----------------+ . : . : |
||||
* | /: . : . : |
||||
* | / : . : . : |
||||
* | - - - - - - -/ : . : . : |
||||
* | /. : . : . : |
||||
* | ....-------' . : . : . : |
||||
* 0 +------------------------------------------------------------------------> elapsed time |
||||
* . : . : . : |
||||
* _ _ _______ ____________ |
||||
* flag: __| |_| |____| . : |_______|. : . : |__________ |
||||
* f t f t f t . : f t. : . : f |
||||
* round_threshold_usec : . : . : . : |
||||
* = 1 usec: 0 1 . :2 . :3 . :4 = "ceil()" |
||||
* = 0 == gran_usec/2: 0 1 : 2 : 3 : = "round()" |
||||
* >= gran_usec: 0 1 2 3 = "floor()" |
||||
* |
||||
*/ |
||||
struct time_cc_cfg { |
||||
/*! Granularity in microseconds: nr of microseconds that one rate_ctr increment represents. A typical value is
|
||||
* gran_usec = 1000000, meaning one rate counter increment represents one second. */ |
||||
uint64_t gran_usec; |
||||
/*! Nr of microseconds above a full gran_usec at which to trigger rate_ctr_round. When zero, half a gran_usec. */ |
||||
uint64_t round_threshold_usec; |
||||
/*! Forget counted sub-gran time after the flag was false for this long. */ |
||||
uint64_t forget_sum_usec; |
||||
/*! Rate counter to report to, or NULL to not use it. */ |
||||
struct rate_ctr *rate_ctr; |
||||
|
||||
/*! Update gran_usec from this T timer value, or zero to not use any T timer. */ |
||||
int T_gran; |
||||
/*! Update round_threshold_usec from this T timer value, or zero to not use any T timer. */ |
||||
int T_round_threshold; |
||||
/*! Update forget_sum_usec from this T timer value, or zero to not use any T timer. */ |
||||
int T_forget_sum; |
||||
/*! Look up T_gran and T_forget_sum in this list of timers, or NULL to not use any T timers. */ |
||||
struct osmo_tdef *T_defs; |
||||
}; |
||||
|
||||
/*! Report the cumulative counter of time for which a flag is true as rate counter.
|
||||
* See also time_cc_cfg for details on configuring. |
||||
* |
||||
* Usage: |
||||
* |
||||
* struct my_obj { |
||||
* struct time_cc flag_cc; |
||||
* }; |
||||
* |
||||
* void my_obj_init(struct my_obj *my_obj) |
||||
* { |
||||
* time_cc_init(&my_obj->flag_cc); |
||||
* my_obj->flag_cc.cfg = (struct time_cc_cfg){ |
||||
* .gran_usec = 1000000, |
||||
* .forget_sum_usec = 60000000, |
||||
* .rate_ctr = rate_ctr_group_get_ctr(my_ctrg, MY_CTR_IDX), |
||||
* }; |
||||
* // optional: set initial flag state, default is 'false':
|
||||
* // time_cc_set_flag(&my_obj->flag_cc, false);
|
||||
* } |
||||
* |
||||
* void my_obj_event(struct my_obj *my_obj, bool flag) |
||||
* { |
||||
* time_cc_set_flag(&my_obj->flag_cc, flag); |
||||
* } |
||||
* |
||||
* void my_obj_destruct(struct my_obj *my_obj) |
||||
* { |
||||
* time_cc_cleanup(&my_obj->flag_cc); |
||||
* } |
||||
*/ |
||||
struct time_cc { |
||||
struct time_cc_cfg cfg; |
||||
|
||||
bool flag_state; |
||||
|
||||
/** Overall cumulative sum. Does not get reset for the entire lifetime of a time_cc.
|
||||
* (Informational only, not used by the time_cc implementation.) */ |
||||
uint64_t total_sum; |
||||
|
||||
struct osmo_timer_list timer; |
||||
|
||||
/** CLOCK_MONOTONIC reading in microseconds, at the time when the time_cc instance started counting. */ |
||||
uint64_t start_time; |
||||
/** CLOCK_MONOTONIC reading in microseconds, at the time when the time_cc last evaluated the flag state and
|
||||
* possibly added to the cumulated sum. */ |
||||
uint64_t last_counted_time; |
||||
|
||||
/** Internal cumulative counter of time that flag_state was true. It may get reset to zero regularly, depending
|
||||
* on cfg.forget_sum_usec. This is the basis for incrementing cfg.rate_ctr. */ |
||||
uint64_t sum; |
||||
/** The amount of time that already reported cfg.rate_ctr increments account for. This may be ahead of or behind
|
||||
* 'sum', depending on cfg.round_threshold_usec. */ |
||||
uint64_t reported_sum; |
||||
}; |
||||
|
||||
void time_cc_init(struct time_cc *tc); |
||||
void time_cc_set_flag(struct time_cc *tc, bool flag); |
||||
void time_cc_cleanup(struct time_cc *tc); |
@ -1,208 +0,0 @@ |
||||
/* Report the cumulative counter of time for which a flag is true as rate counter. */ |
||||
/* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* |
||||
* All Rights Reserved |
||||
* |
||||
* Author: Neels Hofmeyr <nhofmeyr@sysmocom.de> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as published by |
||||
* the Free Software Foundation; either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* |
||||
*/ |
||||
|
||||
#include <limits.h> |
||||
|
||||
#include <osmocom/core/tdef.h> |
||||
#include <osmocom/core/rate_ctr.h> |
||||
|
||||
#include <osmocom/bsc/time_cc.h> |
||||
|
||||
#define GRAN_USEC(TIME_CC) ((TIME_CC)->cfg.gran_usec ? : 1000000) |
||||
#define ROUND_THRESHOLD_USEC(TIME_CC) ((TIME_CC)->cfg.round_threshold_usec ? \ |
||||
OSMO_MIN((TIME_CC)->cfg.round_threshold_usec, GRAN_USEC(TIME_CC)) \
|
||||
: (GRAN_USEC(TIME_CC) / 2)) |
||||
|
||||
static uint64_t time_now_usec() |
||||
{ |
||||
struct timespec tp; |
||||
if (osmo_clock_gettime(CLOCK_MONOTONIC, &tp)) |
||||
return 0; |
||||
return (uint64_t)tp.tv_sec * 1000000 + tp.tv_nsec / 1000; |
||||
} |
||||
|
||||
static void time_cc_forget_sum(struct time_cc *tc, uint64_t now); |
||||
|
||||
static void time_cc_update_from_tdef(struct time_cc *tc, uint64_t now) |
||||
{ |
||||
bool do_forget_sum = false; |
||||
if (!tc->cfg.T_defs) |
||||
return; |
||||
if (tc->cfg.T_gran) { |
||||
uint64_t was = GRAN_USEC(tc); |
||||
tc->cfg.gran_usec = osmo_tdef_get(tc->cfg.T_defs, tc->cfg.T_gran, OSMO_TDEF_US, -1); |
||||
if (was != GRAN_USEC(tc)) |
||||
do_forget_sum = true; |
||||
} |
||||
if (tc->cfg.T_round_threshold) |
||||
tc->cfg.round_threshold_usec = osmo_tdef_get(tc->cfg.T_defs, tc->cfg.T_round_threshold, |
||||
OSMO_TDEF_US, -1); |
||||
if (tc->cfg.T_forget_sum) { |
||||
uint64_t was = tc->cfg.forget_sum_usec; |
||||
tc->cfg.forget_sum_usec = osmo_tdef_get(tc->cfg.T_defs, tc->cfg.T_forget_sum, OSMO_TDEF_US, -1); |
||||
if (tc->cfg.forget_sum_usec && was != tc->cfg.forget_sum_usec) |
||||
do_forget_sum = true; |
||||
} |
||||
|
||||
if (do_forget_sum && tc->sum) |
||||
time_cc_forget_sum(tc, now); |
||||
} |
||||
|
||||
static void time_cc_schedule_timer(struct time_cc *tc, uint64_t now); |
||||
|
||||
/* Clear out osmo_timer and internal counting state of struct time_cc. The .cfg remains unaffected. After calling, the
|
||||
* time_cc instance can be used again to accumulate state as if it had just been initialized. */ |
||||
void time_cc_cleanup(struct time_cc *tc) |
||||
{ |
||||
osmo_timer_del(&tc->timer); |
||||
*tc = (struct time_cc){ |
||||
.cfg = tc->cfg, |
||||
}; |
||||
} |
||||
|
||||
static void time_cc_start(struct time_cc *tc, uint64_t now) |
||||
{ |
||||
time_cc_cleanup(tc); |
||||
/* Set the default of 1 second of granularity */ |
||||
tc->start_time = now; |
||||
tc->last_counted_time = now; |
||||
time_cc_update_from_tdef(tc, now); |
||||
time_cc_schedule_timer(tc, now); |
||||
} |
||||
|
||||
static void time_cc_count_time(struct time_cc *tc, uint64_t now) |
||||
{ |
||||
uint64_t time_delta = now - tc->last_counted_time; |
||||
tc->last_counted_time = now; |
||||
if (!tc->flag_state) |
||||
return; |
||||
/* Flag is currently true, cumulate the elapsed time */ |
||||
tc->total_sum += time_delta; |
||||
tc->sum += time_delta; |
||||
} |
||||
|
||||
static void time_cc_report(struct time_cc *tc, uint64_t now) |
||||
{ |
||||
uint64_t delta; |
||||
uint64_t n; |
||||
if (!tc->cfg.rate_ctr) |
||||
return; |
||||
/* We report a sum "rounded up", ahead of time. If the granularity period has not yet elapsed after the last
|
||||
* reporting, do not report again yet. */ |
||||
if (tc->reported_sum > tc->sum) |
||||
return; |
||||
delta = tc->sum - tc->reported_sum; |
||||
/* elapsed full periods */ |
||||
n = delta / GRAN_USEC(tc); |
||||
/* If the delta has passed round_threshold (normally half of gran_usec), increment. */ |
||||
delta -= n * GRAN_USEC(tc); |
||||
if (delta >= ROUND_THRESHOLD_USEC(tc)) |
||||
n++; |
||||
if (!n) |
||||
return; |
||||
|
||||
/* integer sanity, since rate_ctr_add() takes an int argument. */ |
||||
if (n > INT_MAX) |
||||
n = INT_MAX; |
||||
rate_ctr_add(tc->cfg.rate_ctr, n); |
||||
/* Store the increments of gran_usec that were counted. */ |
||||
tc->reported_sum += n * GRAN_USEC(tc); |
||||
} |
||||
|
||||
static void time_cc_forget_sum(struct time_cc *tc, uint64_t now) |
||||
{ |
||||
tc->reported_sum = 0; |
||||
tc->sum = 0; |
||||
|
||||
if (tc->last_counted_time < now) |
||||
tc->last_counted_time = now; |
||||
} |
||||
|
||||
/* Initialize struct time_cc. Call this once before use, and before setting up the .cfg items. */ |
||||
void time_cc_init(struct time_cc *tc) |
||||
{ |
||||
*tc = (struct time_cc){0}; |
||||
} |
||||
|
||||
void time_cc_set_flag(struct time_cc *tc, bool flag) |
||||
{ |
||||
uint64_t now = time_now_usec(); |
||||
if (!tc->start_time) |
||||
time_cc_start(tc, now); |
||||
/* No flag change == no effect */ |
||||
if (flag == tc->flag_state) |
||||
return; |
||||
/* Sum up elapsed time, report increments for that. */ |
||||
time_cc_count_time(tc, now); |
||||
time_cc_report(tc, now); |
||||
tc->flag_state = flag; |
||||
time_cc_schedule_timer(tc, now); |
||||
} |
||||
|
||||
static void time_cc_timer_cb(void *data) |
||||
{ |
||||
struct time_cc *tc = data; |
||||
uint64_t now = time_now_usec(); |
||||
|
||||
time_cc_update_from_tdef(tc, now); |
||||
|
||||
if (tc->flag_state) { |
||||
time_cc_count_time(tc, now); |
||||
time_cc_report(tc, now); |
||||
} else if (tc->cfg.forget_sum_usec && tc->sum |
||||
&& (now >= tc->last_counted_time + tc->cfg.forget_sum_usec)) { |
||||
time_cc_forget_sum(tc, now); |
||||
} |
||||
time_cc_schedule_timer(tc, now); |
||||
} |
||||
|
||||
static void time_cc_schedule_timer(struct time_cc *tc, uint64_t now) |
||||
{ |
||||
uint64_t next_event = UINT64_MAX; |
||||
|
||||
time_cc_update_from_tdef(tc, now); |
||||
|
||||
/* Figure out the next time we should do anything, if the flag state remains unchanged. */ |
||||
/* If it is required, when will the next forget_sum happen? */ |
||||
if (tc->cfg.forget_sum_usec && !tc->flag_state && tc->sum > 0) { |
||||
uint64_t next_forget_time = tc->last_counted_time + tc->cfg.forget_sum_usec; |
||||
next_event = OSMO_MIN(next_event, next_forget_time); |
||||
} |
||||
/* Next rate_ctr increment? */ |
||||
if (tc->flag_state && tc->cfg.rate_ctr) { |
||||
uint64_t next_inc = now + (tc->reported_sum - tc->sum) + ROUND_THRESHOLD_USEC(tc); |
||||
next_event = OSMO_MIN(next_event, next_inc); |
||||
} |
||||
|
||||
/* No event coming up? */ |
||||
if (next_event == UINT64_MAX) |
||||
return; |
||||
|
||||
if (next_event <= now) |
||||
next_event = 0; |
||||
else |
||||
next_event -= now; |
||||
|
||||
osmo_timer_setup(&tc->timer, time_cc_timer_cb, tc); |
||||
osmo_timer_del(&tc->timer); |
||||
osmo_timer_schedule(&tc->timer, next_event / 1000000, next_event % 1000000); |
||||
} |
@ -1,36 +0,0 @@ |
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-ggdb3 \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
time_cc_test.ok \
|
||||
$(NULL)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
time_cc_test \
|
||||
$(NULL)
|
||||
|
||||
time_cc_test_SOURCES = \
|
||||
time_cc_test.c \
|
||||
$(NULL)
|
||||
|
||||
time_cc_test_LDADD = \
|
||||
$(top_builddir)/src/osmo-bsc/libbsc.la \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
.PHONY: update_exp |
||||
update_exp: |
||||
$(builddir)/time_cc_test >$(srcdir)/time_cc_test.ok
|
@ -1,769 +0,0 @@ |
||||
/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved |
||||
* |
||||
* Author: Neels Janosch Hofmeyr <nhofmeyr@sysmocom.de> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as published by |
||||
* the Free Software Foundation; either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* |
||||
*/ |
||||
|
||||
#include <inttypes.h> |
||||
|
||||
#include <osmocom/core/utils.h> |
||||
#include <osmocom/core/rate_ctr.h> |
||||
#include <osmocom/core/logging.h> |
||||
#include <osmocom/core/application.h> |
||||
#include <osmocom/core/select.h> |
||||
#include <osmocom/core/tdef.h> |
||||
|
||||
#include <osmocom/bsc/time_cc.h> |
||||
|
||||
enum my_ctrs { |
||||
CTR_CEIL, |
||||
CTR_ROUND, |
||||
CTR_FLOOR, |
||||
}; |
||||
|
||||
const struct rate_ctr_desc my_ctr_desc[] = { |
||||
[CTR_CEIL] = {"ceil", "testing round_threshold_usec = 1"}, |
||||
[CTR_ROUND] = {"round", "testing round_threshold_usec = 0 = gran_usec/2"}, |
||||
[CTR_FLOOR] = {"floor", "testing round_threshold_usec = gran_usec"}, |
||||
}; |
||||
|
||||
const struct rate_ctr_group_desc my_ctrg_desc = { |
||||
"time_cc_test", |
||||
"Counters for time_cc test", |
||||
0, |
||||
ARRAY_SIZE(my_ctr_desc), |
||||
my_ctr_desc, |
||||
}; |
||||
|
||||
struct rate_ctr_group *my_ctrg; |
||||
|
||||
|
||||
enum my_obj_timers { |
||||
T_GRAN = -23, |
||||
T_ROUND_THRESH = -24, |
||||
T_FORGET_SUM = -25, |
||||
}; |
||||
|
||||
struct osmo_tdef g_my_obj_tdefs[] = { |
||||
{ .T = T_GRAN, .default_val = 0, .unit = OSMO_TDEF_MS, .desc = "flag_cc granularity, or zero for 1 second" }, |
||||
{ .T = T_ROUND_THRESH, .default_val = 0, .unit = OSMO_TDEF_MS, |
||||
.desc = "flag_cc rounding threshold, or zero for half a granularity" }, |
||||
{ .T = T_FORGET_SUM, .default_val = 0, .unit = OSMO_TDEF_MS, |
||||
.desc = "flag_cc inactivity forget period, or zero to not forget any timings" }, |
||||
{} |
||||
}; |
||||
|
||||
|
||||
struct my_obj { |
||||
struct time_cc flag_cc_ceil; |
||||
struct time_cc flag_cc_round; |
||||
struct time_cc flag_cc_floor; |
||||
}; |
||||
|
||||
void my_obj_init(struct my_obj *my_obj) |
||||
{ |
||||
time_cc_init(&my_obj->flag_cc_ceil); |
||||
my_obj->flag_cc_ceil.cfg = (struct time_cc_cfg){ |
||||
.rate_ctr = rate_ctr_group_get_ctr(my_ctrg, CTR_CEIL), |
||||
.round_threshold_usec = 1, |
||||
.T_gran = T_GRAN, |
||||
.T_forget_sum = T_FORGET_SUM, |
||||
.T_defs = g_my_obj_tdefs, |
||||
}; |
||||
|
||||
time_cc_init(&my_obj->flag_cc_round); |
||||
my_obj->flag_cc_round.cfg = (struct time_cc_cfg){ |
||||
.rate_ctr = rate_ctr_group_get_ctr(my_ctrg, CTR_ROUND), |
||||
.T_gran = T_GRAN, |
||||
.T_round_threshold = T_ROUND_THRESH, |
||||
.T_forget_sum = T_FORGET_SUM, |
||||
.T_defs = g_my_obj_tdefs, |
||||
}; |
||||
|
||||
time_cc_init(&my_obj->flag_cc_floor); |
||||
my_obj->flag_cc_floor.cfg = (struct time_cc_cfg){ |
||||
.rate_ctr = rate_ctr_group_get_ctr(my_ctrg, CTR_FLOOR), |
||||
.round_threshold_usec = UINT64_MAX, /* always >= gran_usec */ |
||||
.T_gran = T_GRAN, |
||||
.T_forget_sum = T_FORGET_SUM, |
||||
.T_defs = g_my_obj_tdefs, |
||||
}; |
||||
} |
||||
|
||||
void my_obj_event(struct my_obj *my_obj, bool flag) |
||||
{ |
||||
time_cc_set_flag(&my_obj->flag_cc_ceil, flag); |
||||
time_cc_set_flag(&my_obj->flag_cc_round, flag); |
||||
time_cc_set_flag(&my_obj->flag_cc_floor, flag); |
||||
} |
||||
|
||||
void my_obj_destruct(struct my_obj *my_obj) |
||||
{ |
||||
time_cc_cleanup(&my_obj->flag_cc_ceil); |
||||
time_cc_cleanup(&my_obj->flag_cc_round); |
||||
time_cc_cleanup(&my_obj->flag_cc_floor); |
||||
} |
||||
|
||||
static const struct log_info_cat log_categories[] = { |
||||
}; |
||||
|
||||
static const struct log_info log_info = { |
||||
.cat = log_categories, |
||||
.num_cat = ARRAY_SIZE(log_categories), |
||||
}; |
||||
|
||||
int main() |
||||
{ |
||||
void *ctx = talloc_named_const(NULL, 0, "time_cc_test"); |
||||
struct timespec *now; |
||||
struct my_obj my_obj = {0}; |
||||
|
||||
osmo_init_logging2(ctx, &log_info); |
||||
|
||||
/* enable override for CLOCK_MONOTONIC */ |
||||
osmo_clock_override_enable(CLOCK_MONOTONIC, true); |
||||
now = osmo_clock_override_gettimespec(CLOCK_MONOTONIC); |
||||
now->tv_sec = 23000; |
||||
now->tv_nsec = 0; |
||||
|
||||
/* enable override for osmo_gettimeofday(), for osmo_timer_schedule() */ |
||||
osmo_gettimeofday_override = true; |
||||
osmo_gettimeofday_override_time = (struct timeval){23000, 0}; |
||||
|
||||
my_ctrg = rate_ctr_group_alloc(ctx, &my_ctrg_desc, 0); |
||||
|
||||
#define CHECK_RATE_CTRS(exp_ceil, exp_round, exp_floor) do { \ |
||||
printf("%d CHECK_RATE_CTRS(" #exp_ceil ", " #exp_round ", " #exp_floor ")", \
|
||||
my_obj.flag_cc_round.flag_state); \
|
||||
while (osmo_select_main_ctx(1) > 0); \
|
||||
if (exp_ceil != my_obj.flag_cc_ceil.cfg.rate_ctr->current \
|
||||
|| exp_round != my_obj.flag_cc_round.cfg.rate_ctr->current \
|
||||
|| exp_floor != my_obj.flag_cc_floor.cfg.rate_ctr->current) \
|
||||
printf("\n ERROR on line %d: ctr_ceil=%"PRIu64" ctr_round=%"PRIu64" ctr_floor=%"PRIu64"\n", \
|
||||
__LINE__, \
|
||||
my_obj.flag_cc_ceil.cfg.rate_ctr->current, \
|
||||
my_obj.flag_cc_round.cfg.rate_ctr->current, \
|
||||
my_obj.flag_cc_floor.cfg.rate_ctr->current); \
|
||||
else \
|
||||
printf(" ok\n"); \
|
||||
} while (0) |
||||
|
||||
#define ADD_MILLISECS_NO_SELECT(ms) do { \ |
||||
osmo_clock_override_add(CLOCK_MONOTONIC, ms / 1000, (uint64_t)(ms % 1000) * 1000000); \
|
||||
osmo_gettimeofday_override_add(ms / 1000, (uint64_t)(ms % 1000) * 1000); \
|
||||
printf("%d ADD_MILLISECS(" #ms ") --> %ld.%03ld", my_obj.flag_cc_round.flag_state, \
|
||||
now->tv_sec, now->tv_nsec/1000000); \
|
||||
printf("\n"); \
|
||||
} while (0) |
||||
|
||||
#define ADD_MILLISECS(ms) do { \ |
||||
ADD_MILLISECS_NO_SELECT(ms); \
|
||||
while (osmo_select_main_ctx(1) > 0); \
|
||||
} while (0) |
||||
|
||||
#define FLAG(VAL) do { \ |
||||
printf(" flag: %s -> %s\n", my_obj.flag_cc_round.flag_state ? "TRUE" : "FALSE", VAL ? "TRUE" : "FALSE"); \
|
||||
my_obj_event(&my_obj, VAL); \
|
||||
} while (0) |
||||
|
||||
/*
|
||||
* sum ^ |
||||
* | ________ |
||||
* | / |
||||
* | / |
||||
* | / |
||||
* 3*gran --+--------------------------------------+ |
||||
* | /: |
||||
* | / : |
||||
* | - - - - - - - - - - - - - - - - - / : |
||||
* | /. : |
||||
* | / . : |
||||
* 2*gran --+--------------------------------+ . : |
||||
* | /: . : |
||||
* | / : . : |
||||
* | - - - - - - - - - -_________/ : . : |
||||
* | / . : . : |
||||
* | / . : . : |
||||
* 1*gran --+-----------------+ . : . : |
||||
* | /: . : . : |
||||
* | / : . : . : |
||||
* | - - - - - - -/ : . : . : |
||||
* | /. : . : . : |
||||
* | ....-------' . : . : . : |
||||
* 0 +----------------------------------------------------------> elapsed time |
||||
* . : . : . : |
||||
* _ _ _______ ____________ |
||||
* flag: __| |_| |____| . : |_______|. : . : |__________ |
||||
* f t f t f t . : f t. : . : f |
||||
* round_threshold_usec : . : . : . : |
||||
* = 1 usec: 0 1 . :2 . :3 . :4 = "ceil()" |
||||
* = 0 == gran_usec/2: 0 1 : 2 : 3 : = "round()" |
||||
* = gran_usec: 0 1 2 3 = "floor()" |
||||
*/ |
||||
|
||||
printf("\n----------- cumulating time, without forget_sum\n\n"); |
||||
|
||||
my_obj_init(&my_obj); |
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
|
||||
ADD_MILLISECS(100); |
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
|
||||
FLAG(true); |
||||
/* flag has just turned true the first time */ |
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
ADD_MILLISECS(1); |
||||
/* flag has been true for 0.001s */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
ADD_MILLISECS(99); |
||||
/* flag has been true for 0.1s */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS(100); |
||||
|
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
ADD_MILLISECS(100); |
||||
/* flag has been true for 0.2s */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS(300); |
||||
|
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
ADD_MILLISECS(299); |
||||
/* flag has been true for 0.499s */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
ADD_MILLISECS(1); |
||||
/* flag has been true for 0.5s */ |
||||
CHECK_RATE_CTRS(1, 1, 0); |
||||
ADD_MILLISECS(499); |
||||
/* flag has been true for 0.999s */ |
||||
CHECK_RATE_CTRS(1, 1, 0); |
||||
ADD_MILLISECS(1); |
||||
/* flag has been true for 1.0s */ |
||||
CHECK_RATE_CTRS(1, 1, 1); |
||||
ADD_MILLISECS(1); |
||||
/* flag has been true for 1.001s */ |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
ADD_MILLISECS(299); |
||||
/* flag has been true for 1.3s */ |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
|
||||
ADD_MILLISECS(400); |
||||
|
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
ADD_MILLISECS(199); |
||||
/* flag has been true for 1.499s */ |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
ADD_MILLISECS(2); |
||||
/* flag has been true for 1.501s */ |
||||
CHECK_RATE_CTRS(2, 2, 1); |
||||
ADD_MILLISECS(498); |
||||
/* flag has been true for 1.999s */ |
||||
CHECK_RATE_CTRS(2, 2, 1); |
||||
ADD_MILLISECS(2); |
||||
/* flag has been true for 2.001s */ |
||||
CHECK_RATE_CTRS(3, 2, 2); |
||||
ADD_MILLISECS(500); |
||||
/* flag has been true for 2.501s */ |
||||
CHECK_RATE_CTRS(3, 3, 2); |
||||
ADD_MILLISECS(498); |
||||
/* flag has been true for 2.999s */ |
||||
CHECK_RATE_CTRS(3, 3, 2); |
||||
ADD_MILLISECS(3); |
||||
/* flag has been true for 3.003s */ |
||||
CHECK_RATE_CTRS(4, 3, 3); |
||||
ADD_MILLISECS(200); |
||||
/* flag has been true for 3.203s */ |
||||
CHECK_RATE_CTRS(4, 3, 3); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(4, 3, 3); |
||||
|
||||
ADD_MILLISECS(4321); |
||||
CHECK_RATE_CTRS(4, 3, 3); |
||||
|
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(4, 3, 3); |
||||
ADD_MILLISECS(5678); |
||||
CHECK_RATE_CTRS(9, 9, 8); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(9, 9, 8); |
||||
|
||||
my_obj_destruct(&my_obj); |
||||
rate_ctr_group_reset(my_ctrg); |
||||
|
||||
printf("\n----------- test forget_sum_usec\n\n"); |
||||
osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, 10, OSMO_TDEF_S); |
||||
|
||||
now->tv_sec = 23000; |
||||
now->tv_nsec = 0; |
||||
osmo_gettimeofday_override_time = (struct timeval){23000, 0}; |
||||
|
||||
my_obj_init(&my_obj); |
||||
|
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
|
||||
FLAG(true); |
||||
/* flag has just turned true the first time */ |
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
ADD_MILLISECS(100); |
||||
/* flag has been true for 0.1s */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS(1000); |
||||
/* 1 s of being false, forget_sum_usec has not yet occurred */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS(8999); |
||||
/* 9.999 s of being false, forget_sum_usec has not yet occurred */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS(1); |
||||
/* 10 s of being false, forget_sum_usec has occurred */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
ADD_MILLISECS(1); |
||||
/* Since previous sums were forgotton, ceil() triggers again */ |
||||
CHECK_RATE_CTRS(2, 0, 0); |
||||
/* If the sum had not been forgotten, adding 400 ms to the initial 100 ms would have triggered round(). Verify
|
||||
* that this does not occur, since now full 500 ms are required */ |
||||
ADD_MILLISECS(399); |
||||
CHECK_RATE_CTRS(2, 0, 0); |
||||
/* Adding another 100 ms will trigger round() */ |
||||
ADD_MILLISECS(99); |
||||
CHECK_RATE_CTRS(2, 0, 0); |
||||
ADD_MILLISECS(1); |
||||
CHECK_RATE_CTRS(2, 1, 0); |
||||
/* If the sum had not been forgotten, adding 900 ms to the initial 100 ms would have triggered floor(). Verify
|
||||
* that this does not occur, since now full 1000 ms are required. We already added 500 ms above. */ |
||||
ADD_MILLISECS(400); |
||||
CHECK_RATE_CTRS(2, 1, 0); |
||||
/* Adding another 100 ms will trigger floor() */ |
||||
ADD_MILLISECS(99); |
||||
CHECK_RATE_CTRS(2, 1, 0); |
||||
ADD_MILLISECS(1); |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
|
||||
/* Test that durations of false below forget_sum_usec never trigger a forget */ |
||||
ADD_MILLISECS(300); |
||||
CHECK_RATE_CTRS(3, 1, 1); |
||||
/* internal counter is now at 0.3s above the last reported rate counter */ |
||||
FLAG(false); |
||||
ADD_MILLISECS(9999); |
||||
FLAG(true); |
||||
ADD_MILLISECS(25); |
||||
FLAG(false); |
||||
ADD_MILLISECS(9999); |
||||
FLAG(true); |
||||
ADD_MILLISECS(25); |
||||
FLAG(false); |
||||
ADD_MILLISECS(9999); |
||||
FLAG(true); |
||||
ADD_MILLISECS(25); |
||||
FLAG(false); |
||||
ADD_MILLISECS(9999); |
||||
FLAG(true); |
||||
ADD_MILLISECS(25); |
||||
/* internal counter is now at 0.4s above the last reported rate counter */ |
||||
CHECK_RATE_CTRS(3, 1, 1); |
||||
ADD_MILLISECS(100); |
||||
CHECK_RATE_CTRS(3, 2, 1); |
||||
ADD_MILLISECS(500); |
||||
CHECK_RATE_CTRS(3, 2, 2); |
||||
|
||||
/* Test that repeated time_cc_set_flag(false) does not cancel a forget_sum_usec */ |
||||
ADD_MILLISECS(300); |
||||
/* internal counter is now at 0.3s above the last reported rate counter */ |
||||
CHECK_RATE_CTRS(4, 2, 2); |
||||
FLAG(false); |
||||
ADD_MILLISECS(5000); |
||||
/* Repeat 'false', must not affect forget_sum_usec */ |
||||
FLAG(false); |
||||
ADD_MILLISECS(5000); |
||||
CHECK_RATE_CTRS(4, 2, 2); |
||||
/* 10 s have passed, forget_sum_usec has occurred.
|
||||
* Hence ceil() will trigger again right away: */ |
||||
FLAG(true); |
||||
ADD_MILLISECS(1); |
||||
CHECK_RATE_CTRS(5, 2, 2); |
||||
/* Adding 200 ms to the initial 300 ms would have triggered round(), but no more after forget_sum_usec */ |
||||
ADD_MILLISECS(199); |
||||
CHECK_RATE_CTRS(5, 2, 2); |
||||
/* Adding another 300 ms will trigger round() */ |
||||
ADD_MILLISECS(299); |
||||
CHECK_RATE_CTRS(5, 2, 2); |
||||
ADD_MILLISECS(1); |
||||
CHECK_RATE_CTRS(5, 3, 2); |
||||
/* Adding 700 ms to the initial 300 ms would have triggered ceil(), but no more after forget_sum_usec */ |
||||
ADD_MILLISECS(200); |
||||
CHECK_RATE_CTRS(5, 3, 2); |
||||
/* Adding another 300 ms will trigger ceil() */ |
||||
ADD_MILLISECS(299); |
||||
CHECK_RATE_CTRS(5, 3, 2); |
||||
ADD_MILLISECS(1); |
||||
CHECK_RATE_CTRS(5, 3, 3); |
||||
|
||||
my_obj_destruct(&my_obj); |
||||
rate_ctr_group_reset(my_ctrg); |
||||
|
||||
|
||||
/* Verify correctness when select() lags and runs timer callbacks too late */ |
||||
printf("\n----------- cumulating time, without forget_sum, when timer cb are invoked late\n\n"); |
||||
osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, 0, OSMO_TDEF_S); |
||||
now->tv_sec = 23000; |
||||
now->tv_nsec = 0; |
||||
osmo_gettimeofday_override_time = (struct timeval){23000, 0}; |
||||
|
||||
my_obj_init(&my_obj); |
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
|
||||
ADD_MILLISECS_NO_SELECT(100); |
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
|
||||
FLAG(true); |
||||
/* flag has just turned true the first time */ |
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
ADD_MILLISECS_NO_SELECT(100); |
||||
/* flag has been true for 0.1s */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS_NO_SELECT(100); |
||||
|
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
ADD_MILLISECS_NO_SELECT(100); |
||||
/* flag has been true for 0.2s */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS_NO_SELECT(300); |
||||
|
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
ADD_MILLISECS_NO_SELECT(799); |
||||
/* flag has been true for 0.999s */ |
||||
CHECK_RATE_CTRS(1, 1, 0); |
||||
ADD_MILLISECS_NO_SELECT(1); |
||||
/* flag has been true for 1.0s */ |
||||
CHECK_RATE_CTRS(1, 1, 1); |
||||
ADD_MILLISECS_NO_SELECT(300); |
||||
/* flag has been true for 1.3s */ |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
|
||||
ADD_MILLISECS_NO_SELECT(400); |
||||
|
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
ADD_MILLISECS_NO_SELECT(699); |
||||
/* flag has been true for 1.999s */ |
||||
CHECK_RATE_CTRS(2, 2, 1); |
||||
ADD_MILLISECS_NO_SELECT(1); |
||||
/* flag has been true for 2.0s */ |
||||
CHECK_RATE_CTRS(2, 2, 2); |
||||
ADD_MILLISECS_NO_SELECT(1); |
||||
/* flag has been true for 2.001s */ |
||||
CHECK_RATE_CTRS(3, 2, 2); |
||||
ADD_MILLISECS_NO_SELECT(499); |
||||
/* flag has been true for 2.5s */ |
||||
CHECK_RATE_CTRS(3, 3, 2); |
||||
ADD_MILLISECS_NO_SELECT(499); |
||||
/* flag has been true for 2.999s */ |
||||
CHECK_RATE_CTRS(3, 3, 2); |
||||
ADD_MILLISECS_NO_SELECT(1); |
||||
/* flag has been true for 3.0s */ |
||||
CHECK_RATE_CTRS(3, 3, 3); |
||||
ADD_MILLISECS_NO_SELECT(200); |
||||
/* flag has been true for 3.2s */ |
||||
CHECK_RATE_CTRS(4, 3, 3); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(4, 3, 3); |
||||
|
||||
ADD_MILLISECS_NO_SELECT(4321); |
||||
CHECK_RATE_CTRS(4, 3, 3); |
||||
|
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(4, 3, 3); |
||||
ADD_MILLISECS_NO_SELECT(5678); |
||||
CHECK_RATE_CTRS(9, 9, 8); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(9, 9, 8); |
||||
|
||||
my_obj_destruct(&my_obj); |
||||
rate_ctr_group_reset(my_ctrg); |
||||
|
||||
|
||||
printf("\n----------- test forget_sum, when timer cb are invoked late\n\n"); |
||||
osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, 10, OSMO_TDEF_S); |
||||
|
||||
now->tv_sec = 23000; |
||||
now->tv_nsec = 0; |
||||
osmo_gettimeofday_override_time = (struct timeval){23000, 0}; |
||||
|
||||
my_obj_init(&my_obj); |
||||
|
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
|
||||
FLAG(true); |
||||
/* flag has just turned true the first time */ |
||||
CHECK_RATE_CTRS(0, 0, 0); |
||||
ADD_MILLISECS_NO_SELECT(100); |
||||
/* flag has been true for 0.1s */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
FLAG(false); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS_NO_SELECT(1000); |
||||
/* 1 s of being false, forget_sum_usec has not yet occurred */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS_NO_SELECT(8999); |
||||
/* 9.999 s of being false, forget_sum_usec has not yet occurred */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
ADD_MILLISECS_NO_SELECT(1); |
||||
/* 10 s of being false, forget_sum_usec has occurred */ |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
|
||||
FLAG(true); |
||||
CHECK_RATE_CTRS(1, 0, 0); |
||||
ADD_MILLISECS_NO_SELECT(1); |
||||
/* Since previous sums were forgotton, ceil() triggers again */ |
||||
CHECK_RATE_CTRS(2, 0, 0); |
||||
/* If the sum had not been forgotten, adding 400 ms to the initial 100 ms would have triggered round(). Verify
|
||||
* that this does not occur, since now full 500 ms are required */ |
||||
ADD_MILLISECS_NO_SELECT(399); |
||||
CHECK_RATE_CTRS(2, 0, 0); |
||||
/* Adding another 100 ms will trigger round() */ |
||||
ADD_MILLISECS_NO_SELECT(99); |
||||
CHECK_RATE_CTRS(2, 0, 0); |
||||
ADD_MILLISECS_NO_SELECT(1); |
||||
CHECK_RATE_CTRS(2, 1, 0); |
||||
/* If the sum had not been forgotten, adding 900 ms to the initial 100 ms would have triggered floor(). Verify
|
||||
* that this does not occur, since now full 1000 ms are required. We already added 500 ms above. */ |
||||
ADD_MILLISECS_NO_SELECT(400); |
||||
CHECK_RATE_CTRS(2, 1, 0); |
||||
/* Adding another 100 ms will trigger floor() */ |
||||
ADD_MILLISECS_NO_SELECT(99); |
||||
CHECK_RATE_CTRS(2, 1, 0); |
||||
ADD_MILLISECS_NO_SELECT(1); |
||||
CHECK_RATE_CTRS(2, 1, 1); |
||||
|
||||
/* Test that durations of false below forget_sum_usec never trigger a forget */ |
||||
ADD_MILLISECS_NO_SELECT(300); |
||||
CHECK_RATE_CTRS(3, 1, 1); |
||||
/* internal counter is now at 0.3s above the last reported rate counter */ |
||||
FLAG(false); |
||||
ADD_MILLISECS_NO_SELECT(9999); |
||||
FLAG(true); |
||||
ADD_MILLISECS_NO_SELECT(25); |
||||
FLAG(false); |
||||
ADD_MILLISECS_NO_SELECT(9999); |
||||
FLAG(true); |
||||
ADD_MILLISECS_NO_SELECT(25); |
||||
FLAG(false); |
||||
ADD_MILLISECS_NO_SELECT(9999); |
||||
FLAG(true); |
||||
ADD_MILLISECS_NO_SELECT(25); |
||||
FLAG(false); |
||||
ADD_MILLISECS_NO_SELECT(9999); |
||||
FLAG(true); |
||||
ADD_MILLISECS_NO_SELECT(25); |
||||
/* internal counter is now at 0.4s above the last reported rate counter */ |
||||
CHECK_RATE_CTRS(3, 1, 1); |
||||
ADD_MILLISECS_NO_SELECT(100); |
||||
CHECK_RATE_CTRS(3, 2, 1); |
||||
ADD_MILLISECS_NO_SELECT(500); |
||||
CHECK_RATE_CTRS(3, 2, 2); |
||||
|
||||
my_obj_destruct(&my_obj); |
||||
rate_ctr_group_reset(my_ctrg); |
||||
|
||||
|
||||
#define SET_TDEFS(gran, round_thresh, forget_sum) do { \ |
||||
osmo_tdef_set(g_my_obj_tdefs, T_GRAN, gran, OSMO_TDEF_MS); \
|
||||
osmo_tdef_set(g_my_obj_tdefs, T_ROUND_THRESH, round_thresh, OSMO_TDEF_MS); \
|
||||
osmo_tdef_set(g_my_obj_tdefs, T_FORGET_SUM, forget_sum, OSMO_TDEF_S); \
|
||||
printf("T_defs: T_gran=%luusec T_round_threshold=%luusec T_forget_sum=%luusec\n", \
|
||||
osmo_tdef_get(g_my_obj_tdefs, T_GRAN, OSMO_TDEF_US, -1), \
|
||||
osmo_tdef_get(g_my_obj_tdefs, |