/src/opensips/core_stats.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2006 Voice Sistem SRL |
3 | | * |
4 | | * This file is part of opensips, a free SIP server. |
5 | | * |
6 | | * opensips is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * opensips is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
19 | | * |
20 | | * History: |
21 | | * --------- |
22 | | * 2006-01-23 first version (bogdan) |
23 | | * 2006-11-28 Added statistics for the number of bad URI's, methods, and |
24 | | * proxy requests (Jeffrey Magder - SOMA Networks) |
25 | | * 2009-04-23 NET and PKG statistics added (bogdan) |
26 | | */ |
27 | | |
28 | | /*! |
29 | | * \file |
30 | | * \brief OpenSIPS Core statistics |
31 | | */ |
32 | | |
33 | | |
34 | | #include <string.h> |
35 | | |
36 | | #include "statistics.h" |
37 | | #include "globals.h" |
38 | | #include "pt.h" |
39 | | #include "timer.h" |
40 | | #include <sys/types.h> |
41 | | #include <signal.h> |
42 | | #include "socket_info.h" |
43 | | #include "ipc.h" |
44 | | |
45 | | |
46 | | #ifdef STATISTICS |
47 | | |
48 | | /*************************** SIP statistics *********************************/ |
49 | | stat_var* rcv_reqs; |
50 | | stat_var* rcv_rpls; |
51 | | stat_var* fwd_reqs; |
52 | | stat_var* fwd_rpls; |
53 | | stat_var* drp_reqs; |
54 | | stat_var* drp_rpls; |
55 | | stat_var* err_reqs; |
56 | | stat_var* err_rpls; |
57 | | stat_var* bad_URIs; |
58 | | stat_var* bad_msg_hdr; |
59 | | stat_var* slow_msgs; |
60 | | |
61 | | |
62 | | const stat_export_t core_stats[] = { |
63 | | {"rcv_requests" , 0, &rcv_reqs }, |
64 | | {"rcv_replies" , 0, &rcv_rpls }, |
65 | | {"fwd_requests" , 0, &fwd_reqs }, |
66 | | {"fwd_replies" , 0, &fwd_rpls }, |
67 | | {"drop_requests" , 0, &drp_reqs }, |
68 | | {"drop_replies" , 0, &drp_rpls }, |
69 | | {"err_requests" , 0, &err_reqs }, |
70 | | {"err_replies" , 0, &err_rpls }, |
71 | | {"bad_URIs_rcvd", 0, &bad_URIs }, |
72 | | {"bad_msg_hdr", 0, &bad_msg_hdr }, |
73 | | {"slow_messages" , 0, &slow_msgs }, |
74 | | {"timestamp", STAT_IS_FUNC, (stat_var**)get_ticks }, |
75 | | {0,0,0} |
76 | | }; |
77 | | |
78 | | |
79 | | |
80 | | /*************************** NET statistics *********************************/ |
81 | | |
82 | | static unsigned long net_get_wb_udp(unsigned short foo) |
83 | 0 | { |
84 | 0 | return get_total_bytes_waiting(PROTO_UDP); |
85 | 0 | } |
86 | | |
87 | | static unsigned long net_get_wb_tcp(unsigned short foo) |
88 | 0 | { |
89 | 0 | return get_total_bytes_waiting(PROTO_TCP); |
90 | 0 | } |
91 | | |
92 | | static unsigned long net_get_wb_tls(unsigned short foo) |
93 | 0 | { |
94 | 0 | return get_total_bytes_waiting(PROTO_TLS); |
95 | 0 | } |
96 | | |
97 | | const stat_export_t net_stats[] = { |
98 | | {"waiting_udp" , STAT_IS_FUNC, (stat_var**)net_get_wb_udp }, |
99 | | {"waiting_tcp" , STAT_IS_FUNC, (stat_var**)net_get_wb_tcp }, |
100 | | {"waiting_tls" , STAT_IS_FUNC, (stat_var**)net_get_wb_tls }, |
101 | | {0,0,0} |
102 | | }; |
103 | | |
104 | | |
105 | | |
106 | | /*************************** PKG statistics *********************************/ |
107 | | |
108 | | #ifdef PKG_MALLOC |
109 | | static pkg_status_holder *pkg_status = NULL; |
110 | | static time_t *marker_t = NULL; |
111 | | static int no_pkg_status = 0; |
112 | | |
113 | | static void rpc_get_pkg_stats(int sender_id, void *foo) |
114 | | { |
115 | | #ifdef PKG_MALLOC |
116 | | pkg_status_holder *holder; |
117 | | |
118 | | holder = (pkg_status && process_no<no_pkg_status)? |
119 | | &(pkg_status[process_no]) : NULL ; |
120 | | |
121 | | set_pkg_stats( holder ); |
122 | | #endif |
123 | | return; |
124 | | } |
125 | | |
126 | | static inline void signal_pkg_status(unsigned long proc_id) |
127 | | { |
128 | | time_t t; |
129 | | |
130 | | if (IPC_FD_WRITE(proc_id)<=0) |
131 | | return; |
132 | | |
133 | | t = time(NULL); |
134 | | if (t>marker_t[proc_id]+1) { |
135 | | |
136 | | if (proc_id==process_no) { |
137 | | /* avoid sending IPC to ourselves, as it will get executed |
138 | | * after we ar done with pkg_status job; better do it inline */ |
139 | | rpc_get_pkg_stats(process_no, NULL); |
140 | | } else { |
141 | | if (ipc_send_rpc( proc_id, rpc_get_pkg_stats, NULL)<0) { |
142 | | LM_ERR("failed to trigger pkg stats for process %ld\n", |
143 | | proc_id ); |
144 | | return; |
145 | | } |
146 | | } |
147 | | |
148 | | marker_t[proc_id] = t; |
149 | | usleep(20); |
150 | | } |
151 | | } |
152 | | |
153 | | static unsigned long get_pkg_total_size( void* proc_id) |
154 | | { |
155 | | signal_pkg_status((unsigned long)proc_id); |
156 | | return pkg_status[(unsigned long)proc_id][PKG_TOTAL_SIZE_IDX]; |
157 | | } |
158 | | |
159 | | static unsigned long get_pkg_used_size( void* proc_id) |
160 | | { |
161 | | signal_pkg_status((unsigned long)proc_id); |
162 | | return pkg_status[(unsigned long)proc_id][PKG_USED_SIZE_IDX]; |
163 | | } |
164 | | |
165 | | static unsigned long get_pkg_real_used_size( void* proc_id) |
166 | | { |
167 | | signal_pkg_status((unsigned long)proc_id); |
168 | | return pkg_status[(unsigned long)proc_id][PKG_REAL_USED_SIZE_IDX]; |
169 | | } |
170 | | |
171 | | static unsigned long get_pkg_max_used_size( void* proc_id) |
172 | | { |
173 | | signal_pkg_status((unsigned long)proc_id); |
174 | | return pkg_status[(unsigned long)proc_id][PKG_MAX_USED_SIZE_IDX]; |
175 | | } |
176 | | |
177 | | static unsigned long get_pkg_free_size( void* proc_id) |
178 | | { |
179 | | signal_pkg_status((unsigned long)proc_id); |
180 | | return pkg_status[(unsigned long)proc_id][PKG_FREE_SIZE_IDX]; |
181 | | } |
182 | | |
183 | | static unsigned long get_pkg_fragments( void*proc_id) |
184 | | { |
185 | | signal_pkg_status((unsigned long)proc_id); |
186 | | return pkg_status[(unsigned long)proc_id][PKG_FRAGMENTS_SIZE_IDX]; |
187 | | } |
188 | | |
189 | | |
190 | | int init_pkg_stats(int procs_no) |
191 | | { |
192 | | int n; |
193 | | str n_str; |
194 | | char *name; |
195 | | str sname; |
196 | | group_stats *total_size_grp, *used_size_grp, *real_used_size_grp, |
197 | | *max_used_size_grp, *free_size_grp, *frags_grp; |
198 | | |
199 | | LM_DBG("setting stats for %d processes\n",procs_no); |
200 | | |
201 | | pkg_status = shm_malloc(procs_no*sizeof(pkg_status_holder)); |
202 | | marker_t = shm_malloc(procs_no*sizeof(time_t)); |
203 | | if (pkg_status==NULL || marker_t==NULL) { |
204 | | LM_ERR("no more pkg mem for stats\n"); |
205 | | return -1; |
206 | | } |
207 | | memset( pkg_status, 0, procs_no*sizeof(pkg_status_holder)); |
208 | | memset( marker_t, 0, procs_no*sizeof(time_t)); |
209 | | no_pkg_status = procs_no; |
210 | | |
211 | | |
212 | | total_size_grp = register_stats_group("proc_total_size"); |
213 | | if (!total_size_grp) { |
214 | | LM_ERR("could not register stats group proc_total_size"); |
215 | | return -1; |
216 | | } |
217 | | used_size_grp = register_stats_group("proc_used_size"); |
218 | | if (!used_size_grp) { |
219 | | LM_ERR("could not register stats group proc_used_size"); |
220 | | return -1; |
221 | | } |
222 | | real_used_size_grp = register_stats_group("proc_real_used_size"); |
223 | | if (!real_used_size_grp) { |
224 | | LM_ERR("could not register stats group proc_real_used_size"); |
225 | | return -1; |
226 | | } |
227 | | max_used_size_grp = register_stats_group("proc_max_used_size"); |
228 | | if (!max_used_size_grp) { |
229 | | LM_ERR("could not register stats group proc_max_used_size"); |
230 | | return -1; |
231 | | } |
232 | | free_size_grp = register_stats_group("proc_free_size"); |
233 | | if (!free_size_grp) { |
234 | | LM_ERR("could not register stats group proc_free_size"); |
235 | | return -1; |
236 | | } |
237 | | frags_grp = register_stats_group("proc_fragments"); |
238 | | if (!frags_grp) { |
239 | | LM_ERR("could not register stats group proc_fragments"); |
240 | | return -1; |
241 | | } |
242 | | |
243 | | /* build the stats and register them */ |
244 | | for( n=0 ; n<procs_no ; n++) { |
245 | | n_str.s = int2str( n, &n_str.len); |
246 | | |
247 | | if ( (name=build_stat_name( &n_str,"total_size"))==0 || |
248 | | register_stat2("pkmem", name, (stat_var**)get_pkg_total_size, |
249 | | STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC|STAT_PER_PROC, |
250 | | (void*)(long)n, 0)!=0 ) { |
251 | | LM_ERR("failed to add stat variable\n"); |
252 | | return -1; |
253 | | } |
254 | | sname.s = name; |
255 | | sname.len = strlen(name); |
256 | | pt[n].pkg_total = get_stat(&sname); |
257 | | pt[n].pkg_total->flags |= STAT_HIDDEN; |
258 | | add_stats_group(total_size_grp, pt[n].pkg_total); |
259 | | |
260 | | if ( (name=build_stat_name( &n_str,"used_size"))==0 || |
261 | | register_stat2("pkmem", name, (stat_var**)get_pkg_used_size, |
262 | | STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC|STAT_PER_PROC, |
263 | | (void*)(long)n, 0)!=0 ) { |
264 | | LM_ERR("failed to add stat variable\n"); |
265 | | return -1; |
266 | | } |
267 | | sname.s = name; |
268 | | sname.len = strlen(name); |
269 | | pt[n].pkg_used = get_stat(&sname); |
270 | | pt[n].pkg_used->flags |= STAT_HIDDEN; |
271 | | add_stats_group(used_size_grp, pt[n].pkg_used); |
272 | | |
273 | | if ( (name=build_stat_name( &n_str,"real_used_size"))==0 || |
274 | | register_stat2("pkmem", name, (stat_var**)get_pkg_real_used_size, |
275 | | STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC|STAT_PER_PROC, |
276 | | (void*)(long)n, 0)!=0 ) { |
277 | | LM_ERR("failed to add stat variable\n"); |
278 | | return -1; |
279 | | } |
280 | | sname.s = name; |
281 | | sname.len = strlen(name); |
282 | | pt[n].pkg_rused = get_stat(&sname); |
283 | | pt[n].pkg_rused->flags |= STAT_HIDDEN; |
284 | | add_stats_group(real_used_size_grp, pt[n].pkg_rused); |
285 | | |
286 | | if ( (name=build_stat_name( &n_str,"max_used_size"))==0 || |
287 | | register_stat2("pkmem", name, (stat_var**)get_pkg_max_used_size, |
288 | | STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC|STAT_PER_PROC, |
289 | | (void*)(long)n, 0)!=0 ) { |
290 | | LM_ERR("failed to add stat variable\n"); |
291 | | return -1; |
292 | | } |
293 | | sname.s = name; |
294 | | sname.len = strlen(name); |
295 | | pt[n].pkg_mused = get_stat(&sname); |
296 | | pt[n].pkg_mused->flags |= STAT_HIDDEN; |
297 | | add_stats_group(max_used_size_grp, pt[n].pkg_mused); |
298 | | |
299 | | if ( (name=build_stat_name( &n_str,"free_size"))==0 || |
300 | | register_stat2("pkmem", name, (stat_var**)get_pkg_free_size, |
301 | | STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC|STAT_PER_PROC, |
302 | | (void*)(long)n, 0)!=0 ) { |
303 | | LM_ERR("failed to add stat variable\n"); |
304 | | return -1; |
305 | | } |
306 | | sname.s = name; |
307 | | sname.len = strlen(name); |
308 | | pt[n].pkg_free = get_stat(&sname); |
309 | | pt[n].pkg_free->flags |= STAT_HIDDEN; |
310 | | add_stats_group(free_size_grp, pt[n].pkg_free); |
311 | | |
312 | | if ( (name=build_stat_name( &n_str,"fragments"))==0 || |
313 | | register_stat2("pkmem", name, (stat_var**)get_pkg_fragments, |
314 | | STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC|STAT_PER_PROC, |
315 | | (void*)(long)n, 0)!=0 ) { |
316 | | LM_ERR("failed to add stat variable\n"); |
317 | | return -1; |
318 | | } |
319 | | sname.s = name; |
320 | | sname.len = strlen(name); |
321 | | pt[n].pkg_frags = get_stat(&sname); |
322 | | pt[n].pkg_frags->flags |= STAT_HIDDEN; |
323 | | add_stats_group(frags_grp, pt[n].pkg_frags); |
324 | | } |
325 | | |
326 | | return 0; |
327 | | } |
328 | | #endif /* PKG */ |
329 | | |
330 | | #endif /* STATISTICS */ |