Browse code

Copy statistics files from kamailio into libkcore

Jan Janak authored on 10/03/2009 23:02:11
Showing 2 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,502 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2006 Voice Sistem SRL
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
+ *
22
+ *
23
+ * History:
24
+ * ---------
25
+ *  2006-01-16  first version (bogdan)
26
+ *  2006-11-28  added get_stat_var_from_num_code() (Jeffrey Magder -
27
+ *              SOMA Networks)
28
+ */
29
+
30
+/*!
31
+ * \file
32
+ * \brief Statistics support
33
+ */
34
+
35
+
36
+#include <string.h>
37
+
38
+#include "mem/shm_mem.h"
39
+#include "mi/mi.h"
40
+#include "ut.h"
41
+#include "dprint.h"
42
+#include "locking.h"
43
+#include "core_stats.h"
44
+#include "statistics.h"
45
+
46
+#ifdef STATISTICS
47
+
48
+static stats_collector *collector;
49
+
50
+static struct mi_root *mi_get_stats(struct mi_root *cmd, void *param);
51
+static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param);
52
+
53
+static mi_export_t mi_stat_cmds[] = {
54
+	{ "get_statistics",    mi_get_stats,    0  ,  0,  0 },
55
+	{ "reset_statistics",  mi_reset_stats,  0  ,  0,  0 },
56
+	{ 0, 0, 0, 0, 0}
57
+};
58
+
59
+
60
+
61
+#ifdef NO_ATOMIC_OPS
62
+#warning STATISTICS: Architecture with no support for atomic operations. \
63
+         Using Locks!!
64
+gen_lock_t *stat_lock = 0;
65
+#endif
66
+
67
+#define stat_hash(_s) core_hash( _s, 0, STATS_HASH_SIZE)
68
+
69
+
70
+
71
+/*! \brief
72
+ * Returns the statistic associated with 'numerical_code' and 'out_codes'.
73
+ * Specifically:
74
+ *
75
+ *  - if out_codes is nonzero, then the stat_var for the number of messages 
76
+ *    _sent out_ with the 'numerical_code' will be returned if it exists.
77
+ *  - otherwise, the stat_var for the number of messages _received_ with the 
78
+ *    'numerical_code' will be returned, if the stat exists. 
79
+ */
80
+stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int out_codes)
81
+{
82
+	static char msg_code[INT2STR_MAX_LEN+4];
83
+	str stat_name;
84
+
85
+	stat_name.s = int2bstr( (unsigned long)numerical_code, msg_code, 
86
+		&stat_name.len);
87
+	stat_name.s[stat_name.len++] = '_';
88
+
89
+	if (out_codes) {
90
+		stat_name.s[stat_name.len++] = 'o';
91
+		stat_name.s[stat_name.len++] = 'u';
92
+		stat_name.s[stat_name.len++] = 't';
93
+	} else {
94
+		stat_name.s[stat_name.len++] = 'i';
95
+		stat_name.s[stat_name.len++] = 'n';
96
+	}
97
+
98
+	return get_stat(&stat_name);
99
+}
100
+
101
+
102
+
103
+int init_stats_collector(void)
104
+{
105
+	/* init the collector */
106
+	collector = (stats_collector*)shm_malloc(sizeof(stats_collector));
107
+	if (collector==0) {
108
+		LM_ERR("no more shm mem\n");
109
+		goto error;
110
+	}
111
+	memset( collector, 0 , sizeof(stats_collector));
112
+
113
+#ifdef NO_ATOMIC_OPS
114
+	/* init BIG (really BIG) lock */
115
+	stat_lock = lock_alloc();
116
+	if (stat_lock==0 || lock_init( stat_lock )==0 ) {
117
+		LM_ERR("failed to init the really BIG lock\n");
118
+		goto error;
119
+	}
120
+#endif
121
+
122
+	/* register MI commands */
123
+	if (register_mi_mod( "statistics", mi_stat_cmds)<0) {
124
+		LM_ERR("unable to register MI cmds\n");
125
+		goto error;
126
+	}
127
+
128
+	/* register core statistics */
129
+	if (register_module_stats( "core", core_stats)!=0 ) {
130
+		LM_ERR("failed to register core statistics\n");
131
+		goto error;
132
+	}
133
+	/* register sh_mem statistics */
134
+	if (register_module_stats( "shmem", shm_stats)!=0 ) {
135
+		LM_ERR("failed to register sh_mem statistics\n");
136
+		goto error;
137
+	}
138
+	LM_DBG("statistics manager successfully initialized\n");
139
+
140
+	return 0;
141
+error:
142
+	return -1;
143
+}
144
+
145
+
146
+void destroy_stats_collector(void)
147
+{
148
+	stat_var *stat;
149
+	stat_var *tmp_stat;
150
+	int i;
151
+
152
+#ifdef NO_ATOMIC_OPS
153
+	/* destroy big lock */
154
+	if (stat_lock)
155
+		lock_destroy( stat_lock );
156
+#endif
157
+
158
+	if (collector) {
159
+		/* destroy hash table */
160
+		for( i=0 ; i<STATS_HASH_SIZE ; i++ ) {
161
+			for( stat=collector->hstats[i] ; stat ; ) {
162
+				tmp_stat = stat;
163
+				stat = stat->hnext;
164
+				if ((tmp_stat->flags&STAT_IS_FUNC)==0 && tmp_stat->u.val)
165
+					shm_free(tmp_stat->u.val);
166
+				if ( (tmp_stat->flags&STAT_SHM_NAME) && tmp_stat->name.s)
167
+					shm_free(tmp_stat->name.s);
168
+				shm_free(tmp_stat);
169
+			}
170
+		}
171
+
172
+		/* destroy sts_module array */
173
+		if (collector->amodules)
174
+			shm_free(collector->amodules);
175
+
176
+		/* destroy the collector */
177
+		shm_free(collector);
178
+	}
179
+
180
+	return;
181
+}
182
+
183
+
184
+static inline module_stats* get_stat_module( str *module)
185
+{
186
+	int i;
187
+
188
+	if ( (module==0) || module->s==0 || module->len==0 )
189
+		return 0;
190
+
191
+	for( i=0 ; i<collector->mod_no ; i++ ) {
192
+		if ( (collector->amodules[i].name.len == module->len) &&
193
+		(strncasecmp(collector->amodules[i].name.s,module->s,module->len)==0) )
194
+			return &collector->amodules[i];
195
+	}
196
+
197
+	return 0;
198
+}
199
+
200
+
201
+static inline module_stats* add_stat_module( char *module)
202
+{
203
+	module_stats *amods;
204
+	module_stats *mods;
205
+	int len;
206
+
207
+	if ( (module==0) || ((len = strlen(module))==0 ) )
208
+		return 0;
209
+
210
+	amods = (module_stats*)shm_realloc( collector->amodules,
211
+			(collector->mod_no+1)*sizeof(module_stats) );
212
+	if (amods==0) {
213
+		LM_ERR("no more shm memory\n");
214
+		return 0;
215
+	}
216
+
217
+	collector->amodules = amods;
218
+	collector->mod_no++;
219
+
220
+	mods = &amods[collector->mod_no-1];
221
+	memset( mods, 0, sizeof(module_stats) );
222
+
223
+	mods->name.s = module;
224
+	mods->name.len = len;
225
+
226
+	return mods;
227
+}
228
+
229
+
230
+int register_stat( char *module, char *name, stat_var **pvar, int flags)
231
+{
232
+	module_stats* mods;
233
+	stat_var *stat;
234
+	stat_var *it;
235
+	str smodule;
236
+	int hash;
237
+
238
+	if (module==0 || name==0 || pvar==0) {
239
+		LM_ERR("invalid parameters module=%p, name=%p, pvar=%p \n", 
240
+				module, name, pvar);
241
+		goto error;
242
+	}
243
+
244
+	stat = (stat_var*)shm_malloc(sizeof(stat_var));
245
+	if (stat==0) {
246
+		LM_ERR("no more shm memory\n");
247
+		goto error;
248
+	}
249
+	memset( stat, 0, sizeof(stat_var));
250
+
251
+	if ( (flags&STAT_IS_FUNC)==0 ) {
252
+		stat->u.val = (stat_val*)shm_malloc(sizeof(stat_val));
253
+		if (stat->u.val==0) {
254
+			LM_ERR("no more shm memory\n");
255
+			goto error1;
256
+		}
257
+#ifdef NO_ATOMIC_OPS
258
+		*(stat->u.val) = 0;
259
+#else
260
+		atomic_set(stat->u.val,0);
261
+#endif
262
+		*pvar = stat;
263
+	} else {
264
+		stat->u.f = (stat_function)(pvar);
265
+	}
266
+
267
+	/* is the module already recorded? */
268
+	smodule.s = module;
269
+	smodule.len = strlen(module);
270
+	mods = get_stat_module(&smodule);
271
+	if (mods==0) {
272
+		mods = add_stat_module(module);
273
+		if (mods==0) {
274
+			LM_ERR("failed to add new module\n");
275
+			goto error2;
276
+		}
277
+	}
278
+
279
+	/* fill the stat record */
280
+	stat->mod_idx = collector->mod_no-1;
281
+
282
+	stat->name.s = name;
283
+	stat->name.len = strlen(name);
284
+	stat->flags = flags;
285
+
286
+
287
+	/* compute the hash by name */
288
+	hash = stat_hash( &stat->name );
289
+
290
+	/* link it */
291
+	if (collector->hstats[hash]==0) {
292
+		collector->hstats[hash] = stat;
293
+	} else {
294
+		it = collector->hstats[hash];
295
+		while(it->hnext)
296
+			it = it->hnext;
297
+		it->hnext = stat;
298
+	}
299
+	collector->stats_no++;
300
+
301
+	/* add the statistic also to the module statistic list */
302
+	if (mods->tail) {
303
+		mods->tail->lnext = stat;
304
+	} else {
305
+		mods->head = stat;
306
+	}
307
+	mods->tail = stat;
308
+	mods->no++;
309
+
310
+	return 0;
311
+error2:
312
+	if ( (flags&STAT_IS_FUNC)==0 ) {
313
+		shm_free(*pvar);
314
+		*pvar = 0;
315
+	}
316
+error1:
317
+	shm_free(stat);
318
+error:
319
+	*pvar = 0;
320
+	return -1;
321
+}
322
+
323
+
324
+
325
+int register_module_stats(char *module, stat_export_t *stats)
326
+{
327
+	int ret;
328
+
329
+	if (module==0 || module[0]==0 || !stats || !stats[0].name)
330
+		return 0;
331
+
332
+	for( ; stats->name ; stats++) {
333
+		ret = register_stat( module, stats->name, stats->stat_pointer,
334
+			stats->flags);
335
+		if (ret!=0) {
336
+			LM_CRIT("failed to add statistic\n");
337
+			return -1;
338
+		}
339
+	}
340
+
341
+	return 0;
342
+}
343
+
344
+
345
+
346
+stat_var* get_stat( str *name )
347
+{
348
+	stat_var *stat;
349
+	int hash;
350
+
351
+	if (name==0 || name->s==0 || name->len==0)
352
+		return 0;
353
+
354
+	/* compute the hash by name */
355
+	hash = stat_hash( name );
356
+
357
+	/* and look for it */
358
+	for( stat=collector->hstats[hash] ; stat ; stat=stat->hnext ) {
359
+		if ( (stat->name.len==name->len) &&
360
+		(strncasecmp( stat->name.s, name->s, name->len)==0) )
361
+			return stat;
362
+	}
363
+
364
+	return 0;
365
+}
366
+
367
+
368
+
369
+/***************************** MI STUFF ********************************/
370
+
371
+inline static int mi_add_stat(struct mi_node *rpl, stat_var *stat)
372
+{
373
+	struct mi_node *node;
374
+
375
+	node = addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu",
376
+		collector->amodules[stat->mod_idx].name.len,
377
+		collector->amodules[stat->mod_idx].name.s,
378
+		stat->name.len, stat->name.s,
379
+		get_stat_val(stat) );
380
+
381
+	if (node==0)
382
+		return -1;
383
+	return 0;
384
+}
385
+
386
+inline static int mi_add_module_stats(struct mi_node *rpl,
387
+													module_stats *mods)
388
+{
389
+	struct mi_node *node;
390
+	stat_var *stat;
391
+
392
+	for( stat=mods->head ; stat ; stat=stat->lnext) {
393
+		node = addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu",
394
+			mods->name.len, mods->name.s,
395
+			stat->name.len, stat->name.s,
396
+			get_stat_val(stat) );
397
+		if (node==0)
398
+			return -1;
399
+	}
400
+	return 0;
401
+}
402
+
403
+
404
+static struct mi_root *mi_get_stats(struct mi_root *cmd, void *param)
405
+{
406
+	struct mi_root *rpl_tree;
407
+	struct mi_node *rpl;
408
+	struct mi_node *arg;
409
+	module_stats   *mods;
410
+	stat_var       *stat;
411
+	str val;
412
+	int i;
413
+
414
+	if (cmd->node.kids==NULL)
415
+		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
416
+
417
+	rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
418
+	if (rpl_tree==0)
419
+		return 0;
420
+	rpl = &rpl_tree->node;
421
+
422
+	for( arg=cmd->node.kids ; arg ; arg=arg->next) {
423
+		if (arg->value.len==0)
424
+			continue;
425
+
426
+		val = arg->value;
427
+
428
+		if ( val.len==3 && memcmp(val.s,"all",3)==0) {
429
+			/* add all statistic variables */
430
+			for( i=0 ; i<collector->mod_no ;i++ ) {
431
+				if (mi_add_module_stats( rpl, &collector->amodules[i] )!=0)
432
+					goto error;
433
+			}
434
+		} else if ( val.len>1 && val.s[val.len-1]==':') {
435
+			/* add module statistics */
436
+			val.len--;
437
+			mods = get_stat_module( &val );
438
+			if (mods==0)
439
+				continue;
440
+			if (mi_add_module_stats( rpl, mods )!=0)
441
+				goto error;
442
+		} else {
443
+			/* add only one statistic */
444
+			stat = get_stat( &val );
445
+			if (stat==0)
446
+				continue;
447
+			if (mi_add_stat(rpl,stat)!=0)
448
+				goto error;
449
+		}
450
+	}
451
+
452
+	if (rpl->kids==0) {
453
+		free_mi_tree(rpl_tree);
454
+		return init_mi_tree( 404, "Statistics Not Found", 20);
455
+	}
456
+
457
+	return rpl_tree;
458
+error:
459
+	free_mi_tree(rpl_tree);
460
+	return 0;
461
+}
462
+
463
+
464
+
465
+static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param)
466
+{
467
+	struct mi_root *rpl_tree;
468
+	struct mi_node *arg;
469
+	stat_var       *stat;
470
+	int found;
471
+
472
+	if (cmd->node.kids==NULL)
473
+		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
474
+
475
+	rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
476
+	if (rpl_tree==0)
477
+		return 0;
478
+	found = 0;
479
+
480
+	for( arg=cmd->node.kids ; arg ; arg=arg->next) {
481
+		if (arg->value.len==0)
482
+			continue;
483
+
484
+		stat = get_stat( &arg->value );
485
+		if (stat==0)
486
+			continue;
487
+
488
+		reset_stat( stat );
489
+		found = 1;
490
+	}
491
+
492
+	if (!found) {
493
+		free_mi_tree(rpl_tree);
494
+		return init_mi_tree( 404, "Statistics Not Found", 20);
495
+	}
496
+
497
+	return rpl_tree;
498
+}
499
+
500
+
501
+#endif /*STATISTICS*/
502
+
0 503
new file mode 100644
... ...
@@ -0,0 +1,199 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2006 Voice Sistem SRL
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
+ *
22
+ * History:
23
+ * ---------
24
+ *  2006-01-16  first version (bogdan)
25
+ *  2006-11-28  added get_stat_var_from_num_code() (Jeffrey Magder -
26
+ *              SOMA Networks)
27
+ */
28
+
29
+/*!
30
+ * \file
31
+ * \brief Kamailio statistics handling
32
+ */
33
+
34
+
35
+#ifndef _STATISTICS_H_
36
+#define _STATISTICS_H_
37
+
38
+#include "hash_func.h"
39
+#include "atomic.h"
40
+
41
+#define STATS_HASH_POWER   8
42
+#define STATS_HASH_SIZE    (1<<(STATS_HASH_POWER))
43
+
44
+
45
+#define STAT_NO_RESET  (1<<0)
46
+#define STAT_NO_SYNC   (1<<1)
47
+#define STAT_SHM_NAME  (1<<2)
48
+#define STAT_IS_FUNC   (1<<3)
49
+
50
+#ifdef NO_ATOMIC_OPS
51
+typedef unsigned int stat_val;
52
+#else
53
+typedef atomic_t stat_val;
54
+#endif
55
+
56
+typedef unsigned long (*stat_function)(void);
57
+
58
+struct module_stats_;
59
+
60
+typedef struct stat_var_{
61
+	unsigned int mod_idx;
62
+	str name;
63
+	int flags;
64
+	union{
65
+		stat_val *val;
66
+		stat_function f;
67
+	}u;
68
+	struct stat_var_ *hnext;
69
+	struct stat_var_ *lnext;
70
+} stat_var;
71
+
72
+typedef struct module_stats_ {
73
+	str name;
74
+	int no;
75
+	stat_var *head;
76
+	stat_var *tail;
77
+} module_stats;
78
+
79
+typedef struct stats_collector_ {
80
+	int stats_no;
81
+	int mod_no;
82
+	stat_var* hstats[STATS_HASH_SIZE];
83
+	module_stats *amodules;
84
+}stats_collector;
85
+
86
+typedef struct stat_export_ {
87
+	char* name;                /* null terminated statistic name */
88
+	int flags;                 /* flags */
89
+	stat_var** stat_pointer;   /* pointer to the variable's mem location *
90
+	                            * NOTE - it's in shm mem */
91
+} stat_export_t;
92
+
93
+
94
+#ifdef STATISTICS
95
+int init_stats_collector(void);
96
+
97
+void destroy_stats_collector(void);
98
+
99
+int register_stat( char *module, char *name, stat_var **pvar, int flags);
100
+
101
+int register_module_stats(char *module, stat_export_t *stats);
102
+
103
+stat_var* get_stat( str *name );
104
+
105
+unsigned int get_stat_val( stat_var *var );
106
+
107
+/*! \brief
108
+ * Returns the statistic associated with 'numerical_code' and 'is_a_reply'.
109
+ * Specifically:
110
+ *
111
+ *  - if in_codes is nonzero, then the stat_var for the number of messages 
112
+ *    _received_ with the 'numerical_code' will be returned if it exists.
113
+ *  - otherwise, the stat_var for the number of messages _sent_ with the 
114
+ *    'numerical_code' will be returned, if the stat exists. 
115
+ */
116
+stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int in_codes);
117
+
118
+
119
+#ifdef NO_ATOMIC_OPS
120
+#include "locking.h"
121
+extern gen_lock_t *stat_lock;
122
+#endif
123
+
124
+#else
125
+	#define init_stats_collector()  0
126
+	#define destroy_stats_collector()
127
+	#define register_module_stats(_mod,_stats) 0
128
+	#define register_stat( _mod, _name, _pvar, _flags) 0
129
+	#define get_stat( _name )  0
130
+	#define get_stat_val( _var ) 0
131
+	#define get_stat_var_from_num_code( _n_code, _in_code) NULL
132
+#endif
133
+
134
+
135
+#ifdef STATISTICS
136
+	#ifdef NO_ATOMIC_OPS
137
+		#define update_stat( _var, _n) \
138
+			do { \
139
+				if ( !((_var)->flags&STAT_IS_FUNC) ) {\
140
+					if ((_var)->flags&STAT_NO_SYNC) {\
141
+						*((_var)->u.val) += _n;\
142
+					} else {\
143
+						lock_get(stat_lock);\
144
+						*((_var)->u.val) += _n;\
145
+						lock_release(stat_lock);\
146
+					}\
147
+				}\
148
+			}while(0)
149
+		#define reset_stat( _var) \
150
+			do { \
151
+				if ( ((_var)->flags&(STAT_NO_RESET|STAT_IS_FUNC))==0 ) {\
152
+					if ((_var)->flags&STAT_NO_SYNC) {\
153
+						*((_var)->u.val) = 0;\
154
+					} else {\
155
+						lock_get(stat_lock);\
156
+						*((_var)->u.val) = 0;\
157
+						lock_release(stat_lock);\
158
+					}\
159
+				}\
160
+			}while(0)
161
+		#define get_stat_val( _var ) ((unsigned long)\
162
+			((_var)->flags&STAT_IS_FUNC)?(_var)->u.f():*((_var)->u.val))
163
+	#else
164
+		#define update_stat( _var, _n) \
165
+			do { \
166
+				if ( !((_var)->flags&STAT_IS_FUNC) ) {\
167
+					if (_n>=0) \
168
+						atomic_add( _n, (_var)->u.val);\
169
+					else \
170
+						atomic_sub( -(_n), (_var)->u.val);\
171
+				}\
172
+			}while(0)
173
+		#define reset_stat( _var) \
174
+			do { \
175
+				if ( ((_var)->flags&(STAT_NO_RESET|STAT_IS_FUNC))==0 ) {\
176
+					atomic_set( (_var)->u.val, 0);\
177
+				}\
178
+			}while(0)
179
+		#define get_stat_val( _var ) ((unsigned long)\
180
+			((_var)->flags&STAT_IS_FUNC)?(_var)->u.f():(_var)->u.val->counter)
181
+	#endif /* NO_ATOMIC_OPS */
182
+
183
+	#define if_update_stat(_c, _var, _n) \
184
+		do { \
185
+			if (_c) update_stat( _var, _n); \
186
+		}while(0)
187
+	#define if_reset_stat(_c, _var) \
188
+		do { \
189
+			if (_c) reset_stat( _var); \
190
+		}while(0)
191
+#else
192
+	#define update_stat( _var, _n)
193
+	#define reset_stat( _var)
194
+	#define if_update_stat( _c, _var, _n)
195
+	#define if_reset_stat( _c, _var)
196
+#endif /*STATISTICS*/
197
+
198
+
199
+#endif