1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 *
16 * Authors : Benjamin GAUTHIER - 24 Mar 2004
17 * Joseph BANINO
18 * Olivier JACQUES
19 * Richard GAYRAUD
20 * From Hewlett Packard Company.
21 * Wolfgang Beck
22 *
23 */
24
25 #include <iostream>
26 #include <fstream>
27 #include <iomanip>
28 #include <assert.h>
29
30 #include "sipp.hpp"
31 #include "scenario.hpp"
32 #include "screen.hpp"
33 #ifdef HAVE_GSL
34 #include <gsl/gsl_rng.h>
35 #include <gsl/gsl_randist.h>
36 #include <gsl/gsl_cdf.h>
37 #endif
38
39 /*
40 ** Local definitions (macros)
41 */
42
43 /*
44 ** Warning! All DISPLAY_ macros must be called where f FILE is
45 ** defined. This is to allow printing to stdout or a file.
46 */
47 #define DISPLAY_LINE()\
48 fprintf(f," ------------------------------------------------------------------------------ \r\n")
49 #define DISPLAY_DLINE()\
50 fprintf(f,"================================================================================\r\n")
51 #define DISPLAY_CROSS_LINE()\
52 fprintf(f,"-------------------------+---------------------------+--------------------------\r\n")
53
54 #define DISPLAY_HEADER()\
55 fprintf(f," Counter Name | Periodic value | Cumulative value\r\n")
56 #define DISPLAY_TXT_COL(T1, V1, V2)\
57 fprintf(f," %-22.22s | %-25.25s |", T1, V1); fprintf(f," %-24.24s \r\n", V2)
58 #define DISPLAY_VAL_RATEF_COL(T1, V1, V2)\
59 fprintf(f," %-22.22s | %8.3f cps | %8.3f cps \r\n", T1, V1, V2)
60 #define DISPLAY_2VAL(T1, V1, V2)\
61 fprintf(f," %-22.22s | %8llu | %8llu \r\n", T1, V1, V2)
62 #define DISPLAY_CUMUL(T1, V1)\
63 fprintf(f," %-22.22s | | %8llu \r\n", T1, V1)
64 #define DISPLAY_PERIO(T1, V1)\
65 fprintf(f," %-22.22s | %8llu | \r\n", T1, V1)
66 #define DISPLAY_VALF(T1, V1)\
67 fprintf(f," %-22.22s | %8.3f ms \r\n", T1, V1)
68 #define DISPLAY_VAL_RATEF(T1, V1)\
69 fprintf(f," %-22.22s | %8.3f cps \r\n", T1, V1)
70 #define DISPLAY_VAL_RATE(T1, V1)\
71 fprintf(f," %-22.22s | %8d cps \r\n", T1, V1)
72 #define DISPLAY_VAL(T1, V1)\
73 fprintf(f," %-22.22s : %8d \r\n", T1, V1)
74 #define DISPLAY_2VALF(T1, V1, T2, V2)\
75 fprintf(f," %-22.22s : %8.2f | %-7.7s : %8.2f \r\n", T1, V1, T2, V2)
76 #define DISPLAY_3VAL(T1, V1, T2, V2, T3, V3)\
77 fprintf(f," %-22.22s : %8d | %-7.7s : %8d | %-12.12s : %5d \r\n", T1, V1, T2, V2, T3, V3)
78 #define DISPLAY_3VALF(T1, V1, T2, V2, T3, V3)\
79 fprintf(f," %-22.22s : %8.3f | %-7.7s : %8.3f | %-12.12s : %5.1f \r\n", T1, V1, T2, V2, T3, V3)
80 #define DISPLAY_TXT(T1, V1)\
81 fprintf(f," %-22.22s | %-52.52s \r\n", T1, V1)
82 #define DISPLAY_INFO(T1)\
83 fprintf(f," %-77.77s \r\n", T1)
84 #define DISPLAY_REPART(T1, T2, V1)\
85 fprintf(f," %8d ms <= n < %8d ms : %10lu %-29.29s \r\n", T1, T2, V1, "")
86 #define DISPLAY_LAST_REPART(T1, V1)\
87 fprintf(f," %14.14s n >= %8d ms : %10lu %-29.29s \r\n", "", T1, V1, "")
88
89 #define RESET_COUNTERS(PT)\
90 memset (PT, 0, CStat::E_NB_COUNTER * sizeof(unsigned long long))
91
92 #define RESET_C_COUNTERS \
93 { \
94 int i; \
95 for (i=CStat::CPT_G_C_OutOfCallMsgs; \
96 i<=CStat::CPT_G_C_AutoAnswered; \
97 i++) \
98 M_G_counters[i - E_NB_COUNTER - 1] = (unsigned long) 0; \
99 for (i=CStat::CPT_C_IncomingCallCreated; \
100 i<=CStat::CPT_C_Retransmissions; \
101 i++) \
102 M_counters[i] = (unsigned long) 0; \
103 for (unsigned int j=0;j<M_genericMap.size(); j++) { \
104 M_genericCounters[j * GENERIC_TYPES + GENERIC_C] = 0; \
105 } \
106 for (unsigned int j=0;j<M_rtdMap.size(); j++) { \
107 M_rtdInfo[(j * GENERIC_TYPES * RTD_TYPES) + (GENERIC_C * RTD_TYPES) + RTD_COUNT] = 0; \
108 M_rtdInfo[(j * GENERIC_TYPES * RTD_TYPES) + (GENERIC_C * RTD_TYPES) + RTD_SUM] = 0; \
109 M_rtdInfo[(j * GENERIC_TYPES * RTD_TYPES) + (GENERIC_C * RTD_TYPES) + RTD_SUMSQ] = 0; \
110 } \
111 }
112
113 #define RESET_PD_COUNTERS \
114 { \
115 int i; \
116 for (i=CStat::CPT_G_PD_OutOfCallMsgs; \
117 i<=CStat::CPT_G_PD_AutoAnswered; \
118 i++) \
119 M_G_counters[i - E_NB_COUNTER - 1] = (unsigned long) 0; \
120 for (i=CStat::CPT_PD_IncomingCallCreated; \
121 i<=CStat::CPT_PD_Retransmissions; \
122 i++) \
123 M_counters[i] = (unsigned long) 0; \
124 for (unsigned int j=0;j<M_genericMap.size(); j++) { \
125 M_genericCounters[j * GENERIC_TYPES + GENERIC_PD] = 0; \
126 } \
127 for (unsigned int j=0;j<M_rtdMap.size(); j++) { \
128 M_rtdInfo[(j * GENERIC_TYPES * RTD_TYPES) + (GENERIC_PD * RTD_TYPES) + RTD_COUNT] = 0; \
129 M_rtdInfo[(j * GENERIC_TYPES * RTD_TYPES) + (GENERIC_PD * RTD_TYPES) + RTD_SUM] = 0; \
130 M_rtdInfo[(j * GENERIC_TYPES * RTD_TYPES) + (GENERIC_PD * RTD_TYPES) + RTD_SUMSQ] = 0; \
131 } \
132 }
133
134 #define RESET_PL_COUNTERS \
135 { \
136 int i; \
137 for (i=CStat::CPT_G_PL_OutOfCallMsgs; \
138 i<=CStat::CPT_G_PL_AutoAnswered; \
139 i++) \
140 M_G_counters[i - E_NB_COUNTER - 1] = (unsigned long) 0; \
141 for (i=CStat::CPT_PL_IncomingCallCreated; \
142 i<=CStat::CPT_PL_Retransmissions; \
143 i++) \
144 M_counters[i] = (unsigned long) 0; \
145 for (unsigned int j=0;j<M_genericMap.size(); j++) { \
146 M_genericCounters[j * GENERIC_TYPES + GENERIC_PL] = 0; \
147 } \
148 for (unsigned int j=0;j<M_rtdMap.size(); j++) { \
149 M_rtdInfo[(j * GENERIC_TYPES * RTD_TYPES) + (GENERIC_PL * RTD_TYPES) + RTD_COUNT] = 0; \
150 M_rtdInfo[(j * GENERIC_TYPES * RTD_TYPES) + (GENERIC_PL * RTD_TYPES) + RTD_SUM] = 0; \
151 M_rtdInfo[(j * GENERIC_TYPES * RTD_TYPES) + (GENERIC_PL * RTD_TYPES) + RTD_SUMSQ] = 0; \
152 } \
153 }
154
155 /*
156 __________________________________________________________________________
157
158 C L A S S CS t a t
159 __________________________________________________________________________
160 */
161
162 unsigned long long CStat::M_G_counters[E_NB_G_COUNTER - E_NB_COUNTER];
163
~CStat()164 CStat::~CStat()
165 {
166 int i;
167
168 for (i = 0; i < nRtds(); i++) {
169 if (M_ResponseTimeRepartition[i] != NULL) {
170 delete [] M_ResponseTimeRepartition[i];
171 }
172 }
173 free(M_ResponseTimeRepartition);
174
175 if (M_CallLengthRepartition != NULL)
176 delete [] M_CallLengthRepartition;
177
178 if(M_outputStream != NULL) {
179 M_outputStream->close();
180 delete M_outputStream;
181 }
182
183 if(M_fileName != NULL)
184 delete [] M_fileName;
185
186 if(M_outputStreamRtt != NULL) {
187 M_outputStreamRtt->close();
188 delete M_outputStreamRtt;
189 }
190 if(M_fileNameRtt != NULL)
191 delete [] M_fileNameRtt;
192
193
194 if(M_dumpRespTime != NULL)
195 delete [] M_dumpRespTime ;
196
197 free(M_rtdInfo);
198 for (int_str_map::iterator i = M_revRtdMap.begin(); i != M_revRtdMap.end(); ++i) {
199 free(i->second);
200 }
201
202 M_SizeOfResponseTimeRepartition = 0;
203 M_SizeOfCallLengthRepartition = 0;
204 M_CallLengthRepartition = NULL;
205 M_fileName = NULL;
206 M_outputStream = NULL;
207
208 M_outputStreamRtt = NULL;
209 M_fileNameRtt = NULL;
210 M_dumpRespTime = NULL;
211 }
212
213
init()214 int CStat::init ()
215 {
216 // reset of all counter
217 RESET_COUNTERS(M_counters);
218 GET_TIME (&M_startTime);
219 memcpy (&M_pdStartTime, &M_startTime, sizeof (struct timeval));
220 memcpy (&M_plStartTime, &M_startTime, sizeof (struct timeval));
221 M_outputStream = NULL;
222 M_headerAlreadyDisplayed = false;
223
224 M_outputStreamRtt = NULL;
225 M_headerAlreadyDisplayedRtt = false;
226
227 std::vector<int> error_codes(0);
228
229 return(1);
230 }
231
232
isWellFormed(char * P_listeStr,int * nombre)233 int CStat::isWellFormed(char * P_listeStr,
234 int * nombre)
235 {
236 char * ptr = P_listeStr;
237 int sizeOf;
238 bool isANumber;
239
240 (*nombre) = 0;
241 sizeOf = strlen(P_listeStr);
242 // getting the number
243 if(sizeOf > 0) {
244 // is the string well formed ? [0-9] [,]
245 isANumber = false;
246 for(int i=0; i<=sizeOf; i++) {
247 switch(ptr[i]) {
248 case ',':
249 if(isANumber == false) {
250 return(0);
251 } else {
252 (*nombre)++;
253 }
254 isANumber = false;
255 break;
256 case '0':
257 case '1':
258 case '2':
259 case '3':
260 case '4':
261 case '5':
262 case '6':
263 case '7':
264 case '8':
265 case '9':
266 isANumber = true;
267 break;
268 case '\t':
269 case ' ' :
270 break;
271 case '\0':
272 if(isANumber == false) {
273 return(0);
274 } else {
275 (*nombre)++;
276 }
277 break;
278 default:
279 return(0);
280 }
281 } // enf for
282 }
283 return(1);
284 }
285
286
createIntegerTable(char * P_listeStr,unsigned int ** listeInteger,int * sizeOfList)287 int CStat::createIntegerTable(char * P_listeStr,
288 unsigned int ** listeInteger,
289 int * sizeOfList)
290 {
291 int nb=0;
292 char * ptr = P_listeStr;
293 char * ptr_prev = P_listeStr;
294 unsigned int current_int;
295
296 if(isWellFormed(P_listeStr, sizeOfList) == 1) {
297 (*listeInteger) = new unsigned int[(*sizeOfList)];
298 while((*ptr) != ('\0')) {
299 if((*ptr) == ',') {
300 sscanf(ptr_prev, "%u", ¤t_int);
301 if (nb<(*sizeOfList))
302 (*listeInteger)[nb] = current_int;
303 nb++;
304 ptr_prev = ptr+1;
305 }
306 ptr++;
307 }
308 // on lit le dernier
309 sscanf(ptr_prev, "%u", ¤t_int);
310 if (nb<(*sizeOfList))
311 (*listeInteger)[nb] = current_int;
312 nb++;
313 return(1);
314 }
315 return(0);
316 }
317
318
setFileName(const char * P_name,const char * P_extension)319 void CStat::setFileName(const char* P_name, const char* P_extension)
320 {
321 int sizeOf, sizeOfExtension;
322
323 if(P_name != NULL) {
324 // +6 for PID
325 sizeOf = strlen(P_name) + 6;
326 if(sizeOf > 0) {
327 if(P_extension != NULL) {
328 sizeOfExtension = strlen(P_extension);
329 if(sizeOfExtension > 0) {
330 if(M_fileName != NULL)
331 delete [] M_fileName;
332 M_fileName = new char[MAX_PATH];
333 sprintf(M_fileName, "%s_%d_", P_name, getpid());
334 strcat(M_fileName, P_extension);
335 } else {
336 if(M_fileName != NULL)
337 delete [] M_fileName;
338 M_fileName = new char[MAX_PATH];
339 sprintf(M_fileName, "%s_%d_", P_name, getpid());
340 strcat(M_fileName, DEFAULT_EXTENSION);
341 }
342 } else {
343 if(M_fileName != NULL)
344 delete [] M_fileName;
345 M_fileName = new char[MAX_PATH];
346 sprintf(M_fileName, "%s_%d_", P_name, getpid());
347 strcat(M_fileName, DEFAULT_EXTENSION);
348 }
349 } else {
350 cerr << "new file name length is null - "
351 << "keeping the default filename : "
352 << DEFAULT_FILE_NAME << endl;
353 }
354 } else {
355 cerr << "new file name is NULL ! - keeping the default filename : "
356 << DEFAULT_FILE_NAME << endl;
357 }
358 }
359
360
setFileName(const char * P_name)361 void CStat::setFileName(const char* P_name)
362 {
363 int sizeOf;
364
365 if(P_name != NULL) {
366 sizeOf = strlen(P_name);
367 if(sizeOf > 0) {
368 if(M_fileName != NULL)
369 delete [] M_fileName;
370 M_fileName = new char[sizeOf+1];
371 strcpy(M_fileName, P_name);
372 } else {
373 cerr << "new file name length is null - "
374 "keeping the default filename : "
375 << DEFAULT_FILE_NAME << endl;
376 }
377 } else {
378 cerr << "new file name is NULL ! - keeping the default filename : "
379 << DEFAULT_FILE_NAME << endl;
380 }
381 }
382
383
initRtt(const char * P_name,const char * P_extension,unsigned long P_report_freq_dumpRtt)384 void CStat::initRtt(const char* P_name, const char* P_extension,
385 unsigned long P_report_freq_dumpRtt)
386 {
387 int sizeOf, sizeOfExtension;
388
389 if(P_name != NULL) {
390 sizeOf = strlen(P_name) ;
391 if(sizeOf > 0) {
392 // 4 for '_rtt' and 6 for pid
393 sizeOf += 10 ;
394 sizeOfExtension = strlen(P_extension);
395 if(M_fileNameRtt != NULL)
396 delete [] M_fileNameRtt;
397 sizeOf += sizeOfExtension;
398 M_fileNameRtt = new char[sizeOf+1];
399 sprintf (M_fileNameRtt, "%s_%d_rtt%s", P_name, getpid(),P_extension);
400 } else {
401 cerr << "new file name length is null - "
402 << "keeping the default filename : "
403 << DEFAULT_FILE_NAME << endl;
404 }
405 } else {
406 cerr << "new file name is NULL ! - keeping the default filename : "
407 << DEFAULT_FILE_NAME << endl;
408 }
409
410 // initiate the table dump response time
411 M_report_freq_dumpRtt = P_report_freq_dumpRtt ;
412
413 M_dumpRespTime = new T_value_rtt [P_report_freq_dumpRtt] ;
414
415 if ( M_dumpRespTime == NULL ) {
416 cerr << "Memory allocation failure" << endl;
417 exit(EXIT_FATAL_ERROR);
418 }
419
420 for (unsigned L_i = 0 ; L_i < P_report_freq_dumpRtt; L_i ++) {
421 M_dumpRespTime[L_i].date = 0.0;
422 M_dumpRespTime[L_i].rtd_no = 0;
423 M_dumpRespTime[L_i].rtt = 0.0;
424 }
425 }
426
setRepartitionCallLength(char * P_listeStr)427 void CStat::setRepartitionCallLength(char * P_listeStr)
428 {
429 unsigned int * listeInteger;
430 int sizeOfListe;
431
432 if(createIntegerTable(P_listeStr, &listeInteger, &sizeOfListe) == 1) {
433 initRepartition(listeInteger,
434 sizeOfListe,
435 &M_CallLengthRepartition,
436 &M_SizeOfCallLengthRepartition);
437 } else {
438 ERROR("Could not create table for call length repartition '%s'\n", P_listeStr);
439 }
440 delete [] listeInteger;
441 listeInteger = NULL;
442 }
443
setRepartitionResponseTime(char * P_listeStr)444 void CStat::setRepartitionResponseTime (char * P_listeStr)
445 {
446 unsigned int * listeInteger;
447 int sizeOfListe;
448 int i;
449
450 for (i = 0; i < nRtds(); i++) {
451 if(createIntegerTable(P_listeStr, &listeInteger, &sizeOfListe) == 1) {
452 initRepartition(listeInteger,
453 sizeOfListe,
454 &M_ResponseTimeRepartition[i],
455 &M_SizeOfResponseTimeRepartition);
456 } else {
457 ERROR("Could not create table for response time repartition '%s'\n", P_listeStr);
458 }
459 delete [] listeInteger;
460 listeInteger = NULL;
461 }
462 }
463
464
setRepartitionCallLength(unsigned int * repartition,int nombre)465 void CStat::setRepartitionCallLength(unsigned int* repartition,
466 int nombre)
467 {
468 initRepartition(repartition,
469 nombre,
470 &M_CallLengthRepartition,
471 &M_SizeOfCallLengthRepartition);
472 }
473
setRepartitionResponseTime(unsigned int * repartition,int nombre)474 void CStat::setRepartitionResponseTime(unsigned int* repartition,
475 int nombre)
476 {
477 for (int i = 0; i < nRtds(); i++) {
478 initRepartition(repartition,
479 nombre,
480 &M_ResponseTimeRepartition[i],
481 &M_SizeOfResponseTimeRepartition);
482 }
483 }
484
485
initRepartition(unsigned int * repartition,int nombre,T_dynamicalRepartition ** tabRepartition,int * tabNb)486 void CStat::initRepartition(unsigned int* repartition,
487 int nombre,
488 T_dynamicalRepartition ** tabRepartition,
489 int* tabNb)
490 {
491 bool sortDone;
492 int i;
493 unsigned int swap;
494
495 if((nombre <= 0) || (repartition == NULL) ) {
496 (*tabNb) = 0;
497 (*tabRepartition) = NULL;
498 return;
499 }
500
501 (*tabNb) = nombre + 1;
502 (*tabRepartition) = new T_dynamicalRepartition[(*tabNb)];
503
504 // copying the repartition table in the local table
505 for(i=0; i<nombre; i++) {
506 (*tabRepartition)[i].borderMax = repartition[i];
507 (*tabRepartition)[i].nbInThisBorder = 0;
508 }
509
510 // sorting the repartition table
511 sortDone = false;
512 while(!sortDone) {
513 sortDone = true;
514 for(i=0; i<(nombre-1); i++) {
515 if((*tabRepartition)[i].borderMax > (*tabRepartition)[i+1].borderMax) {
516 // swapping this two value and setting sortDone to false
517 swap = (*tabRepartition)[i].borderMax;
518 (*tabRepartition)[i].borderMax =
519 (*tabRepartition)[i+1].borderMax;
520 (*tabRepartition)[i+1].borderMax = swap;
521 sortDone = false;
522 }
523 }
524 }
525 // setting the range for max <= value < infinity
526 (*tabRepartition)[nombre].borderMax =
527 (*tabRepartition)[nombre-1].borderMax;
528 (*tabRepartition)[nombre].nbInThisBorder = 0;
529 }
530
531
computeStat(E_Action P_action)532 int CStat::computeStat (E_Action P_action)
533 {
534 switch (P_action) {
535 case E_CREATE_OUTGOING_CALL :
536 M_counters [CPT_C_OutgoingCallCreated]++;
537 M_counters [CPT_PD_OutgoingCallCreated]++;
538 M_counters [CPT_PL_OutgoingCallCreated]++;
539 M_counters [CPT_C_CurrentCall]++;
540 if (M_counters[CPT_C_CurrentCall] > M_counters[CPT_C_CurrentCallPeak]) {
541 M_counters [CPT_C_CurrentCallPeak] = M_counters[CPT_C_CurrentCall];
542 M_counters [CPT_C_CurrentCallPeakTime] = clock_tick / 1000;
543 }
544 if (M_counters[CPT_C_CurrentCall] > M_counters[CPT_PD_CurrentCallPeak]) {
545 M_counters [CPT_PD_CurrentCallPeak] = M_counters[CPT_C_CurrentCall];
546 M_counters [CPT_PD_CurrentCallPeakTime] = clock_tick / 1000;
547 }
548 if (M_counters[CPT_C_CurrentCall] > M_counters[CPT_PL_CurrentCallPeak]) {
549 M_counters [CPT_PL_CurrentCallPeak] = M_counters[CPT_C_CurrentCall];
550 M_counters [CPT_PL_CurrentCallPeakTime] = clock_tick / 1000;
551 }
552 break;
553
554 case E_CREATE_INCOMING_CALL :
555 M_counters [CPT_C_IncomingCallCreated]++;
556 M_counters [CPT_PD_IncomingCallCreated]++;
557 M_counters [CPT_PL_IncomingCallCreated]++;
558 M_counters [CPT_C_CurrentCall]++;
559 if (M_counters[CPT_C_CurrentCall] > M_counters[CPT_C_CurrentCallPeak]) {
560 M_counters [CPT_C_CurrentCallPeak] = M_counters[CPT_C_CurrentCall];
561 M_counters [CPT_C_CurrentCallPeakTime] = clock_tick / 1000;
562 }
563 if (M_counters[CPT_C_CurrentCall] > M_counters[CPT_PD_CurrentCallPeak]) {
564 M_counters [CPT_PD_CurrentCallPeak] = M_counters[CPT_C_CurrentCall];
565 M_counters [CPT_PD_CurrentCallPeakTime] = clock_tick / 1000;
566 }
567 if (M_counters[CPT_C_CurrentCall] > M_counters[CPT_PL_CurrentCallPeak]) {
568 M_counters [CPT_PL_CurrentCallPeak] = M_counters[CPT_C_CurrentCall];
569 M_counters [CPT_PL_CurrentCallPeakTime] = clock_tick / 1000;
570 }
571 break;
572
573 case E_CALL_FAILED :
574 M_counters [CPT_C_FailedCall]++;
575 M_counters [CPT_PD_FailedCall]++;
576 M_counters [CPT_PL_FailedCall]++;
577 M_counters [CPT_C_CurrentCall]--;
578 break;
579
580 case E_CALL_SUCCESSFULLY_ENDED :
581 M_counters [CPT_C_SuccessfulCall]++;
582 M_counters [CPT_PD_SuccessfulCall]++;
583 M_counters [CPT_PL_SuccessfulCall]++;
584 M_counters [CPT_C_CurrentCall]--;
585 break;
586
587 case E_FAILED_CANNOT_SEND_MSG :
588 M_counters [CPT_C_FailedCallCannotSendMessage]++;
589 M_counters [CPT_PD_FailedCallCannotSendMessage]++;
590 M_counters [CPT_PL_FailedCallCannotSendMessage]++;
591 break;
592
593 case E_FAILED_MAX_UDP_RETRANS :
594 M_counters [CPT_C_FailedCallMaxUdpRetrans]++;
595 M_counters [CPT_PD_FailedCallMaxUdpRetrans]++;
596 M_counters [CPT_PL_FailedCallMaxUdpRetrans]++;
597 break;
598
599 case E_FAILED_TCP_CONNECT :
600 M_counters [CPT_C_FailedCallTcpConnect]++;
601 M_counters [CPT_PD_FailedCallTcpConnect]++;
602 M_counters [CPT_PL_FailedCallTcpConnect]++;
603 break;
604
605 case E_FAILED_TCP_CLOSED :
606 M_counters [CPT_C_FailedCallTcpClosed]++;
607 M_counters [CPT_PD_FailedCallTcpClosed]++;
608 M_counters [CPT_PL_FailedCallTcpClosed]++;
609 break;
610
611 case E_FAILED_UNEXPECTED_MSG :
612 M_counters [CPT_C_FailedCallUnexpectedMessage]++;
613 M_counters [CPT_PD_FailedCallUnexpectedMessage]++;
614 M_counters [CPT_PL_FailedCallUnexpectedMessage]++;
615 break;
616
617 case E_FAILED_CALL_REJECTED :
618 M_counters [CPT_C_FailedCallCallRejected]++;
619 M_counters [CPT_PD_FailedCallCallRejected]++;
620 M_counters [CPT_PL_FailedCallCallRejected]++;
621 break;
622
623 case E_FAILED_CMD_NOT_SENT :
624 M_counters [CPT_C_FailedCallCmdNotSent]++;
625 M_counters [CPT_PD_FailedCallCmdNotSent]++;
626 M_counters [CPT_PL_FailedCallCmdNotSent]++;
627 break;
628
629 case E_FAILED_REGEXP_DOESNT_MATCH :
630 M_counters [CPT_C_FailedCallRegexpDoesntMatch]++;
631 M_counters [CPT_PD_FailedCallRegexpDoesntMatch]++;
632 M_counters [CPT_PL_FailedCallRegexpDoesntMatch]++;
633 break;
634
635 case E_FAILED_REGEXP_SHOULDNT_MATCH :
636 M_counters [CPT_C_FailedCallRegexpShouldntMatch]++;
637 M_counters [CPT_PD_FailedCallRegexpShouldntMatch]++;
638 M_counters [CPT_PL_FailedCallRegexpShouldntMatch]++;
639 break;
640
641 case E_FAILED_REGEXP_HDR_NOT_FOUND :
642 M_counters [CPT_C_FailedCallRegexpHdrNotFound]++;
643 M_counters [CPT_PD_FailedCallRegexpHdrNotFound]++;
644 M_counters [CPT_PL_FailedCallRegexpHdrNotFound]++;
645 break;
646
647 case E_FAILED_OUTBOUND_CONGESTION :
648 M_counters [CPT_C_FailedOutboundCongestion]++;
649 M_counters [CPT_PD_FailedOutboundCongestion]++;
650 M_counters [CPT_PL_FailedOutboundCongestion]++;
651 break;
652
653 case E_FAILED_TIMEOUT_ON_RECV :
654 M_counters [CPT_C_FailedTimeoutOnRecv]++;
655 M_counters [CPT_PD_FailedTimeoutOnRecv]++;
656 M_counters [CPT_PL_FailedTimeoutOnRecv]++;
657 break;
658
659 case E_FAILED_TIMEOUT_ON_SEND :
660 M_counters [CPT_C_FailedTimeoutOnSend]++;
661 M_counters [CPT_PD_FailedTimeoutOnSend]++;
662 M_counters [CPT_PL_FailedTimeoutOnSend]++;
663 break;
664
665 case E_RETRANSMISSION :
666 M_counters [CPT_C_Retransmissions]++;
667 M_counters [CPT_PD_Retransmissions]++;
668 M_counters [CPT_PL_Retransmissions]++;
669 break;
670
671 case E_RESET_C_COUNTERS :
672 RESET_C_COUNTERS;
673 GET_TIME (&M_startTime);
674 break;
675
676 case E_RESET_PD_COUNTERS :
677 //DEBUG (C_Debug::E_LEVEL_4, "ENTER CASE", "%s",
678 // "CStat::computeStat : RESET_PD_COUNTERS");
679 RESET_PD_COUNTERS;
680 GET_TIME (&M_pdStartTime);
681 break;
682
683 case E_RESET_PL_COUNTERS :
684 //DEBUG (C_Debug::E_LEVEL_4, "ENTER CASE", "%s",
685 // "C_Stat::computeStat : RESET_PL_COUNTERS");
686 RESET_PL_COUNTERS;
687 GET_TIME (&M_plStartTime);
688 if (periodic_rtd) {
689 resetRepartition(M_CallLengthRepartition, M_SizeOfCallLengthRepartition);
690 for (int i = 0; i < nRtds(); i++) {
691 resetRepartition(M_ResponseTimeRepartition[i], M_SizeOfResponseTimeRepartition);
692 }
693 }
694 break;
695
696 default :
697 ERROR("CStat::ComputeStat() - Unrecognized Action %d\n", P_action);
698 return (-1);
699 } /* end switch */
700 return (0);
701 }
702
globalStat(E_Action P_action)703 int CStat::globalStat (E_Action P_action)
704 {
705 switch (P_action) {
706 case E_OUT_OF_CALL_MSGS :
707 M_G_counters [CPT_G_C_OutOfCallMsgs - E_NB_COUNTER - 1]++;
708 M_G_counters [CPT_G_PD_OutOfCallMsgs - E_NB_COUNTER - 1]++;
709 M_G_counters [CPT_G_PL_OutOfCallMsgs - E_NB_COUNTER - 1]++;
710 break;
711
712 case E_WATCHDOG_MAJOR :
713 M_G_counters [CPT_G_C_WatchdogMajor - E_NB_COUNTER - 1]++;
714 M_G_counters [CPT_G_PD_WatchdogMajor - E_NB_COUNTER - 1]++;
715 M_G_counters [CPT_G_PL_WatchdogMajor - E_NB_COUNTER - 1]++;
716 break;
717
718 case E_WATCHDOG_MINOR :
719 M_G_counters [CPT_G_C_WatchdogMinor - E_NB_COUNTER - 1]++;
720 M_G_counters [CPT_G_PD_WatchdogMinor - E_NB_COUNTER - 1]++;
721 M_G_counters [CPT_G_PL_WatchdogMinor - E_NB_COUNTER - 1]++;
722 break;
723
724 case E_DEAD_CALL_MSGS :
725 M_G_counters [CPT_G_C_DeadCallMsgs - E_NB_COUNTER - 1]++;
726 M_G_counters [CPT_G_PD_DeadCallMsgs - E_NB_COUNTER - 1]++;
727 M_G_counters [CPT_G_PL_DeadCallMsgs - E_NB_COUNTER - 1]++;
728 break;
729
730 case E_FATAL_ERRORS :
731 M_G_counters [CPT_G_C_FatalErrors - E_NB_COUNTER - 1]++;
732 M_G_counters [CPT_G_PD_FatalErrors - E_NB_COUNTER - 1]++;
733 M_G_counters [CPT_G_PL_FatalErrors - E_NB_COUNTER - 1]++;
734 break;
735
736 case E_WARNING :
737 M_G_counters [CPT_G_C_Warnings - E_NB_COUNTER - 1]++;
738 M_G_counters [CPT_G_PD_Warnings - E_NB_COUNTER - 1]++;
739 M_G_counters [CPT_G_PL_Warnings - E_NB_COUNTER - 1]++;
740 break;
741
742 case E_AUTO_ANSWERED :
743 // Let's count the automatic answered calls
744 M_G_counters [CPT_G_C_AutoAnswered - E_NB_COUNTER - 1]++;
745 M_G_counters [CPT_G_PD_AutoAnswered - E_NB_COUNTER - 1]++;
746 M_G_counters [CPT_G_PL_AutoAnswered - E_NB_COUNTER - 1]++;
747 break;
748 default :
749 ERROR("CStat::ComputeStat() - Unrecognized Action %d\n", P_action);
750 return (-1);
751 } /* end switch */
752 return (0);
753 }
754
755
computeRtt(unsigned long long P_start_time,unsigned long long P_stop_time,int which)756 void CStat::computeRtt (unsigned long long P_start_time, unsigned long long P_stop_time, int which)
757 {
758 M_dumpRespTime[M_counterDumpRespTime].date = (double)P_stop_time / (double)1000;
759 M_dumpRespTime[M_counterDumpRespTime].rtd_no = which;
760 M_dumpRespTime[M_counterDumpRespTime].rtt =
761 ((double)(P_stop_time - P_start_time)) / (double)1000;
762 M_counterDumpRespTime++ ;
763
764 if (M_counterDumpRespTime > (M_report_freq_dumpRtt - 1)) {
765 dumpDataRtt () ;
766 }
767 }
768
GetStat(E_CounterName P_counter)769 unsigned long long CStat::GetStat (E_CounterName P_counter)
770 {
771 if (P_counter < E_NB_COUNTER) {
772 return M_counters [P_counter];
773 } else {
774 return M_G_counters [P_counter - E_NB_COUNTER - 1];
775 }
776 }
777
778 /* Get the current start time. */
getStartTime(struct timeval * t)779 void CStat::getStartTime(struct timeval *t)
780 {
781 memcpy(t, &M_startTime, sizeof(M_startTime));
782 }
783
784
785 /* Use the short form standard deviation formula given the sum of the squares
786 * and the sum. */
computeStdev(E_CounterName P_SumCounter,E_CounterName P_NbOfCallUsed,E_CounterName P_Squares)787 double CStat::computeStdev(E_CounterName P_SumCounter,
788 E_CounterName P_NbOfCallUsed,
789 E_CounterName P_Squares)
790 {
791 if (M_counters[P_NbOfCallUsed] <= 0)
792 return 0.0;
793
794 double numerator = ((double)(M_counters[P_NbOfCallUsed]) * (double)(M_counters[P_Squares])) - ((double)(M_counters[P_SumCounter] * M_counters[P_SumCounter]));
795 double denominator = (double)(M_counters[P_NbOfCallUsed]) * (((double)(M_counters[P_NbOfCallUsed])) - 1.0);
796
797 return sqrt(numerator/denominator);
798 }
799
computeMean(E_CounterName P_SumCounter,E_CounterName P_NbOfCallUsed)800 double CStat::computeMean(E_CounterName P_SumCounter,
801 E_CounterName P_NbOfCallUsed)
802 {
803 if (M_counters[P_NbOfCallUsed] == 0)
804 return 0.0;
805 return ((double)(M_counters[P_SumCounter]) / (double)(M_counters[P_NbOfCallUsed]));
806 }
807
computeRtdMean(int which,int type)808 double CStat::computeRtdMean(int which, int type)
809 {
810 unsigned long long count = M_rtdInfo[((which - 1) * RTD_TYPES * GENERIC_TYPES) + (type * RTD_TYPES) + RTD_COUNT];
811 unsigned long long sum = M_rtdInfo[((which - 1) * RTD_TYPES * GENERIC_TYPES) + (type * RTD_TYPES) + RTD_SUM];
812
813 if (count == 0)
814 return 0.0;
815 return ((double)(sum) / (double)(count));
816 }
817
computeRtdStdev(int which,int type)818 double CStat::computeRtdStdev(int which, int type)
819 {
820 unsigned long long count = M_rtdInfo[((which - 1) * RTD_TYPES * GENERIC_TYPES) + (type * RTD_TYPES) + RTD_COUNT];
821 unsigned long long sum = M_rtdInfo[((which - 1) * RTD_TYPES * GENERIC_TYPES) + (type * RTD_TYPES) + RTD_SUM];
822 unsigned long long sumsq = M_rtdInfo[((which - 1) * RTD_TYPES * GENERIC_TYPES) + (type * RTD_TYPES) + RTD_SUMSQ];
823
824 if (count <= 1)
825 return 0.0;
826
827 double numerator = ((double)count * (double)sumsq) - (double)(sum * sum);
828 double denominator = (double)(count) * ((double)(count) - 1.0);
829
830 return sqrt(numerator/denominator);
831 }
832
updateAverageCounter(E_CounterName P_SumCounter,E_CounterName P_NbOfCallUsed,E_CounterName P_Squares,unsigned long P_value)833 void CStat::updateAverageCounter(E_CounterName P_SumCounter,
834 E_CounterName P_NbOfCallUsed,
835 E_CounterName P_Squares,
836 unsigned long P_value)
837 {
838 if (M_counters [P_NbOfCallUsed] <= 0) {
839 M_counters [P_NbOfCallUsed] ++;
840 M_counters [P_SumCounter] = P_value;
841 M_counters [P_Squares] = (P_value * P_value);
842 } else {
843 M_counters [P_SumCounter] += P_value;
844 M_counters [P_Squares] += (P_value * P_value);
845 M_counters [P_NbOfCallUsed] ++;
846 }
847 }
848
computeStat(E_Action P_action,unsigned long P_value)849 int CStat::computeStat (E_Action P_action,
850 unsigned long P_value)
851 {
852 return computeStat(P_action, P_value, 0);
853 }
854
findCounter(const char * counter,bool alloc)855 int CStat::findCounter(const char *counter, bool alloc)
856 {
857 str_int_map::iterator it = M_genericMap.find(str_int_map::key_type(counter));
858 if (it != M_genericMap.end()) {
859 return it->second;
860 }
861 if (!alloc) {
862 return -1;
863 }
864 int ret = M_genericMap.size() + 1;
865 M_genericMap[str_int_map::key_type(counter)] = ret;
866
867 bool numeric = true;
868 const char *p = counter;
869 while (*p) {
870 if (!isdigit(*p)) {
871 numeric = false;
872 break;
873 }
874 p++;
875 }
876 if (numeric) {
877 char *s = new char[20];
878 snprintf(s, 20, "GenericCounter%s", counter);
879 M_revGenericMap[ret] = s;
880 M_genericDisplay[ret] = strdup(counter);
881 } else {
882 M_revGenericMap[ret] = strdup(counter);
883 M_genericDisplay[ret] = strdup(counter);
884 }
885
886
887 M_genericCounters = (unsigned long long *)realloc(M_genericCounters, sizeof(unsigned long long) * GENERIC_TYPES * M_genericMap.size());
888 if (!M_genericCounters) {
889 ERROR("Could not allocate generic counters!\n");
890 }
891 M_genericCounters[(ret - 1) * GENERIC_TYPES + GENERIC_C] = 0;
892 M_genericCounters[(ret - 1) * GENERIC_TYPES + GENERIC_PD] = 0;
893 M_genericCounters[(ret - 1)* GENERIC_TYPES + GENERIC_PL] = 0;
894
895 return ret;
896 }
897
findRtd(const char * name,bool start)898 int CStat::findRtd(const char *name, bool start)
899 {
900 str_int_map::iterator it = M_rtdMap.find(str_int_map::key_type(name));
901 if (it != M_rtdMap.end()) {
902 if (start) {
903 rtd_started[it->first] = true;
904 } else {
905 rtd_stopped[it->first] = true;
906 }
907 return it->second;
908 }
909
910 int ret = M_rtdMap.size() + 1;
911 M_rtdMap[str_int_map::key_type(name)] = ret;
912
913 M_revRtdMap[ret] = strdup(name);
914
915
916 M_rtdInfo = (unsigned long long *)realloc(M_rtdInfo, sizeof(unsigned long long) * RTD_TYPES * GENERIC_TYPES * M_rtdMap.size());
917 if (!M_rtdInfo) {
918 ERROR("Could not allocate RTD info!\n");
919 }
920 M_rtdInfo[((ret - 1) * RTD_TYPES * GENERIC_TYPES) + (GENERIC_C * RTD_TYPES) + RTD_COUNT] = 0;
921 M_rtdInfo[((ret - 1) * RTD_TYPES * GENERIC_TYPES) + (GENERIC_C * RTD_TYPES) + RTD_SUM] = 0;
922 M_rtdInfo[((ret - 1) * RTD_TYPES * GENERIC_TYPES) + (GENERIC_C * RTD_TYPES) + RTD_SUMSQ] = 0;
923
924 M_rtdInfo[((ret - 1) * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PD * RTD_TYPES) + RTD_COUNT] = 0;
925 M_rtdInfo[((ret - 1) * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PD * RTD_TYPES) + RTD_SUM] = 0;
926 M_rtdInfo[((ret - 1) * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PD * RTD_TYPES) + RTD_SUMSQ] = 0;
927
928 M_rtdInfo[((ret - 1) * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PL * RTD_TYPES) + RTD_COUNT] = 0;
929 M_rtdInfo[((ret - 1) * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PL * RTD_TYPES) + RTD_SUM] = 0;
930 M_rtdInfo[((ret - 1) * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PL * RTD_TYPES) + RTD_SUMSQ] = 0;
931
932 M_ResponseTimeRepartition = (T_dynamicalRepartition **)realloc(M_ResponseTimeRepartition, sizeof(T_dynamicalRepartition *) * M_rtdMap.size());
933 if (!M_ResponseTimeRepartition) {
934 ERROR("Could not allocate RTD info!\n");
935 }
936 M_ResponseTimeRepartition[ret - 1] = NULL;
937
938 if (start) {
939 rtd_started[name] = true;
940 } else {
941 rtd_stopped[name] = true;
942 }
943 return ret;
944 }
945
nRtds()946 int CStat::nRtds()
947 {
948 return M_rtdMap.size();
949 }
950
951 /* If you start an RTD, then you should be interested in collecting statistics for it. */
validateRtds()952 void CStat::validateRtds()
953 {
954 for (str_int_map::iterator it = rtd_started.begin(); it != rtd_started.end(); it++) {
955 str_int_map::iterator stopit = rtd_stopped.find(it->first);
956 if (stopit == rtd_stopped.end() || !stopit->second) {
957 ERROR("You have started Response Time Duration %s, but have never stopped it!", it->first.c_str());
958 }
959 }
960 }
961
computeStat(E_Action P_action,unsigned long P_value,int which)962 int CStat::computeStat (E_Action P_action,
963 unsigned long P_value,
964 int which)
965 {
966 switch (P_action) {
967 case E_ADD_CALL_DURATION :
968 // Updating Cumulative Counter
969 updateAverageCounter(CPT_C_AverageCallLength_Sum,
970 CPT_C_NbOfCallUsedForAverageCallLength,
971 CPT_C_AverageCallLength_Squares, P_value);
972 updateRepartition(M_CallLengthRepartition,
973 M_SizeOfCallLengthRepartition, P_value);
974 // Updating Periodical Diplayed counter
975 updateAverageCounter(CPT_PD_AverageCallLength_Sum,
976 CPT_PD_NbOfCallUsedForAverageCallLength,
977 CPT_PD_AverageCallLength_Squares, P_value);
978 // Updating Periodical Logging counter
979 updateAverageCounter(CPT_PL_AverageCallLength_Sum,
980 CPT_PL_NbOfCallUsedForAverageCallLength,
981 CPT_PL_AverageCallLength_Squares, P_value);
982 break;
983
984
985 case E_ADD_GENERIC_COUNTER :
986 M_genericCounters[which * GENERIC_TYPES + GENERIC_C] += P_value;
987 M_genericCounters[which * GENERIC_TYPES + GENERIC_PD] += P_value;
988 M_genericCounters[which * GENERIC_TYPES + GENERIC_PL] += P_value;
989 break;
990
991 case E_ADD_RESPONSE_TIME_DURATION :
992 // Updating Cumulative Counter
993 M_rtdInfo[(which * RTD_TYPES * GENERIC_TYPES) + (GENERIC_C * RTD_TYPES) + RTD_COUNT]++;
994 M_rtdInfo[(which * RTD_TYPES * GENERIC_TYPES) + (GENERIC_C * RTD_TYPES) + RTD_SUM] += P_value;
995 M_rtdInfo[(which * RTD_TYPES * GENERIC_TYPES) + (GENERIC_C * RTD_TYPES) + RTD_SUMSQ] += (P_value * P_value);
996 updateRepartition(M_ResponseTimeRepartition[which], M_SizeOfResponseTimeRepartition, P_value);
997
998 // Updating Periodical Diplayed counter
999 M_rtdInfo[(which * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PD * RTD_TYPES) + RTD_COUNT]++;
1000 M_rtdInfo[(which * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PD * RTD_TYPES) + RTD_SUM] += P_value;
1001 M_rtdInfo[(which * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PD * RTD_TYPES) + RTD_SUMSQ] += (P_value * P_value);
1002
1003 // Updating Periodical Logging counter
1004 M_rtdInfo[(which * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PL * RTD_TYPES) + RTD_COUNT]++;
1005 M_rtdInfo[(which * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PL * RTD_TYPES) + RTD_SUM] += P_value;
1006 M_rtdInfo[(which * RTD_TYPES * GENERIC_TYPES) + (GENERIC_PL * RTD_TYPES) + RTD_SUMSQ] += (P_value * P_value);
1007 break;
1008
1009 default :
1010 ERROR("CStat::ComputeStat() - Unrecognized Action %d\n", P_action);
1011 return (-1);
1012 } /* end switch */
1013 return (0);
1014 }
1015
1016
updateRepartition(T_dynamicalRepartition * P_tabReport,int P_sizeOfTab,unsigned long P_value)1017 void CStat::updateRepartition(T_dynamicalRepartition* P_tabReport,
1018 int P_sizeOfTab,
1019 unsigned long P_value)
1020 {
1021 if(P_tabReport == NULL) {
1022 return;
1023 }
1024
1025 for (int i = 0; i < P_sizeOfTab - 1; i++) {
1026 if (P_value < P_tabReport[i].borderMax) {
1027 P_tabReport[i].nbInThisBorder++;
1028 return;
1029 }
1030 }
1031
1032 /* If this is not true, we never should have gotten here. */
1033 assert(P_value >= P_tabReport[P_sizeOfTab-1].borderMax);
1034 P_tabReport[P_sizeOfTab-1].nbInThisBorder ++;
1035 }
1036
resetRepartition(T_dynamicalRepartition * P_tabReport,int P_sizeOfTab)1037 void CStat::resetRepartition(T_dynamicalRepartition* P_tabReport,
1038 int P_sizeOfTab)
1039 {
1040 if(P_tabReport == NULL) {
1041 return;
1042 }
1043
1044 for (int i = 0; i < P_sizeOfTab; i++) {
1045 P_tabReport[i].nbInThisBorder = 0;
1046 }
1047 }
1048
1049
CStat()1050 CStat::CStat ()
1051 {
1052 size_t L_size = 0;
1053 L_size += strlen(DEFAULT_FILE_NAME) ;
1054 L_size += strlen(DEFAULT_EXTENSION) ;
1055 L_size += 1 ;
1056 M_fileName = new char[L_size];
1057 strcpy(M_fileName, DEFAULT_FILE_NAME);
1058 strcat(M_fileName, DEFAULT_EXTENSION);
1059 M_ResponseTimeRepartition = NULL;
1060 M_CallLengthRepartition = NULL;
1061 M_SizeOfResponseTimeRepartition = 0;
1062 M_SizeOfCallLengthRepartition = 0;
1063 M_fileNameRtt = NULL;
1064 M_genericCounters = NULL;
1065 M_time_ref = 0.0 ;
1066 M_dumpRespTime = NULL ;
1067 M_counterDumpRespTime = 0 ;
1068 M_dumpRespTime = NULL;
1069 M_fileNameRtt = NULL;
1070 M_rtdInfo = NULL;
1071
1072 init();
1073 }
1074
sRepartitionHeader(T_dynamicalRepartition * tabRepartition,int sizeOfTab,const char * P_repartitionName)1075 char* CStat::sRepartitionHeader(T_dynamicalRepartition * tabRepartition,
1076 int sizeOfTab,
1077 const char * P_repartitionName)
1078 {
1079 static char *repartitionHeader = NULL;
1080 char buffer[MAX_CHAR_BUFFER_SIZE];
1081 int dlen = strlen(stat_delimiter);
1082
1083 if(tabRepartition != NULL) {
1084 repartitionHeader = (char *)realloc(repartitionHeader, strlen(P_repartitionName) + dlen + 1);
1085 sprintf(repartitionHeader, "%s%s", P_repartitionName, stat_delimiter);
1086 for(int i=0; i<(sizeOfTab-1); i++) {
1087 sprintf(buffer, "%s_<%d%s", P_repartitionName, tabRepartition[i].borderMax, stat_delimiter);
1088 repartitionHeader = (char *)realloc(repartitionHeader, strlen(repartitionHeader) + strlen(buffer) + 1);
1089 strcat(repartitionHeader, buffer);
1090 }
1091 sprintf(buffer, "%s_>=%d%s", P_repartitionName, tabRepartition[sizeOfTab-1].borderMax, stat_delimiter);
1092 repartitionHeader = (char *)realloc(repartitionHeader, strlen(repartitionHeader) + strlen(buffer) + 1);
1093 strcat(repartitionHeader, buffer);
1094 } else {
1095 repartitionHeader = (char *)realloc(repartitionHeader, 2);
1096 strcpy(repartitionHeader, "");
1097 }
1098
1099 return(repartitionHeader);
1100 }
1101
sRepartitionInfo(T_dynamicalRepartition * tabRepartition,int sizeOfTab)1102 char* CStat::sRepartitionInfo(T_dynamicalRepartition * tabRepartition,
1103 int sizeOfTab)
1104 {
1105 static char *repartitionInfo;
1106 char buffer[MAX_CHAR_BUFFER_SIZE];
1107 int dlen = strlen(stat_delimiter);
1108
1109 if(tabRepartition != NULL) {
1110 // if a repartition is present, this field match the repartition name
1111 repartitionInfo = (char *)realloc(repartitionInfo, dlen + 1);
1112 sprintf(repartitionInfo, "%s", stat_delimiter);
1113 for(int i=0; i<(sizeOfTab-1); i++) {
1114 sprintf(buffer, "%lu%s", tabRepartition[i].nbInThisBorder, stat_delimiter);
1115 repartitionInfo = (char *)realloc(repartitionInfo, strlen(repartitionInfo) + strlen(buffer) + 1);
1116 strcat(repartitionInfo, buffer);
1117 }
1118 sprintf(buffer, "%lu%s", tabRepartition[sizeOfTab-1].nbInThisBorder, stat_delimiter);
1119 repartitionInfo = (char *)realloc(repartitionInfo, strlen(repartitionInfo) + strlen(buffer) + 1);
1120 strcat(repartitionInfo, buffer);
1121 } else {
1122 repartitionInfo = (char *)realloc(repartitionInfo, 2);
1123 repartitionInfo[0] = '\0';
1124 }
1125
1126 return(repartitionInfo);
1127 }
1128
1129
displayRepartition(FILE * f,T_dynamicalRepartition * tabRepartition,int sizeOfTab)1130 void CStat::displayRepartition(FILE *f,
1131 T_dynamicalRepartition * tabRepartition,
1132 int sizeOfTab)
1133 {
1134 if(tabRepartition != NULL) {
1135 for(int i=0; i<(sizeOfTab-1); i++) {
1136 if(i==0) {
1137 DISPLAY_REPART(0, tabRepartition[i].borderMax,
1138 tabRepartition[i].nbInThisBorder);
1139 } else {
1140 DISPLAY_REPART(tabRepartition[i-1].borderMax,
1141 tabRepartition[i].borderMax,
1142 tabRepartition[i].nbInThisBorder);
1143 }
1144 }
1145 DISPLAY_LAST_REPART (tabRepartition[sizeOfTab-1].borderMax,
1146 tabRepartition[sizeOfTab-1].nbInThisBorder);
1147 } else {
1148 DISPLAY_INFO (" <No repartion defined>");
1149 }
1150 }
1151
displayData(FILE * f)1152 void CStat::displayData (FILE *f)
1153 {
1154 long localElapsedTime, globalElapsedTime ;
1155 struct timeval currentTime;
1156 float averageCallRate;
1157 float realInstantCallRate;
1158 unsigned long numberOfCall;
1159
1160 GET_TIME (¤tTime);
1161 // computing the real call rate
1162 globalElapsedTime = computeDiffTimeInMs (¤tTime, &M_startTime);
1163 localElapsedTime = computeDiffTimeInMs (¤tTime, &M_pdStartTime);
1164
1165 // the call rate is for all the call : incoming and outgoing
1166 numberOfCall = M_counters[CPT_C_IncomingCallCreated] +
1167 M_counters[CPT_C_OutgoingCallCreated];
1168 averageCallRate = (globalElapsedTime > 0 ?
1169 1000*(float)numberOfCall/(float)globalElapsedTime
1170 : 0.0);
1171 numberOfCall = (M_counters[CPT_PD_IncomingCallCreated] +
1172 M_counters[CPT_PD_OutgoingCallCreated]);
1173 realInstantCallRate = (localElapsedTime > 0 ?
1174 1000*(float)numberOfCall / (float)localElapsedTime :
1175 0.0);
1176
1177 // display info
1178 DISPLAY_DLINE ();
1179 // build and display header info
1180 DISPLAY_TXT ("Start Time ", formatTime(&M_startTime));
1181 DISPLAY_TXT ("Last Reset Time", formatTime(&M_pdStartTime));
1182 DISPLAY_TXT ("Current Time", formatTime(¤tTime));
1183
1184 // printing the header in the middle
1185 DISPLAY_CROSS_LINE();
1186 DISPLAY_HEADER();
1187 DISPLAY_CROSS_LINE();
1188
1189 DISPLAY_TXT_COL ("Elapsed Time",
1190 msToHHMMSSus(localElapsedTime),
1191 msToHHMMSSus(globalElapsedTime));
1192
1193 DISPLAY_VAL_RATEF_COL ("Call Rate",
1194 realInstantCallRate,
1195 averageCallRate);
1196 DISPLAY_CROSS_LINE ();
1197
1198 DISPLAY_2VAL ("Incoming call created",
1199 M_counters[CPT_PD_IncomingCallCreated],
1200 M_counters[CPT_C_IncomingCallCreated]);
1201 DISPLAY_2VAL ("OutGoing call created",
1202 M_counters[CPT_PD_OutgoingCallCreated],
1203 M_counters[CPT_C_OutgoingCallCreated]);
1204 DISPLAY_CUMUL ("Total Call created", M_counters[CPT_C_IncomingCallCreated] +
1205 M_counters[CPT_C_OutgoingCallCreated]);
1206 DISPLAY_PERIO ("Current Call", M_counters[CPT_C_CurrentCall]);
1207
1208 if (M_genericMap.size()) {
1209 DISPLAY_CROSS_LINE ();
1210 }
1211 for (unsigned int i = 1; i < M_genericMap.size() + 1; i++) {
1212 char *s = (char *)malloc(20 + strlen(M_genericDisplay[i]));
1213 sprintf(s, "Counter %s", M_genericDisplay[i]);
1214
1215 DISPLAY_2VAL(s, M_genericCounters[(i - 1) * GENERIC_TYPES + GENERIC_PD], M_genericCounters[(i - 1) * GENERIC_TYPES + GENERIC_C]);
1216 free(s);
1217 }
1218
1219 DISPLAY_CROSS_LINE ();
1220 DISPLAY_2VAL ("Successful call",
1221 M_counters[CPT_PD_SuccessfulCall],
1222 M_counters[CPT_C_SuccessfulCall]);
1223 DISPLAY_2VAL ("Failed call",
1224 M_counters[CPT_PD_FailedCall],
1225 M_counters[CPT_C_FailedCall]);
1226 // DISPLAY_2VAL ("Unexpected msg",
1227 // M_counters[CPT_PD_UnexpectedMessage],
1228 // M_counters[CPT_C_UnexpectedMessage]);
1229
1230
1231 DISPLAY_CROSS_LINE ();
1232 for (int i = 1; i <= nRtds(); i++) {
1233 char s[80];
1234
1235 /* Skip if we aren't stopped. */
1236 assert(rtd_stopped[M_revRtdMap[i]] == true);
1237
1238 sprintf(s, "Response Time %s", M_revRtdMap[i]);
1239 DISPLAY_TXT_COL (s,
1240 msToHHMMSSus( (unsigned long)computeRtdMean(i, GENERIC_PD)),
1241 msToHHMMSSus( (unsigned long)computeRtdMean(i, GENERIC_C)));
1242 }
1243 /* I Broke this!
1244 DISPLAY_TXT_COL ("Call Length",
1245 msToHHMMSSus( (unsigned long)computeMean(CPT_PD_AverageCallLength_Sum, CPT_PD_NbOfCallUsedForAverageCallLength)),
1246 msToHHMMSSus( (unsigned long)computeMean(CPT_C_AverageCallLength_Sum, CPT_C_NbOfCallUsedForAverageCallLength) ));
1247 */
1248 DISPLAY_CROSS_LINE ();
1249
1250 for (int i = 1; i <= nRtds(); i++) {
1251 displayRtdRepartition(f, i);
1252 }
1253 DISPLAY_INFO("Average Call Length Repartition");
1254 displayRepartition(f, M_CallLengthRepartition, M_SizeOfCallLengthRepartition);
1255
1256 // DISPLAY_VAL ("NbCall Average RT(P)",
1257 // M_counters[CPT_PD_NbOfCallUsedForAverageResponseTime]);
1258 // DISPLAY_VAL ("NbCall Average RT",
1259 // M_counters[CPT_C_NbOfCallUsedForAverageResponseTime]);
1260 // DISPLAY_VAL ("NbCall Average CL",
1261 // M_counters[CPT_C_NbOfCallUsedForAverageCallLength]);
1262 // DISPLAY_VAL ("NbCall Average CL(P)",
1263 // M_counters[CPT_PD_NbOfCallUsedForAverageCallLength]);
1264 DISPLAY_DLINE ();
1265 fflush(f);
1266 } /* end of displayData () */
1267
1268
displayStat(FILE * f)1269 void CStat::displayStat (FILE *f)
1270 {
1271 long localElapsedTime, globalElapsedTime ;
1272 struct timeval currentTime;
1273 float averageCallRate;
1274 float realInstantCallRate;
1275 unsigned long numberOfCall;
1276
1277 GET_TIME (¤tTime);
1278 // computing the real call rate
1279 globalElapsedTime = computeDiffTimeInMs (¤tTime, &M_startTime);
1280 localElapsedTime = computeDiffTimeInMs (¤tTime, &M_pdStartTime);
1281 // the call rate is for all the call : incoming and outgoing
1282 numberOfCall = (M_counters[CPT_C_IncomingCallCreated] +
1283 M_counters[CPT_C_OutgoingCallCreated]);
1284 averageCallRate = (globalElapsedTime > 0 ?
1285 1000*(float)numberOfCall/(float)globalElapsedTime :
1286 0.0);
1287 numberOfCall = (M_counters[CPT_PD_IncomingCallCreated] +
1288 M_counters[CPT_PD_OutgoingCallCreated]);
1289 realInstantCallRate = (localElapsedTime > 0 ?
1290 1000*(float)numberOfCall / (float)localElapsedTime :
1291 0.0);
1292
1293 // build and display header info
1294 DISPLAY_TXT ("Start Time ", formatTime(&M_startTime));
1295 DISPLAY_TXT ("Last Reset Time", formatTime(&M_pdStartTime));
1296 DISPLAY_TXT ("Current Time", formatTime(¤tTime));
1297
1298 // printing the header in the middle
1299 DISPLAY_CROSS_LINE();
1300 DISPLAY_HEADER();
1301 DISPLAY_CROSS_LINE();
1302
1303 DISPLAY_TXT_COL ("Elapsed Time",
1304 msToHHMMSSus(localElapsedTime),
1305 msToHHMMSSus(globalElapsedTime));
1306
1307 DISPLAY_VAL_RATEF_COL ("Call Rate", realInstantCallRate, averageCallRate);
1308 DISPLAY_CROSS_LINE ();
1309
1310 DISPLAY_2VAL ("Incoming call created",
1311 M_counters[CPT_PD_IncomingCallCreated],
1312 M_counters[CPT_C_IncomingCallCreated]);
1313 DISPLAY_2VAL ("OutGoing call created",
1314 M_counters[CPT_PD_OutgoingCallCreated],
1315 M_counters[CPT_C_OutgoingCallCreated]);
1316 DISPLAY_CUMUL ("Total Call created", M_counters[CPT_C_IncomingCallCreated] +
1317 M_counters[CPT_C_OutgoingCallCreated]);
1318 DISPLAY_PERIO ("Current Call",
1319 M_counters[CPT_C_CurrentCall]);
1320
1321 if (M_genericMap.size()) {
1322 DISPLAY_CROSS_LINE ();
1323 }
1324 for (unsigned int i = 1; i < M_genericMap.size() + 1; i++) {
1325 char *s = (char *)malloc(20 + strlen(M_genericDisplay[i]));
1326 sprintf(s, "Counter %s", M_genericDisplay[i]);
1327
1328 DISPLAY_2VAL(s, M_genericCounters[(i - 1)* GENERIC_TYPES + GENERIC_PD], M_genericCounters[(i - 1) * GENERIC_TYPES + GENERIC_C]);
1329 free(s);
1330 }
1331
1332 DISPLAY_CROSS_LINE ();
1333 DISPLAY_2VAL ("Successful call",
1334 M_counters[CPT_PD_SuccessfulCall],
1335 M_counters[CPT_C_SuccessfulCall]);
1336 DISPLAY_2VAL ("Failed call",
1337 M_counters[CPT_PD_FailedCall],
1338 M_counters[CPT_C_FailedCall]);
1339 //DISPLAY_2VAL ("Unexpected msg",
1340 // M_counters[CPT_PD_UnexpectedMessage],
1341 // M_counters[CPT_C_UnexpectedMessage]);
1342
1343 DISPLAY_CROSS_LINE ();
1344 for (int i = 1; i <= nRtds(); i++) {
1345 char s[80];
1346
1347 sprintf(s, "Response Time %s", M_revRtdMap[i]);
1348 DISPLAY_TXT_COL (s,
1349 msToHHMMSSus( (unsigned long)computeRtdMean(i, GENERIC_PD)),
1350 msToHHMMSSus( (unsigned long)computeRtdMean(i, GENERIC_C)));
1351 }
1352 DISPLAY_TXT_COL ("Call Length",
1353 msToHHMMSSus( (unsigned long)computeMean(CPT_PD_AverageCallLength_Sum, CPT_PD_NbOfCallUsedForAverageCallLength ) ),
1354 msToHHMMSSus( (unsigned long)computeMean(CPT_C_AverageCallLength_Sum, CPT_C_NbOfCallUsedForAverageCallLength) ));
1355 fflush(f);
1356 }
1357
displayRepartition(FILE * f)1358 void CStat::displayRepartition (FILE *f)
1359 {
1360 displayRtdRepartition(f, 1);
1361 DISPLAY_INFO("Average Call Length Repartition");
1362 displayRepartition(f,
1363 M_CallLengthRepartition,
1364 M_SizeOfCallLengthRepartition);
1365 }
1366
displayRtdRepartition(FILE * f,int which)1367 void CStat::displayRtdRepartition (FILE *f, int which)
1368 {
1369 if (which > nRtds()) {
1370 DISPLAY_INFO (" <No repartion defined>");
1371 return;
1372 }
1373
1374 char s[80];
1375 snprintf(s, sizeof(s), "Average Response Time Repartition %s", M_revRtdMap[which]);
1376 DISPLAY_INFO(s);
1377 displayRepartition(f,
1378 M_ResponseTimeRepartition[which - 1],
1379 M_SizeOfResponseTimeRepartition);
1380 }
1381
1382
dumpData()1383 void CStat::dumpData ()
1384 {
1385 long localElapsedTime, globalElapsedTime ;
1386 struct timeval currentTime;
1387 float averageCallRate;
1388 float realInstantCallRate;
1389 unsigned long numberOfCall;
1390
1391 // computing the real call rate
1392 GET_TIME (¤tTime);
1393 globalElapsedTime = computeDiffTimeInMs (¤tTime, &M_startTime);
1394 localElapsedTime = computeDiffTimeInMs (¤tTime, &M_plStartTime);
1395
1396 // the call rate is for all the call : incoming and outgoing
1397 numberOfCall = (M_counters[CPT_C_IncomingCallCreated] +
1398 M_counters[CPT_C_OutgoingCallCreated]);
1399 averageCallRate = (globalElapsedTime > 0 ?
1400 1000*(float)numberOfCall/(float)globalElapsedTime :
1401 0.0);
1402 numberOfCall = (M_counters[CPT_PL_IncomingCallCreated] +
1403 M_counters[CPT_PL_OutgoingCallCreated]);
1404 realInstantCallRate = (localElapsedTime > 0 ?
1405 1000*(float)numberOfCall / (float)localElapsedTime :
1406 0.0);
1407
1408 if(M_outputStream == NULL) {
1409 // if the file is still not opened, we opened it now
1410 M_outputStream = new ofstream(M_fileName);
1411 M_headerAlreadyDisplayed = false;
1412
1413 if(M_outputStream == NULL) {
1414 cerr << "Unable to open stat file '" << M_fileName << "' !" << endl;
1415 exit(EXIT_FATAL_ERROR);
1416 }
1417
1418 #ifndef __osf__
1419 if(!M_outputStream->is_open()) {
1420 cerr << "Unable to open stat file '" << M_fileName << "' !" << endl;
1421 exit(EXIT_FATAL_ERROR);
1422 }
1423 #endif
1424
1425 }
1426
1427 if(M_headerAlreadyDisplayed == false) {
1428 // header - it's dump in file only one time at the beginning of the file
1429 (*M_outputStream) << "StartTime" << stat_delimiter
1430 << "LastResetTime" << stat_delimiter
1431 << "CurrentTime" << stat_delimiter
1432 << "ElapsedTime(P)" << stat_delimiter
1433 << "ElapsedTime(C)" << stat_delimiter
1434 << "TargetRate" << stat_delimiter
1435 << "CallRate(P)" << stat_delimiter
1436 << "CallRate(C)" << stat_delimiter
1437 << "IncomingCall(P)" << stat_delimiter
1438 << "IncomingCall(C)" << stat_delimiter
1439 << "OutgoingCall(P)" << stat_delimiter
1440 << "OutgoingCall(C)" << stat_delimiter
1441 << "TotalCallCreated" << stat_delimiter
1442 << "CurrentCall" << stat_delimiter
1443 << "SuccessfulCall(P)" << stat_delimiter
1444 << "SuccessfulCall(C)" << stat_delimiter
1445 << "FailedCall(P)" << stat_delimiter
1446 << "FailedCall(C)" << stat_delimiter
1447 << "FailedCannotSendMessage(P)" << stat_delimiter
1448 << "FailedCannotSendMessage(C)" << stat_delimiter
1449 << "FailedMaxUDPRetrans(P)" << stat_delimiter
1450 << "FailedMaxUDPRetrans(C)" << stat_delimiter
1451 << "FailedTcpConnect(P)" << stat_delimiter
1452 << "FailedTcpConnect(C)" << stat_delimiter
1453 << "FailedTcpClosed(P)" << stat_delimiter
1454 << "FailedTcpClosed(C)" << stat_delimiter
1455 << "FailedUnexpectedMessage(P)" << stat_delimiter
1456 << "FailedUnexpectedMessage(C)" << stat_delimiter
1457 << "FailedCallRejected(P)" << stat_delimiter
1458 << "FailedCallRejected(C)" << stat_delimiter
1459 << "FailedCmdNotSent(P)" << stat_delimiter
1460 << "FailedCmdNotSent(C)" << stat_delimiter
1461 << "FailedRegexpDoesntMatch(P)" << stat_delimiter
1462 << "FailedRegexpDoesntMatch(C)" << stat_delimiter
1463 << "FailedRegexpShouldntMatch(P)" << stat_delimiter
1464 << "FailedRegexpShouldntMatch(C)" << stat_delimiter
1465 << "FailedRegexpHdrNotFound(P)" << stat_delimiter
1466 << "FailedRegexpHdrNotFound(C)" << stat_delimiter
1467 << "FailedOutboundCongestion(P)" << stat_delimiter
1468 << "FailedOutboundCongestion(C)" << stat_delimiter
1469 << "FailedTimeoutOnRecv(P)" << stat_delimiter
1470 << "FailedTimeoutOnRecv(C)" << stat_delimiter
1471 << "FailedTimeoutOnSend(P)" << stat_delimiter
1472 << "FailedTimeoutOnSend(C)" << stat_delimiter
1473 << "OutOfCallMsgs(P)" << stat_delimiter
1474 << "OutOfCallMsgs(C)" << stat_delimiter
1475 << "DeadCallMsgs(P)" << stat_delimiter
1476 << "DeadCallMsgs(C)" << stat_delimiter
1477 << "Retransmissions(P)" << stat_delimiter
1478 << "Retransmissions(C)" << stat_delimiter
1479 << "AutoAnswered(P)" << stat_delimiter
1480 << "AutoAnswered(C)" << stat_delimiter
1481 << "Warnings(P)" << stat_delimiter
1482 << "Warnings(C)" << stat_delimiter
1483 << "FatalErrors(P)" << stat_delimiter
1484 << "FatalErrors(C)" << stat_delimiter
1485 << "WatchdogMajor(P)" << stat_delimiter
1486 << "WatchdogMajor(C)" << stat_delimiter
1487 << "WatchdogMinor(P)" << stat_delimiter
1488 << "WatchdogMinor(C)" << stat_delimiter;
1489
1490 for (int i = 1; i <= nRtds(); i++) {
1491 char s_P[80];
1492 char s_C[80];
1493
1494 sprintf(s_P, "ResponseTime%s(P)%s", M_revRtdMap[i], stat_delimiter);
1495 sprintf(s_C, "ResponseTime%s(C)%s", M_revRtdMap[i], stat_delimiter);
1496
1497 (*M_outputStream) << s_P << s_C;
1498
1499 sprintf(s_P, "ResponseTime%sStDev(P)%s", M_revRtdMap[i], stat_delimiter);
1500 sprintf(s_C, "ResponseTime%sStDev(C)%s", M_revRtdMap[i], stat_delimiter);
1501
1502 (*M_outputStream) << s_P << s_C;
1503 }
1504
1505 (*M_outputStream) << "CallLength(P)" << stat_delimiter
1506 << "CallLength(C)" << stat_delimiter;
1507 (*M_outputStream) << "CallLengthStDev(P)" << stat_delimiter
1508 << "CallLengthStDev(C)" << stat_delimiter;
1509 for (unsigned int i = 1; i < M_genericMap.size() + 1; i++) {
1510 (*M_outputStream) << M_revGenericMap[i] << "(P)" << stat_delimiter;
1511 (*M_outputStream) << M_revGenericMap[i] << "(C)" << stat_delimiter;
1512 }
1513 for (int i = 1; i <= nRtds(); i++) {
1514 char s[80];
1515
1516 sprintf(s, "ResponseTimeRepartition%s", M_revRtdMap[i]);
1517 (*M_outputStream) << sRepartitionHeader(M_ResponseTimeRepartition[i - 1],
1518 M_SizeOfResponseTimeRepartition,
1519 s);
1520 }
1521 (*M_outputStream) << sRepartitionHeader(M_CallLengthRepartition,
1522 M_SizeOfCallLengthRepartition,
1523 "CallLengthRepartition");
1524 (*M_outputStream) << endl;
1525 M_headerAlreadyDisplayed = true;
1526 }
1527
1528 // content
1529 (*M_outputStream) << formatTime(&M_startTime) << stat_delimiter;
1530 (*M_outputStream) << formatTime(&M_plStartTime) << stat_delimiter;
1531 (*M_outputStream) << formatTime(¤tTime) << stat_delimiter
1532 << msToHHMMSS(localElapsedTime) << stat_delimiter;
1533 (*M_outputStream) << msToHHMMSS(globalElapsedTime) << stat_delimiter;
1534 if (users >= 0) {
1535 (*M_outputStream) << users << stat_delimiter;
1536 } else {
1537 (*M_outputStream) << rate << stat_delimiter;
1538 }
1539 (*M_outputStream) << realInstantCallRate << stat_delimiter
1540 << averageCallRate << stat_delimiter
1541 << M_counters[CPT_PL_IncomingCallCreated] << stat_delimiter
1542 << M_counters[CPT_C_IncomingCallCreated] << stat_delimiter
1543 << M_counters[CPT_PL_OutgoingCallCreated] << stat_delimiter
1544 << M_counters[CPT_C_OutgoingCallCreated] << stat_delimiter
1545 << (M_counters[CPT_C_IncomingCallCreated]+
1546 M_counters[CPT_C_OutgoingCallCreated])<< stat_delimiter
1547 << M_counters[CPT_C_CurrentCall] << stat_delimiter
1548 << M_counters[CPT_PL_SuccessfulCall] << stat_delimiter
1549 << M_counters[CPT_C_SuccessfulCall] << stat_delimiter
1550 << M_counters[CPT_PL_FailedCall] << stat_delimiter
1551 << M_counters[CPT_C_FailedCall] << stat_delimiter
1552 << M_counters[CPT_PL_FailedCallCannotSendMessage] << stat_delimiter
1553 << M_counters[CPT_C_FailedCallCannotSendMessage] << stat_delimiter
1554 << M_counters[CPT_PL_FailedCallMaxUdpRetrans] << stat_delimiter
1555 << M_counters[CPT_C_FailedCallMaxUdpRetrans ] << stat_delimiter
1556 << M_counters[CPT_PL_FailedCallTcpConnect] << stat_delimiter
1557 << M_counters[CPT_C_FailedCallTcpConnect] << stat_delimiter
1558 << M_counters[CPT_PL_FailedCallTcpClosed] << stat_delimiter
1559 << M_counters[CPT_C_FailedCallTcpClosed] << stat_delimiter
1560 << M_counters[CPT_PL_FailedCallUnexpectedMessage] << stat_delimiter
1561 << M_counters[CPT_C_FailedCallUnexpectedMessage] << stat_delimiter
1562 << M_counters[CPT_PL_FailedCallCallRejected] << stat_delimiter
1563 << M_counters[CPT_C_FailedCallCallRejected] << stat_delimiter
1564 << M_counters[CPT_PL_FailedCallCmdNotSent] << stat_delimiter
1565 << M_counters[CPT_C_FailedCallCmdNotSent] << stat_delimiter
1566 << M_counters[CPT_PL_FailedCallRegexpDoesntMatch] << stat_delimiter
1567 << M_counters[CPT_C_FailedCallRegexpDoesntMatch] << stat_delimiter
1568 << M_counters[CPT_PL_FailedCallRegexpShouldntMatch] << stat_delimiter
1569 << M_counters[CPT_C_FailedCallRegexpShouldntMatch] << stat_delimiter
1570 << M_counters[CPT_PL_FailedCallRegexpHdrNotFound] << stat_delimiter
1571 << M_counters[CPT_C_FailedCallRegexpHdrNotFound] << stat_delimiter
1572 << M_counters[CPT_PL_FailedOutboundCongestion] << stat_delimiter
1573 << M_counters[CPT_C_FailedOutboundCongestion] << stat_delimiter
1574 << M_counters[CPT_PL_FailedTimeoutOnRecv] << stat_delimiter
1575 << M_counters[CPT_C_FailedTimeoutOnRecv] << stat_delimiter
1576 << M_counters[CPT_PL_FailedTimeoutOnSend] << stat_delimiter
1577 << M_counters[CPT_C_FailedTimeoutOnSend] << stat_delimiter
1578 << M_G_counters[CPT_G_PL_OutOfCallMsgs - E_NB_COUNTER - 1] << stat_delimiter
1579 << M_G_counters[CPT_G_C_OutOfCallMsgs - E_NB_COUNTER - 1] << stat_delimiter
1580 << M_G_counters[CPT_G_PL_DeadCallMsgs - E_NB_COUNTER - 1] << stat_delimiter
1581 << M_G_counters[CPT_G_C_DeadCallMsgs - E_NB_COUNTER - 1] << stat_delimiter
1582 << M_counters[CPT_PL_Retransmissions] << stat_delimiter
1583 << M_counters[CPT_C_Retransmissions] << stat_delimiter
1584 << M_G_counters[CPT_G_PL_AutoAnswered - E_NB_COUNTER - 1] << stat_delimiter
1585 << M_G_counters[CPT_G_C_AutoAnswered - E_NB_COUNTER - 1] << stat_delimiter
1586 << M_G_counters[CPT_G_PL_Warnings - E_NB_COUNTER - 1] << stat_delimiter
1587 << M_G_counters[CPT_G_C_Warnings - E_NB_COUNTER - 1] << stat_delimiter
1588 << M_G_counters[CPT_G_PL_FatalErrors - E_NB_COUNTER - 1] << stat_delimiter
1589 << M_G_counters[CPT_G_C_FatalErrors - E_NB_COUNTER - 1] << stat_delimiter
1590 << M_G_counters[CPT_G_PL_WatchdogMajor - E_NB_COUNTER - 1] << stat_delimiter
1591 << M_G_counters[CPT_G_C_WatchdogMajor - E_NB_COUNTER - 1] << stat_delimiter
1592 << M_G_counters[CPT_G_PL_WatchdogMinor - E_NB_COUNTER - 1] << stat_delimiter
1593 << M_G_counters[CPT_G_C_WatchdogMinor - E_NB_COUNTER - 1] << stat_delimiter;
1594
1595 // SF917289 << M_counters[CPT_C_UnexpectedMessage] << stat_delimiter;
1596 for (int i = 1; i <= nRtds(); i++) {
1597 (*M_outputStream) << msToHHMMSSus( (unsigned long)computeRtdMean(i, GENERIC_PL)) << stat_delimiter;
1598 (*M_outputStream) << msToHHMMSSus( (unsigned long)computeRtdMean(i, GENERIC_C)) << stat_delimiter;
1599 (*M_outputStream) << msToHHMMSSus( (unsigned long)computeRtdStdev(i, GENERIC_PL)) << stat_delimiter;
1600 (*M_outputStream) << msToHHMMSSus( (unsigned long)computeRtdStdev(i, GENERIC_C)) << stat_delimiter;
1601 }
1602 (*M_outputStream)
1603 << msToHHMMSSus( (unsigned long)computeMean(CPT_PL_AverageCallLength_Sum, CPT_PL_NbOfCallUsedForAverageCallLength) ) << stat_delimiter;
1604 (*M_outputStream)
1605 << msToHHMMSSus( (unsigned long)computeMean(CPT_C_AverageCallLength_Sum, CPT_C_NbOfCallUsedForAverageCallLength) ) << stat_delimiter;
1606 (*M_outputStream)
1607 << msToHHMMSSus( (unsigned long)computeStdev(CPT_PL_AverageCallLength_Sum,
1608 CPT_PL_NbOfCallUsedForAverageCallLength,
1609 CPT_PL_AverageCallLength_Squares )) << stat_delimiter;
1610 (*M_outputStream)
1611 << msToHHMMSSus( (unsigned long)computeStdev(CPT_C_AverageCallLength_Sum,
1612 CPT_C_NbOfCallUsedForAverageCallLength,
1613 CPT_C_AverageCallLength_Squares )) << stat_delimiter;
1614
1615 for (unsigned int i = 0; i < M_genericMap.size(); i++) {
1616 (*M_outputStream) << M_genericCounters[GENERIC_TYPES * i + GENERIC_PL] << stat_delimiter;
1617 (*M_outputStream) << M_genericCounters[GENERIC_TYPES * i + GENERIC_C] << stat_delimiter;
1618 }
1619
1620 for (int i = 0; i < nRtds(); i++) {
1621 (*M_outputStream)
1622 << sRepartitionInfo(M_ResponseTimeRepartition[i],
1623 M_SizeOfResponseTimeRepartition);
1624 }
1625 (*M_outputStream)
1626 << sRepartitionInfo(M_CallLengthRepartition,
1627 M_SizeOfCallLengthRepartition);
1628 (*M_outputStream) << endl;
1629
1630 // flushing the output file to let the tail -f working !
1631 (*M_outputStream).flush();
1632
1633 } /* end of logData () */
1634
dumpDataRtt()1635 void CStat::dumpDataRtt ()
1636 {
1637 if(M_outputStreamRtt == NULL) {
1638 // if the file is still not opened, we opened it now
1639 M_outputStreamRtt = new ofstream(M_fileNameRtt);
1640 M_headerAlreadyDisplayedRtt = false;
1641
1642 if(M_outputStreamRtt == NULL) {
1643 cerr << "Unable to open rtt file '" << M_fileNameRtt << "' !" << endl;
1644 exit(EXIT_FATAL_ERROR);
1645 }
1646
1647 #ifndef __osf__
1648 if(!M_outputStreamRtt->is_open()) {
1649 cerr << "Unable to open rtt file '" << M_fileNameRtt << "' !" << endl;
1650 exit(EXIT_FATAL_ERROR);
1651 }
1652 #endif
1653 }
1654
1655 if(M_headerAlreadyDisplayedRtt == false) {
1656 (*M_outputStreamRtt) << "Date_ms" << stat_delimiter
1657 << "response_time_ms" << stat_delimiter
1658 << "rtd_no" << endl;
1659 M_headerAlreadyDisplayedRtt = true;
1660 }
1661
1662 for (unsigned int L_i = 0; L_i < M_counterDumpRespTime ; L_i ++) {
1663 (*M_outputStreamRtt) << M_dumpRespTime[L_i].date << stat_delimiter ;
1664 (*M_outputStreamRtt) << M_dumpRespTime[L_i].rtt << stat_delimiter ;
1665 (*M_outputStreamRtt) << M_revRtdMap[M_dumpRespTime[L_i].rtd_no] << endl;
1666 (*M_outputStreamRtt).flush();
1667 M_dumpRespTime[L_i].date = 0.0;
1668 M_dumpRespTime[L_i].rtt = 0.0;
1669 M_dumpRespTime[L_i].rtd_no = 0;
1670 }
1671
1672 // flushing the output file
1673 (*M_outputStreamRtt).flush();
1674
1675 M_counterDumpRespTime = 0;
1676 }
1677
1678
1679 /* Time Gestion */
msToHHMMSS(unsigned long P_ms)1680 char* CStat::msToHHMMSS (unsigned long P_ms)
1681 {
1682 static char L_time [TIME_LENGTH];
1683 unsigned long hh, mm, ss;
1684
1685 P_ms = P_ms / 1000;
1686 hh = P_ms / 3600;
1687 mm = (P_ms - hh * 3600) / 60;
1688 ss = P_ms - (hh * 3600) - (mm * 60);
1689 sprintf (L_time, "%2.2lu:%2.2lu:%2.2lu", hh, mm, ss);
1690 return (L_time);
1691 } /* end of msToHHMMSS */
1692
msToHHMMSSus(unsigned long P_ms)1693 char* CStat::msToHHMMSSus (unsigned long P_ms)
1694 {
1695 static char L_time [TIME_LENGTH];
1696 unsigned long sec, hh, mm, ss, us;
1697
1698 sec = P_ms / 1000;
1699 hh = sec / 3600;
1700 mm = (sec - hh * 3600) / 60;
1701 ss = sec - (hh * 3600) - (mm * 60);
1702 us = 1000*(P_ms - (hh * 3600000) - (mm * 60000) - (ss*1000));
1703 sprintf (L_time, "%2.2lu:%2.2lu:%2.2lu:%06lu", hh, mm, ss, us);
1704 return (L_time);
1705 } /* end of msToHHMMSSus */
1706
formatTime(struct timeval * P_tv,bool with_epoch)1707 char* CStat::formatTime (struct timeval* P_tv, bool with_epoch)
1708 {
1709 static char L_time [TIME_LENGTH];
1710 struct tm * L_currentDate;
1711
1712 // Get the current date and time
1713 L_currentDate = localtime ((const time_t *)&P_tv->tv_sec);
1714
1715 // Format the time
1716 if (L_currentDate == NULL) {
1717 memset (L_time, 0, TIME_LENGTH);
1718 } else {
1719 if (with_epoch) {
1720 sprintf(L_time, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d.%06ld",
1721 L_currentDate->tm_year + 1900,
1722 L_currentDate->tm_mon + 1,
1723 L_currentDate->tm_mday,
1724 L_currentDate->tm_hour,
1725 L_currentDate->tm_min,
1726 L_currentDate->tm_sec,
1727 (long)P_tv->tv_usec);
1728 } else {
1729 sprintf(L_time, "%4.4d-%2.2d-%2.2d\t%2.2d:%2.2d:%2.2d.%06ld\t%10.10ld.%06ld",
1730 L_currentDate->tm_year + 1900,
1731 L_currentDate->tm_mon + 1,
1732 L_currentDate->tm_mday,
1733 L_currentDate->tm_hour,
1734 L_currentDate->tm_min,
1735 L_currentDate->tm_sec,
1736 (long)P_tv->tv_usec,
1737 (long)P_tv->tv_sec, /* time_t is int on some bsds */
1738 (long)P_tv->tv_usec);
1739 }
1740 }
1741 return (L_time);
1742 } /* end of formatTime */
1743
computeDiffTimeInMs(struct timeval * tf,struct timeval * ti)1744 long CStat::computeDiffTimeInMs (struct timeval* tf, struct timeval* ti)
1745 {
1746 long v1, v2;
1747
1748 v1 = tf->tv_sec - ti->tv_sec;
1749 v2 = tf->tv_usec - ti->tv_usec;
1750 if (v2 < 0) v2 += 1000000, v1--;
1751 return (v1*1000 + v2/1000);
1752 }
1753
~CSample()1754 CSample::~CSample()
1755 {
1756 }
1757
1758
1759 /* Implementation of a fixed distribution. */
CFixed(double value)1760 CFixed::CFixed(double value)
1761 {
1762 this->value = value;
1763 }
sample()1764 double CFixed::sample()
1765 {
1766 return value;
1767 }
textDescr(char * s,int len)1768 int CFixed::textDescr(char *s, int len)
1769 {
1770 return snprintf(s, len, "%lf", value);
1771 }
timeDescr(char * s,int len)1772 int CFixed::timeDescr(char *s, int len)
1773 {
1774 return time_string(value, s, len);
1775 }
cdfInv(double)1776 double CFixed::cdfInv(double /*percentile*/)
1777 {
1778 return value;
1779 }
1780
1781 /* Implementation of the default pause time. */
CDefaultPause()1782 CDefaultPause::CDefaultPause()
1783 {
1784 }
sample()1785 double CDefaultPause::sample()
1786 {
1787 return (double)duration;
1788 }
textDescr(char * s,int len)1789 int CDefaultPause::textDescr(char *s, int len)
1790 {
1791 return snprintf(s, len, "%d", duration);
1792 }
timeDescr(char * s,int len)1793 int CDefaultPause::timeDescr(char *s, int len)
1794 {
1795 return time_string(duration, s, len);
1796 }
cdfInv(double)1797 double CDefaultPause::cdfInv(double /*percentile*/)
1798 {
1799 return duration;
1800 }
1801
1802 /* Implementation of a uniform distribution. */
1803 static bool uniform_init = false;
CUniform(double min,double max)1804 CUniform::CUniform(double min, double max)
1805 {
1806 if (!uniform_init) {
1807 uniform_init = true;
1808 srand(time(NULL));
1809 }
1810 this->min = min;
1811 this->max = max;
1812 }
sample()1813 double CUniform::sample()
1814 {
1815 double rval = ((double)rand())/((double)RAND_MAX);
1816 return min + (rval * (max - min));
1817 }
textDescr(char * s,int len)1818 int CUniform::textDescr(char *s, int len)
1819 {
1820 return snprintf(s, len, "%lf/%lf", min, max);
1821 }
timeDescr(char * s,int len)1822 int CUniform::timeDescr(char *s, int len)
1823 {
1824 int used = time_string(min, s, len);
1825 used += snprintf(s + used, len - used, "/");
1826 used += time_string(max, s + used, len - used);
1827 return used;
1828 }
cdfInv(double percentile)1829 double CUniform::cdfInv(double percentile)
1830 {
1831 return min + (max * percentile);
1832 }
1833
1834 #ifdef HAVE_GSL
gsl_init()1835 gsl_rng *gsl_init()
1836 {
1837 static gsl_rng *rng = NULL;
1838
1839 if (rng) {
1840 return rng;
1841 }
1842
1843 gsl_rng_env_setup();
1844 rng = gsl_rng_alloc(gsl_rng_default);
1845 if (!rng) {
1846 ERROR("Could not initialize GSL random number generator.\n");
1847 }
1848
1849 return rng;
1850 }
1851
1852 /* Normal distribution. */
CNormal(double mean,double stdev)1853 CNormal::CNormal(double mean, double stdev)
1854 {
1855 this->mean = mean;
1856 this->stdev = stdev;
1857 rng = gsl_init();
1858 }
1859
sample()1860 double CNormal::sample()
1861 {
1862 double val = gsl_ran_gaussian(rng, stdev);
1863 return val + mean;
1864 }
1865
textDescr(char * s,int len)1866 int CNormal::textDescr(char *s, int len)
1867 {
1868 return snprintf(s, len, "N(%.3lf,%.3lf)", mean, stdev);
1869 }
timeDescr(char * s,int len)1870 int CNormal::timeDescr(char *s, int len)
1871 {
1872 int used = 0;
1873
1874 used += snprintf(s, len, "N(");
1875 used += time_string(mean, s + used, len - used);
1876 used += snprintf(s + used, len - used, ",");
1877 used += time_string(stdev, s + used, len - used);
1878 used += snprintf(s + used, len - used, ")");
1879
1880 return used;
1881 }
cdfInv(double percentile)1882 double CNormal::cdfInv(double percentile)
1883 {
1884 return mean + gsl_cdf_gaussian_Pinv(percentile, stdev);
1885 }
1886
1887 /* Lognormal distribution. */
sample()1888 double CLogNormal::sample()
1889 {
1890 return gsl_ran_lognormal(rng, mean, stdev);
1891 }
textDescr(char * s,int len)1892 int CLogNormal::textDescr(char *s, int len)
1893 {
1894 if (len == 0)
1895 return 0;
1896 s[0] = 'L';
1897 return 1 + this->CNormal::textDescr(s + 1, len - 1);
1898 }
timeDescr(char * s,int len)1899 int CLogNormal::timeDescr(char *s, int len)
1900 {
1901 if (len == 0)
1902 return 0;
1903 s[0] = 'L';
1904 return 1 + this->CNormal::timeDescr(s + 1, len - 1);
1905 }
cdfInv(double percentile)1906 double CLogNormal::cdfInv(double percentile)
1907 {
1908 return gsl_cdf_lognormal_Pinv(percentile, mean, stdev);
1909 }
1910
1911 /* Exponential distribution. */
CExponential(double mean)1912 CExponential::CExponential(double mean)
1913 {
1914 this->mean = mean;
1915 rng = gsl_init();
1916 }
1917
sample()1918 double CExponential::sample()
1919 {
1920 return gsl_ran_exponential(rng, mean);
1921 }
1922
textDescr(char * s,int len)1923 int CExponential::textDescr(char *s, int len)
1924 {
1925 return snprintf(s, len, "Exp(%lf)", mean);
1926 }
timeDescr(char * s,int len)1927 int CExponential::timeDescr(char *s, int len)
1928 {
1929 int used = snprintf(s, len, "Exp(");
1930 used += time_string(mean, s + used, len - used);
1931 used += snprintf(s + used, len - used, ")");
1932 return used;
1933 }
cdfInv(double percentile)1934 double CExponential::cdfInv(double percentile)
1935 {
1936 return gsl_cdf_exponential_Pinv(percentile, mean);
1937 }
1938
1939 /* Weibull distribution. */
CWeibull(double lambda,double k)1940 CWeibull::CWeibull(double lambda, double k)
1941 {
1942 this->lambda = lambda;
1943 this->k = k;
1944 rng = gsl_init();
1945 }
1946
sample()1947 double CWeibull::sample()
1948 {
1949 return gsl_ran_weibull(rng, lambda, k);
1950 }
1951
textDescr(char * s,int len)1952 int CWeibull::textDescr(char *s, int len)
1953 {
1954 return snprintf(s, len, "Wb(%.3lf,%.3lf)", lambda, k);
1955 }
timeDescr(char * s,int len)1956 int CWeibull::timeDescr(char *s, int len)
1957 {
1958 int used = 0;
1959
1960 used += snprintf(s, len, "Wb(");
1961 used += time_string(lambda, s + used, len - used);
1962 used += snprintf(s + used, len - used, ",");
1963 used += time_string(k, s + used, len - used);
1964 used += snprintf(s + used, len - used, ")");
1965
1966 return used;
1967 }
cdfInv(double percentile)1968 double CWeibull::cdfInv(double percentile)
1969 {
1970 return gsl_cdf_weibull_Pinv(percentile, lambda, k);
1971 }
1972
1973 /* Pareto distribution. */
CPareto(double k,double xsubm)1974 CPareto::CPareto(double k, double xsubm)
1975 {
1976 this->k = k;
1977 this->xsubm = xsubm;
1978 rng = gsl_init();
1979 }
1980
sample()1981 double CPareto::sample()
1982 {
1983 return gsl_ran_pareto(rng, k, xsubm);
1984 }
1985
textDescr(char * s,int len)1986 int CPareto::textDescr(char *s, int len)
1987 {
1988 return snprintf(s, len, "P(%.3lf,%.3lf)", k, xsubm);
1989 }
timeDescr(char * s,int len)1990 int CPareto::timeDescr(char *s, int len)
1991 {
1992 int used = 0;
1993
1994 used += snprintf(s, len, "P(");
1995 used += time_string(k, s + used, len - used);
1996 used += snprintf(s + used, len - used, ",");
1997 used += time_string(xsubm, s + used, len - used);
1998 used += snprintf(s + used, len - used, ")");
1999
2000 return used;
2001 }
cdfInv(double percentile)2002 double CPareto::cdfInv(double percentile)
2003 {
2004 return gsl_cdf_pareto_Pinv(percentile, k, xsubm);
2005 }
2006
2007 /* Generalized Pareto distribution. */
CGPareto(double shape,double scale,double location)2008 CGPareto::CGPareto(double shape, double scale, double location)
2009 {
2010 this->shape = shape;
2011 this->scale = scale;
2012 this->location = location;
2013 rng = gsl_init();
2014 }
2015
sample()2016 double CGPareto::sample()
2017 {
2018 return cdfInv(gsl_ran_flat(rng, 0.0, 1.0));
2019 }
2020
textDescr(char * s,int len)2021 int CGPareto::textDescr(char *s, int len)
2022 {
2023 return snprintf(s, len, "P(%.3lf,%.3lf,%.3f)", shape, scale, location);
2024 }
timeDescr(char * s,int len)2025 int CGPareto::timeDescr(char *s, int len)
2026 {
2027 int used = 0;
2028
2029 used += snprintf(s, len, "P(");
2030 used += time_string(shape, s + used, len - used);
2031 used += snprintf(s + used, len - used, ",");
2032 used += time_string(scale, s + used, len - used);
2033 used += snprintf(s + used, len - used, ",");
2034 used += time_string(location, s + used, len - used);
2035 used += snprintf(s + used, len - used, ")");
2036
2037 return used;
2038 }
cdfInv(double percentile)2039 double CGPareto::cdfInv(double percentile)
2040 {
2041 return location + ((scale * (pow(percentile, -shape) - 1))/shape);
2042 }
2043
2044 /* Gamma distribution. */
CGamma(double k,double theta)2045 CGamma::CGamma(double k, double theta)
2046 {
2047 this->k = k;
2048 this->theta = theta;
2049 rng = gsl_init();
2050 }
2051
sample()2052 double CGamma::sample()
2053 {
2054 return gsl_ran_gamma(rng, k, theta);
2055 }
2056
textDescr(char * s,int len)2057 int CGamma::textDescr(char *s, int len)
2058 {
2059 return snprintf(s, len, "G(%.3lf,%.3lf)", k, theta);
2060 }
timeDescr(char * s,int len)2061 int CGamma::timeDescr(char *s, int len)
2062 {
2063 int used = 0;
2064
2065 used += snprintf(s, len, "G(");
2066 used += time_string(k, s + used, len - used);
2067 used += snprintf(s + used, len - used, ",");
2068 used += time_string(theta, s + used, len - used);
2069 used += snprintf(s + used, len - used, ")");
2070
2071 return used;
2072 }
cdfInv(double percentile)2073 double CGamma::cdfInv(double percentile)
2074 {
2075 return gsl_cdf_gamma_Pinv(percentile, k, theta);
2076 }
2077
2078 /* NegBin distribution. */
CNegBin(double p,double n)2079 CNegBin::CNegBin(double p, double n)
2080 {
2081 this->p = p;
2082 this->n = n;
2083 rng = gsl_init();
2084 }
2085
sample()2086 double CNegBin::sample()
2087 {
2088 return gsl_ran_negative_binomial(rng, n, p);
2089 }
2090
textDescr(char * s,int len)2091 int CNegBin::textDescr(char *s, int len)
2092 {
2093 return snprintf(s, len, "NB(%.3lf,%.3lf)", p, n);
2094 }
timeDescr(char * s,int len)2095 int CNegBin::timeDescr(char *s, int len)
2096 {
2097 int used = 0;
2098
2099 used += snprintf(s, len, "NB(");
2100 used += time_string(p, s + used, len - used);
2101 used += snprintf(s + used, len - used, ",");
2102 used += time_string(n, s + used, len - used);
2103 used += snprintf(s + used, len - used, ")");
2104
2105 return used;
2106 }
2107 /* We really don't implement this, but should so that sanity checking will
2108 * work. For now, just return zero. */
cdfInv(double percentile)2109 double CNegBin::cdfInv(double percentile)
2110 {
2111 return 0;
2112 }
2113 #endif
2114