blob: c073a3e294ba5946fa7feab886a09f7219f08e50 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file stat_item.c
2 * utility routines for keeping conters about events and the event rates. */
3/*
4 * (C) 2015 by Sysmocom s.f.m.c. GmbH
Jacob Erlbeck9732cb42015-10-01 20:43:53 +02005 * (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
6 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010025/*! \addtogroup osmo_stat_item
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020026 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020027 * \file stat_item.c */
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020028
29#include <stdint.h>
30#include <string.h>
31
32#include <osmocom/core/utils.h>
33#include <osmocom/core/linuxlist.h>
34#include <osmocom/core/talloc.h>
35#include <osmocom/core/timer.h>
36#include <osmocom/core/stat_item.h>
37
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010038static LLIST_HEAD(osmo_stat_item_groups);
Jacob Erlbeckb27b3522015-10-12 18:47:09 +020039static int32_t global_value_id = 0;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020040
41static void *tall_stat_item_ctx;
42
Neels Hofmeyr87e45502017-06-20 00:17:59 +020043/*! Allocate a new group of counters according to description
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020044 * \param[in] ctx \ref talloc context
45 * \param[in] desc Statistics item group description
46 * \param[in] idx Index of new stat item group
47 */
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010048struct osmo_stat_item_group *osmo_stat_item_group_alloc(void *ctx,
49 const struct osmo_stat_item_group_desc *desc,
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020050 unsigned int idx)
51{
52 unsigned int group_size;
Harald Welteb32a1942015-11-20 10:22:14 +010053 unsigned long items_size = 0;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020054 unsigned int item_idx;
55 void *items;
56
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010057 struct osmo_stat_item_group *group;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020058
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010059 group_size = sizeof(struct osmo_stat_item_group) +
60 desc->num_items * sizeof(struct osmo_stat_item *);
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020061
62 if (!ctx)
63 ctx = tall_stat_item_ctx;
64
65 group = talloc_zero_size(ctx, group_size);
66 if (!group)
67 return NULL;
68
69 group->desc = desc;
70 group->idx = idx;
71
72 /* Get combined size of all items */
73 for (item_idx = 0; item_idx < desc->num_items; item_idx++) {
74 unsigned int size;
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010075 size = sizeof(struct osmo_stat_item) +
76 sizeof(struct osmo_stat_item_value) *
Jacob Erlbeckb27b3522015-10-12 18:47:09 +020077 desc->item_desc[item_idx].num_values;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020078 /* Align to pointer size */
79 size = (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
80
81 /* Store offsets into the item array */
82 group->items[item_idx] = (void *)items_size;
83
84 items_size += size;
85 }
86
87 items = talloc_zero_size(group, items_size);
88 if (!items) {
89 talloc_free(group);
90 return NULL;
91 }
92
93 /* Update item pointers */
94 for (item_idx = 0; item_idx < desc->num_items; item_idx++) {
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010095 struct osmo_stat_item *item = (struct osmo_stat_item *)
Harald Welteb32a1942015-11-20 10:22:14 +010096 ((uint8_t *)items + (unsigned long)group->items[item_idx]);
Jacob Erlbeck9732cb42015-10-01 20:43:53 +020097 unsigned int i;
98
99 group->items[item_idx] = item;
100 item->last_offs = desc->item_desc[item_idx].num_values - 1;
101 item->last_value_index = -1;
102 item->desc = &desc->item_desc[item_idx];
103
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200104 for (i = 0; i <= item->last_offs; i++) {
105 item->values[i].value = desc->item_desc[item_idx].default_value;
Jacob Erlbeckac4ed172015-12-08 10:29:16 +0100106 item->values[i].id = OSMO_STAT_ITEM_NOVALUE_ID;
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200107 }
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200108 }
109
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100110 llist_add(&group->list, &osmo_stat_item_groups);
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200111
112 return group;
113}
114
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200115/*! Free the memory for the specified group of counters */
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100116void osmo_stat_item_group_free(struct osmo_stat_item_group *grp)
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200117{
118 llist_del(&grp->list);
119 talloc_free(grp);
120}
121
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100122void osmo_stat_item_set(struct osmo_stat_item *item, int32_t value)
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200123{
124 item->last_offs += 1;
125 if (item->last_offs >= item->desc->num_values)
126 item->last_offs = 0;
127
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200128 global_value_id += 1;
Jacob Erlbeckac4ed172015-12-08 10:29:16 +0100129 if (global_value_id == OSMO_STAT_ITEM_NOVALUE_ID)
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200130 global_value_id += 1;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200131
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200132 item->values[item->last_offs].value = value;
133 item->values[item->last_offs].id = global_value_id;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200134}
135
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100136int osmo_stat_item_get_next(const struct osmo_stat_item *item, int32_t *next_idx,
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200137 int32_t *value)
138{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100139 const struct osmo_stat_item_value *next_value;
140 const struct osmo_stat_item_value *item_value = NULL;
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200141 int idx_delta;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200142 int next_offs;
143
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200144 next_offs = item->last_offs;
145 next_value = &item->values[next_offs];
146
147 while (next_value->id - *next_idx >= 0 &&
Jacob Erlbeckac4ed172015-12-08 10:29:16 +0100148 next_value->id != OSMO_STAT_ITEM_NOVALUE_ID)
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200149 {
150 item_value = next_value;
151
152 next_offs -= 1;
153 if (next_offs < 0)
154 next_offs = item->desc->num_values - 1;
155 if (next_offs == item->last_offs)
156 break;
157 next_value = &item->values[next_offs];
158 }
159
160 if (!item_value)
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200161 /* All items have been read */
162 return 0;
163
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200164 *value = item_value->value;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200165
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200166 idx_delta = item_value->id + 1 - *next_idx;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200167
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200168 *next_idx = item_value->id + 1;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200169
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200170 return idx_delta;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200171}
172
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200173/*! Skip all values of this item and update idx accordingly */
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100174int osmo_stat_item_discard(const struct osmo_stat_item *item, int32_t *idx)
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200175{
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200176 int discarded = item->values[item->last_offs].id + 1 - *idx;
177 *idx = item->values[item->last_offs].id + 1;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200178
179 return discarded;
180}
181
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200182/*! Skip all values of all items and update idx accordingly */
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100183int osmo_stat_item_discard_all(int32_t *idx)
Jacob Erlbeckb27b3522015-10-12 18:47:09 +0200184{
185 int discarded = global_value_id + 1 - *idx;
186 *idx = global_value_id + 1;
187
188 return discarded;
189}
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200190
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200191/*! Initialize the stat item module */
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100192int osmo_stat_item_init(void *tall_ctx)
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200193{
194 tall_stat_item_ctx = tall_ctx;
195
196 return 0;
197}
198
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200199/*! Search for item group based on group name and index */
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100200struct osmo_stat_item_group *osmo_stat_item_get_group_by_name_idx(
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200201 const char *name, const unsigned int idx)
202{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100203 struct osmo_stat_item_group *statg;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200204
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100205 llist_for_each_entry(statg, &osmo_stat_item_groups, list) {
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200206 if (!statg->desc)
207 continue;
208
209 if (!strcmp(statg->desc->group_name_prefix, name) &&
210 statg->idx == idx)
211 return statg;
212 }
213 return NULL;
214}
215
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200216/*! Search for item group based on group name */
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100217const struct osmo_stat_item *osmo_stat_item_get_by_name(
218 const struct osmo_stat_item_group *statg, const char *name)
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200219{
220 int i;
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100221 const struct osmo_stat_item_desc *item_desc;
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200222
223 if (!statg->desc)
224 return NULL;
225
226 for (i = 0; i < statg->desc->num_items; i++) {
227 item_desc = &statg->desc->item_desc[i];
228
229 if (!strcmp(item_desc->name, name)) {
230 return statg->items[i];
231 }
232 }
233 return NULL;
234}
235
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100236int osmo_stat_item_for_each_item(struct osmo_stat_item_group *statg,
237 osmo_stat_item_handler_t handle_item, void *data)
Jacob Erlbeckc6a71082015-10-19 14:04:38 +0200238{
239 int rc = 0;
240 int i;
241
242 for (i = 0; i < statg->desc->num_items; i++) {
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100243 struct osmo_stat_item *item = statg->items[i];
Jacob Erlbeckc6a71082015-10-19 14:04:38 +0200244 rc = handle_item(statg, item, data);
245 if (rc < 0)
246 return rc;
247 }
248
249 return rc;
250}
251
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100252int osmo_stat_item_for_each_group(osmo_stat_item_group_handler_t handle_group, void *data)
Jacob Erlbeckc6a71082015-10-19 14:04:38 +0200253{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100254 struct osmo_stat_item_group *statg;
Jacob Erlbeckc6a71082015-10-19 14:04:38 +0200255 int rc = 0;
256
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100257 llist_for_each_entry(statg, &osmo_stat_item_groups, list) {
Jacob Erlbeckc6a71082015-10-19 14:04:38 +0200258 rc = handle_group(statg, data);
259 if (rc < 0)
260 return rc;
261 }
262
263 return rc;
264}
265
Jacob Erlbeck9732cb42015-10-01 20:43:53 +0200266/*! @} */