aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom/core/time_cc_rate_ctr.h
blob: 746ecf0cd6ed21b7aa2a35f0a6250657c6b67701 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* Report the cumulative counter of time for which a flag is true as rate counter. */
#pragma once

/*! Configuration for an osmo_time_cc_rate_ctr.
 * 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 osmo_time_cc_rate_ctr_set_flag().
 *
 * The granularity defines how much time one rate counter increment represents:
 * the "normal" configuration is gran_usec = 1000000, i.e. one rate counter increment represents one second.
 *
 * Reporting as rate counter is configurable by using either rate_ctr_early or rate_ctr_full,
 * and by setting a nonzero reset_sum_usec value.
 *
 * Examples:
 * - To see an increment for each gran_usec period where the flag was seen true, set reset_sum_usec = gran_usec and
 *   point rate_ctr_early at your rate_ctr instance.
 * - To see an increment only for those gran_usec periods where the flag was true the entire time, set
 *   reset_sum_usec = gran_usec and point rate_ctr_full at your rate_ctr instance (leave rate_ctr_early = NULL).
 * - To see an increment only when the cumulative time where the flag was true has surpassed another gran_usec step, no
 *   matter how long it takes to get there, set reset_sum_usec = 0 and use rate_ctr_full.
 *
 * Reporting modes in detail:
 *
 * - rate_ctr_early and rate_ctr_full report when the cumulative counter of time where the flag was true reaches a
 *   multiple of granularity period gran_usec, "early" at the start of a true flag, "full" only upon the sum reaching a full
 *   multiple of gran_usec.
 *
 *                 sum ^
 *                     |                                          ________
 *                     |                                         /
 *                     |                                        /
 *                     |                                       /
 *            3*gran --+--------------------------------------+
 *                     |                                     /:
 *                     |                                    / :
 *                     |                                   /  :
 *                     |                                  /   :
 *                     |                                 /    :
 *            2*gran --+--------------------------------+     :
 *                     |                               /:     :
 *                     |                              / :     :
 *                     |                    _________/  :     :
 *                     |                   /            :     :
 *                     |                  /             :     :
 *            1*gran --+-----------------+              :     :
 *                     |                /:              :     :
 *                     |               / :              :     :
 *                     |              /  :              :     :
 *                     |             /   :              :     :
 *                     | ....-------'    :              :     :
 *                  0  +---------+---------+---------+---------+---------+----------------------> elapsed time
 *                               1*gran  : 2*gran       :     :
 *                        _   _      _______          ___________
 *            flag:    __| |_| |____|    :  |________|  :     :  |__________
 *                     f t f t f    t    :  f        t  :     :  f
 *                       :               :              :     :
 *   rate_ctr_early:   0 1               2              3     4          = inc when the sum starts the next granularity
 *   rate_ctr_full:    0                 1              2     3          = inc when the sum becomes a full granularity
 *
 *
 * - The sum can be reset periodically by setting a nonzero reset_sum_usec value:
 *   For example, with reset_sum_usec = 2 * gran_usec:
 *
 *                 sum ^
 *                     |
 *            2*gran --+
 *                     |                                       /|
 *                     |                                      / |
 *                     |                                     /  |
 *                     |                   /|               /   |
 *                     |                  / |              /    |
 *            1*gran --+-----------------+--|-------------+     |
 *                     |                /:  |            /:     |
 *                     |               / :  |           / :     |
 *                     |              /  :  |          /  :     |  ___
 *                     |             /   :  |         /   :     | /
 *                     | ....-------'    :  |________/    :     |/
 *                  0  +---------+----------+---------+---------+-----> elapsed time
 *                               1*gran  :  2*gran        :     4*gran
 *                        _   _      ______           ____________
 *            flag:    __| |_| |____|    : |_________|    :     : |__________
 *                     f t f t f    t    : f         t    :     : f
 *                       :               :           :    :     :
 *   rate_ctr_early:   0 1               2           3    4     5
 *   rate_ctr_full:    0                 1                2
 *
 *   Like this,
 *   - rate_ctr_early increments once for each reset_sum_usec period in which the flag is seen true at any time,
 *     i.e. reports true flags quite sensitively, while guaranteeing a maximum of one increment per gran_usec.
 *   - rate_ctr_full increments only when there is a full gran_usec of "true" seen within one reset_sum_usec period,
 *     i.e. only reports counts for long durations of the flag being true, ignoring insignificantly short true flags.
 */
struct osmo_time_cc_rate_ctr_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 over which to accumulate for reporting, or zero to accumulate indefinitely.
	* When this value is nonzero, it should be >= gran_usec. */
	uint64_t reset_sum_usec;
	/*! Rate counter that reports every true flag seen, at most one per gran_usec period, or NULL to not use it. */
	struct rate_ctr *rate_ctr_early;
	/*! Rate counter that reports a count only for every full gran_usec duration of true flag, or NULL. */
	struct rate_ctr *rate_ctr_full;

	/*! Update gran_usec from this T-timer value, or zero to not use any T timer. */
	int T_gran_usec;
	/*! Update reset_sum_usec from this T-timer value, or zero to not use any T timer. */
	int T_reset_sum_usec;
	/*! Look up T_gran_usec and T_reset_sum_usec in this list of timers, or NULL to not use any T timers. */
	struct osmo_tdef *Tdefs;
};

/*! Report the cumulative counter of time for which a flag is true as rate counter.
 * See also osmo_time_cc_rate_ctr_cfg for details on configuring an osmo_time_cc_rate_ctr.
 *
 * Usage:
 *
 *     struct my_obj {
 *             struct osmo_time_cc_rate_ctr flag_cc;
 *     };
 *
 *     void my_obj_init(struct my_obj *my_obj)
 *     {
 *             my_obj->flag_cc.cfg = (struct osmo_time_cc_rate_ctr_cfg){
 *                             .gran_usec = 1000000,
 *                             .reset_sum_usec = 1000000,
 *                             .rate_ctr_early = rate_ctr_group_get_ctr(my_ctrg, MY_CTR_IDX),
 *                     };
 *             osmo_time_cc_rate_ctr_set_flag(&my_obj->flag_cc, false);
 *     }
 *
 *     void my_obj_event(struct my_obj *my_obj, bool flag)
 *     {
 *             osmo_time_cc_rate_ctr_set_flag(&my_obj->flag_cc, flag);
 *     }
 *
 *     void my_obj_destruct(struct my_obj *my_obj)
 *     {
 *             osmo_time_cc_rate_ctr_cleanup(&my_obj->flag_cc);
 *     }
 */
struct osmo_time_cc_rate_ctr {
	struct osmo_time_cc_rate_ctr_cfg cfg;

	struct osmo_timer_list timer;

	bool flag_state;
	uint64_t start_time;
	uint64_t last_counted_time;
	uint64_t last_reset_time;

	uint64_t total_sum;
	uint64_t sum;
	uint64_t reported_sum_early;
	uint64_t reported_sum_full;
};

void osmo_time_cc_rate_ctr_set_flag(struct osmo_time_cc_rate_ctr *tcr, bool flag);
void osmo_time_cc_rate_ctr_cleanup(struct osmo_time_cc_rate_ctr *tcr);