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", &current_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", &current_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 (&currentTime);
1161     // computing the real call rate
1162     globalElapsedTime   = computeDiffTimeInMs (&currentTime, &M_startTime);
1163     localElapsedTime    = computeDiffTimeInMs (&currentTime, &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(&currentTime));
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 (&currentTime);
1278     // computing the real call rate
1279     globalElapsedTime   = computeDiffTimeInMs (&currentTime, &M_startTime);
1280     localElapsedTime    = computeDiffTimeInMs (&currentTime, &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(&currentTime));
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 (&currentTime);
1393     globalElapsedTime   = computeDiffTimeInMs (&currentTime, &M_startTime);
1394     localElapsedTime    = computeDiffTimeInMs (&currentTime, &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(&currentTime)               << 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