tm: remove old timer based transaction delete functionality, not active since 2007
[kamailio] / src / modules / tm / t_stats.c
1 /*
2  *
3  * Copyright (C) 2001-2003 FhG Fokus
4  *
5  * This file is part of Kamailio, a free SIP server.
6  *
7  * Kamailio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version
11  *
12  * Kamailio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22
23 #include "defs.h"
24
25
26 #include <stdio.h>
27 #include "t_stats.h"
28 #include "../../core/mem/shm_mem.h"
29 #include "../../core/dprint.h"
30 #include "../../core/config.h"
31 #include "../../core/pt.h"
32 #include "h_table.h"
33
34 union t_stats *tm_stats=0;
35
36 int init_tm_stats(void)
37 {
38         /* Delay initialization of tm_stats  to
39          * init_tm_stats_child which gets called from child_init,
40          * in mod_init function other modules can increase the value of
41          * estimated_process_count and thus we do not know about processes created
42          * from modules which get loaded after tm and thus their mod_init
43          * functions will be called after tm mod_init function finishes
44          */
45         return 0;
46 }
47
48
49 int init_tm_stats_child(void)
50 {
51         int size;
52
53         /* We are called from child_init, estimated_process_count has definitive
54          * value now and thus we can safely allocate the variables
55          */
56         if (tm_stats==0){
57                 size=sizeof(*tm_stats) * get_max_procs();
58                 tm_stats=shm_malloc(size);
59                 if (tm_stats == 0) {
60                         ERR("No mem for stats\n");
61                         goto error;
62                 }
63                 memset(tm_stats, 0, size);
64         }
65
66         return 0;
67 error:
68         return -1;
69 }
70
71
72
73 void free_tm_stats()
74 {
75         if (tm_stats == 0) return;
76         shm_free(tm_stats);
77         tm_stats=0;
78 }
79
80
81
82 /* res=s1+s2 */
83 #define tm_proc_stats_add_base(res, s1, s2) \
84         do{\
85                 (res)->waiting=(s1)->waiting+(s2)->waiting; \
86                 (res)->transactions=(s1)->transactions+(s2)->transactions; \
87                 (res)->client_transactions=(s1)->client_transactions+\
88                                                                         (s2)->client_transactions; \
89                 (res)->completed_3xx=(s1)->completed_3xx+(s2)->completed_3xx; \
90                 (res)->completed_4xx=(s1)->completed_4xx+(s2)->completed_4xx; \
91                 (res)->completed_5xx=(s1)->completed_5xx+(s2)->completed_5xx; \
92                 (res)->completed_6xx=(s1)->completed_6xx+(s2)->completed_6xx; \
93                 (res)->completed_2xx=(s1)->completed_2xx+(s2)->completed_2xx; \
94                 (res)->rpl_received=(s1)->rpl_received+(s2)->rpl_received; \
95                 (res)->rpl_generated=(s1)->rpl_generated+(s2)->rpl_generated; \
96                 (res)->rpl_sent=(s1)->rpl_sent+(s2)->rpl_sent; \
97                 (res)->deleted=(s1)->deleted+(s2)->deleted; \
98         }while(0)
99
100
101 #ifdef TM_MORE_STATS
102 #define tm_proc_stats_add(res, s1, s2) \
103         do{\
104                 tm_proc_stats_add_base(res, s1, s2); \
105                 (res)->t_created=(s1)->t_created+(s2)->t_created; \
106                 (res)->t_freed=(s1)->t_freed+(s2)->t_freed; \
107                 (res)->delayed_free=(s1)->delayed_free+(s2)->delayed_free; \
108         }while(0)
109 #else
110 #define tm_proc_stats_add(res, s1, s2) tm_proc_stats_add_base(res, s1, s2)
111 #endif
112
113
114
115 /* we don't worry about locking data during reads (unlike
116  * setting values which always happens from some locks)
117  */
118 void tm_rpc_stats(rpc_t* rpc, void* c)
119 {
120         void* st;
121         unsigned long current, waiting;
122         struct t_proc_stats all;
123         int i, pno;
124
125         pno = get_max_procs();
126         memset(&all, 0, sizeof(all));
127         for(i = 0;i < pno; i++) {
128                 tm_proc_stats_add(&all, &all, &tm_stats[i].s);
129         }
130         current = all.transactions - all.deleted;
131         waiting = all.waiting - all.deleted;
132
133         if (rpc->add(c, "{", &st) < 0) return;
134
135         rpc->struct_add(st, "dd", "current", (unsigned) current, "waiting",
136                                                                         (unsigned) waiting);
137         rpc->struct_add(st, "d", "total", (unsigned) all.transactions);
138         rpc->struct_add(st, "d", "total_local", (unsigned)all.client_transactions);
139         rpc->struct_add(st, "d", "rpl_received", (unsigned)all.rpl_received);
140         rpc->struct_add(st, "d", "rpl_generated", (unsigned)all.rpl_generated);
141         rpc->struct_add(st, "d", "rpl_sent", (unsigned)all.rpl_sent);
142         rpc->struct_add(st, "ddddd",
143                         "6xx", (unsigned int)all.completed_6xx,
144                         "5xx", (unsigned int)all.completed_5xx,
145                         "4xx", (unsigned int)all.completed_4xx,
146                         "3xx", (unsigned int)all.completed_3xx,
147                         "2xx", (unsigned int)all.completed_2xx);
148 #ifdef TM_MORE_STATS
149         rpc->struct_add(st, "dd", "created", (unsigned int)all.t_created, "freed",
150                                                 (unsigned int)all.t_freed);
151         rpc->struct_add(st, "d", "delayed_free", (unsigned int)all.delayed_free);
152 #endif
153         /* rpc->fault(c, 100, "Trying"); */
154 }
155
156 int tm_get_stats(struct t_proc_stats *all)
157 {
158         int i, pno;
159         if(all==NULL)
160                 return -1;
161
162         pno = get_max_procs();
163         memset(all, 0, sizeof(struct t_proc_stats));
164         for(i = 0; i < pno; i++) {
165                 tm_proc_stats_add(all, all, &tm_stats[i].s);
166         }
167         return 0;
168 }
169
170
171 /*  hash statistics */
172 void tm_rpc_hash_stats(rpc_t* rpc, void* c)
173 {
174 #ifdef TM_HASH_STATS
175         void* st;
176         unsigned long acc_min, acc_max, acc_zeroes, acc_dev_no;
177         unsigned long crt_min, crt_max, crt_zeroes, crt_dev_no;
178         unsigned long crt_count, acc_count;
179         double acc_average, acc_dev, acc_d;
180         double crt_average, crt_dev, crt_d;
181         unsigned long acc, crt;
182         int r;
183
184         acc_count=0;
185         acc_min=(unsigned long)(-1);
186         acc_max=0;
187         acc_zeroes=0;
188         acc_dev_no=0;
189         acc_dev=0;
190         crt_count=0;
191         crt_min=(unsigned long)(-1);
192         crt_max=0;
193         crt_zeroes=0;
194         crt_dev_no=0;
195         crt_dev=0;
196         for (r=0; r<TABLE_ENTRIES; r++){
197                 acc=_tm_table->entries[r].acc_entries;
198                 crt=_tm_table->entries[r].cur_entries;
199
200                 acc_count+=acc;
201                 if (acc<acc_min) acc_min=acc;
202                 if (acc>acc_max) acc_max=acc;
203                 if (acc==0) acc_zeroes++;
204
205                 crt_count+=crt;
206                 if (crt<crt_min) crt_min=crt;
207                 if (crt>crt_max) crt_max=crt;
208                 if (crt==0) crt_zeroes++;
209         }
210         acc_average=acc_count/(double)TABLE_ENTRIES;
211         crt_average=crt_count/(double)TABLE_ENTRIES;
212
213         for (r=0; r<TABLE_ENTRIES; r++){
214                 acc=_tm_table->entries[r].acc_entries;
215                 crt=_tm_table->entries[r].cur_entries;
216
217                 acc_d=acc-acc_average;
218                 /* instead of fabs() which requires -lm */
219                 if (acc_d<0) acc_d=-acc_d;
220                 if (acc_d>1) acc_dev_no++;
221                 acc_dev+=acc_d*acc_d;
222                 crt_d=crt-crt_average;
223                 /* instead of fabs() which requires -lm */
224                 if (crt_d<0) crt_d=-crt_d;
225                 if (crt_d>1) crt_dev_no++;
226                 crt_dev+=crt_d*crt_d;
227         }
228
229         if (rpc->add(c, "{", &st) < 0) return;
230         rpc->struct_add(st, "d", "hash_size", (unsigned) TABLE_ENTRIES);
231         rpc->struct_add(st, "d", "crt_transactions", (unsigned)crt_count);
232         rpc->struct_add(st, "f", "crt_target_per_cell", crt_average);
233         rpc->struct_add(st, "dd", "crt_min", (unsigned)crt_min,
234                                                         "crt_max", (unsigned) crt_max);
235         rpc->struct_add(st, "d", "crt_worst_case_extra_cells",
236                                                         (unsigned)(crt_max-(unsigned)crt_average));
237         rpc->struct_add(st, "d", "crt_no_zero_cells", (unsigned)crt_zeroes);
238         rpc->struct_add(st, "d", "crt_no_deviating_cells", crt_dev_no);
239         rpc->struct_add(st, "f", "crt_deviation_sq_sum", crt_dev);
240         rpc->struct_add(st, "d", "acc_transactions", (unsigned)acc_count);
241         rpc->struct_add(st, "f", "acc_target_per_cell", acc_average);
242         rpc->struct_add(st, "dd", "acc_min", (unsigned)acc_min,
243                                                         "acc_max", (unsigned) acc_max);
244         rpc->struct_add(st, "d", "acc_worst_case_extra_cells",
245                                                         (unsigned)(acc_max-(unsigned)acc_average));
246         rpc->struct_add(st, "d", "acc_no_zero_cells", (unsigned)acc_zeroes);
247         rpc->struct_add(st, "d", "acc_no_deviating_cells", acc_dev_no);
248         rpc->struct_add(st, "f", "acc_deviation_sq_sum", acc_dev);
249 #else /* TM_HASH_STATS */
250         rpc->fault(c, 500, "Hash statistics not supported (try"
251                                 "recompiling with -DTM_HASH_STATS)");
252 #endif /* TM_HASH_STATS */
253 }
254
255 /* list active transactions */
256 void tm_rpc_list(rpc_t* rpc, void* c)
257 {
258         int r;
259         void* h;
260         tm_cell_t *tcell;
261         char pbuf[32];
262
263         for (r=0; r<TABLE_ENTRIES; r++) {
264                 lock_hash(r);
265                 if(clist_empty(&_tm_table->entries[r], next_c)) {
266                         unlock_hash(r);
267                         continue;
268                 }
269                 if (rpc->add(c, "{", &h) < 0) {
270                         LM_ERR("failed to add transaction structure\n");
271                         unlock_hash(r);
272                         return;
273                 }
274                 clist_foreach(&_tm_table->entries[r], tcell, next_c)
275                 {
276                         snprintf(pbuf, 31, "%p", (void*)tcell);
277                         rpc->struct_add(h, "sddSSSSSsdddd",
278                                         "cell", pbuf,
279                                         "tindex", (unsigned)tcell->hash_index,
280                                         "tlabel", (unsigned)tcell->label,
281                                         "method", &tcell->method,
282                                         "from", &tcell->from,
283                                         "to", &tcell->to,
284                                         "callid", &tcell->callid,
285                                         "cseq", &tcell->cseq_n,
286                                         "uas_request", (tcell->uas.request)?"yes":"no",
287                                         "tflags", (unsigned)tcell->flags,
288                                         "outgoings", (unsigned)tcell->nr_of_outgoings,
289                                         "ref_count", (unsigned)atomic_get(&tcell->ref_count),
290                                         "lifetime", (unsigned)TICKS_TO_S(tcell->end_of_life)
291                                         );
292                 }
293                 unlock_hash(r);
294         }
295 }
296
297
298 /* rpc command to clean active but very old transactions */
299 void tm_rpc_clean(rpc_t* rpc, void* c)
300 {
301         tm_clean_lifetime();
302 }