blob: 2985bbb0ed58bf1fb6451900e4f2c9f72ea7bcad [file] [log] [blame]
Harald Welte7b45d602010-05-13 11:35:30 +02001/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
2 *
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
Harald Welte9327c6d2011-08-17 16:06:06 +020021/*! \addtogroup rate_ctr
22 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020023 * Counters about events and their event rates.
24 *
25 * \file rate_ctr.c */
Harald Welte9327c6d2011-08-17 16:06:06 +020026
Harald Welte7b45d602010-05-13 11:35:30 +020027#include <stdint.h>
Harald Welte7b45d602010-05-13 11:35:30 +020028#include <string.h>
29
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010030#include <osmocom/core/utils.h>
31#include <osmocom/core/linuxlist.h>
32#include <osmocom/core/talloc.h>
33#include <osmocom/core/timer.h>
34#include <osmocom/core/rate_ctr.h>
Harald Welte7b45d602010-05-13 11:35:30 +020035
36static LLIST_HEAD(rate_ctr_groups);
37
38static void *tall_rate_ctr_ctx;
39
Neels Hofmeyr87e45502017-06-20 00:17:59 +020040/*! Allocate a new group of counters according to description
Harald Welte9327c6d2011-08-17 16:06:06 +020041 * \param[in] ctx \ref talloc context
42 * \param[in] desc Rate counter group description
43 * \param[in] idx Index of new counter group
44 */
Harald Welte7b45d602010-05-13 11:35:30 +020045struct rate_ctr_group *rate_ctr_group_alloc(void *ctx,
46 const struct rate_ctr_group_desc *desc,
47 unsigned int idx)
48{
49 unsigned int size;
50 struct rate_ctr_group *group;
51
52 size = sizeof(struct rate_ctr_group) +
53 desc->num_ctr * sizeof(struct rate_ctr);
54
55 if (!ctx)
56 ctx = tall_rate_ctr_ctx;
57
58 group = talloc_zero_size(ctx, size);
59 if (!group)
60 return NULL;
61
62 group->desc = desc;
Harald Welte087fcff2010-05-13 12:16:17 +020063 group->idx = idx;
Harald Welte7b45d602010-05-13 11:35:30 +020064
65 llist_add(&group->list, &rate_ctr_groups);
66
67 return group;
68}
69
Neels Hofmeyr87e45502017-06-20 00:17:59 +020070/*! Free the memory for the specified group of counters */
Harald Welte7b45d602010-05-13 11:35:30 +020071void rate_ctr_group_free(struct rate_ctr_group *grp)
72{
73 llist_del(&grp->list);
74 talloc_free(grp);
75}
76
Neels Hofmeyr87e45502017-06-20 00:17:59 +020077/*! Add a number to the counter */
Harald Welte7b45d602010-05-13 11:35:30 +020078void rate_ctr_add(struct rate_ctr *ctr, int inc)
79{
80 ctr->current += inc;
81}
82
Neels Hofmeyr87e45502017-06-20 00:17:59 +020083/*! Return the counter difference since the last call to this function */
Jacob Erlbeck423c1e52015-10-19 13:45:42 +020084int64_t rate_ctr_difference(struct rate_ctr *ctr)
85{
86 int64_t result = ctr->current - ctr->previous;
87 ctr->previous = ctr->current;
88
89 return result;
90}
91
Jacob Erlbeckee702cd2015-11-10 11:38:25 +010092/* TODO: support update intervals > 1s */
93/* TODO: implement this as a special stats reporter */
94
Harald Welte7b45d602010-05-13 11:35:30 +020095static void interval_expired(struct rate_ctr *ctr, enum rate_ctr_intv intv)
96{
97 /* calculate rate over last interval */
98 ctr->intv[intv].rate = ctr->current - ctr->intv[intv].last;
99 /* save current counter for next interval */
100 ctr->intv[intv].last = ctr->current;
Harald Welted2dce6d2010-05-13 13:28:12 +0200101
102 /* update the rate of the next bigger interval. This will
103 * be overwritten when that next larger interval expires */
104 if (intv + 1 < ARRAY_SIZE(ctr->intv))
105 ctr->intv[intv+1].rate += ctr->intv[intv].rate;
Harald Welte7b45d602010-05-13 11:35:30 +0200106}
107
Pablo Neira Ayuso0b21c1c2011-05-07 12:42:28 +0200108static struct osmo_timer_list rate_ctr_timer;
Harald Welte7b45d602010-05-13 11:35:30 +0200109static uint64_t timer_ticks;
110
111/* The one-second interval has expired */
112static void rate_ctr_group_intv(struct rate_ctr_group *grp)
113{
114 unsigned int i;
115
116 for (i = 0; i < grp->desc->num_ctr; i++) {
117 struct rate_ctr *ctr = &grp->ctr[i];
118
119 interval_expired(ctr, RATE_CTR_INTV_SEC);
120 if ((timer_ticks % 60) == 0)
121 interval_expired(ctr, RATE_CTR_INTV_MIN);
122 if ((timer_ticks % (60*60)) == 0)
123 interval_expired(ctr, RATE_CTR_INTV_HOUR);
124 if ((timer_ticks % (24*60*60)) == 0)
125 interval_expired(ctr, RATE_CTR_INTV_DAY);
126 }
127}
128
129static void rate_ctr_timer_cb(void *data)
130{
131 struct rate_ctr_group *ctrg;
132
133 /* Increment number of ticks before we calculate intervals,
134 * as a counter value of 0 would already wrap all counters */
135 timer_ticks++;
136
137 llist_for_each_entry(ctrg, &rate_ctr_groups, list)
138 rate_ctr_group_intv(ctrg);
139
Pablo Neira Ayuso0b21c1c2011-05-07 12:42:28 +0200140 osmo_timer_schedule(&rate_ctr_timer, 1, 0);
Harald Welte7b45d602010-05-13 11:35:30 +0200141}
142
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200143/*! Initialize the counter module */
Harald Welte7b45d602010-05-13 11:35:30 +0200144int rate_ctr_init(void *tall_ctx)
145{
146 tall_rate_ctr_ctx = tall_ctx;
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +0200147 osmo_timer_setup(&rate_ctr_timer, rate_ctr_timer_cb, NULL);
Pablo Neira Ayuso0b21c1c2011-05-07 12:42:28 +0200148 osmo_timer_schedule(&rate_ctr_timer, 1, 0);
Harald Welte7b45d602010-05-13 11:35:30 +0200149
150 return 0;
151}
Daniel Willmann2d42dde2011-04-08 10:46:18 +0200152
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200153/*! Search for counter group based on group name and index
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200154 * \param[in] name Name of the counter group you're looking for
155 * \param[in] idx Index inside the counter group
156 * \returns \ref rate_ctr_group or NULL in case of error */
Daniel Willmann2d42dde2011-04-08 10:46:18 +0200157struct rate_ctr_group *rate_ctr_get_group_by_name_idx(const char *name, const unsigned int idx)
158{
159 struct rate_ctr_group *ctrg;
160
161 llist_for_each_entry(ctrg, &rate_ctr_groups, list) {
162 if (!ctrg->desc)
163 continue;
164
165 if (!strcmp(ctrg->desc->group_name_prefix, name) &&
166 ctrg->idx == idx) {
167 return ctrg;
168 }
169 }
170 return NULL;
171}
172
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200173/*! Search for counter based on group + name
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200174 * \param[in] ctrg pointer to \ref rate_ctr_group
175 * \param[in] name name of counter inside group
176 * \returns \ref rate_ctr or NULL in caes of error
177 */
Holger Hans Peter Freythera9f526a2011-04-18 16:45:45 +0200178const struct rate_ctr *rate_ctr_get_by_name(const struct rate_ctr_group *ctrg, const char *name)
Daniel Willmann2d42dde2011-04-08 10:46:18 +0200179{
180 int i;
Holger Hans Peter Freythera9f526a2011-04-18 16:45:45 +0200181 const struct rate_ctr_desc *ctr_desc;
Daniel Willmann2d42dde2011-04-08 10:46:18 +0200182
183 if (!ctrg->desc)
184 return NULL;
185
186 for (i = 0; i < ctrg->desc->num_ctr; i++) {
187 ctr_desc = &ctrg->desc->ctr_desc[i];
188
189 if (!strcmp(ctr_desc->name, name)) {
190 return &ctrg->ctr[i];
191 }
192 }
193 return NULL;
194}
Harald Welte9327c6d2011-08-17 16:06:06 +0200195
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200196/*! Iterate over each counter in group and call function
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200197 * \param[in] counter group over whose counter to iterate
198 * \param[in] handle_counter function pointer
199 * \param[in] data Data to hand transparently to \ref handle_counter
200 * \returns 0 on success; negative otherwise
201 */
Jacob Erlbeck423c1e52015-10-19 13:45:42 +0200202int rate_ctr_for_each_counter(struct rate_ctr_group *ctrg,
203 rate_ctr_handler_t handle_counter, void *data)
204{
205 int rc = 0;
206 int i;
207
208 for (i = 0; i < ctrg->desc->num_ctr; i++) {
209 struct rate_ctr *ctr = &ctrg->ctr[i];
210 rc = handle_counter(ctrg,
211 ctr, &ctrg->desc->ctr_desc[i], data);
212 if (rc < 0)
213 return rc;
214 }
215
216 return rc;
217}
218
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200219/*! Iterate over all counter groups
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200220 * \param[in] handle_group function pointer of callback function
221 * \param[in] data Data to hand transparently to \ref handle_group
222 * \returns 0 on success; negative otherwise
223 */
Jacob Erlbeck423c1e52015-10-19 13:45:42 +0200224int rate_ctr_for_each_group(rate_ctr_group_handler_t handle_group, void *data)
225{
226 struct rate_ctr_group *statg;
227 int rc = 0;
228
229 llist_for_each_entry(statg, &rate_ctr_groups, list) {
230 rc = handle_group(statg, data);
231 if (rc < 0)
232 return rc;
233 }
234
235 return rc;
236}
237
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200238/*! @} */