0030775: Foundation Classes - Preserve application-defined top-level exception filter
[occt.git] / src / OSD / OSD_PerfMeter.cxx
1 /*
2  Created on: 2000-08-10
3  Created by: Michael SAZONOV
4  Copyright (c) 2000-2014 OPEN CASCADE SAS
5
6  This file is part of Open CASCADE Technology software library.
7
8  This library is free software; you can redistribute it and/or modify it under
9  the terms of the GNU Lesser General Public License version 2.1 as published
10  by the Free Software Foundation, with special exception defined in the file
11  OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12  distribution for complete text of the license and disclaimer of any warranty.
13
14  Alternatively, this file may be used under the terms of Open CASCADE
15  commercial license or contractual agreement.
16 */ 
17
18 /*======================================================================
19 */ 
20 /*Purpose :       Set of functions to measure the CPU user time
21 */ 
22 /*25/09/2001 : AGV : (const char *) in prototypes;
23 */ 
24 /*09/11/2001 : AGV : Add functions perf_*_imeter for performance
25 */ 
26 /*Add function perf_tick_meter
27 */ 
28 /*14/05/2002 : AGV : Portability UNIX/Windows
29 */ 
30 /*======================================================================*/ 
31 #include <string.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <limits.h>
35 #include <time.h>
36 #include <OSD_Chronometer.hxx>
37 #include <OSD_PerfMeter.h>
38
39
40 /*======================================================================
41         DEFINITIONS
42 ======================================================================*/
43
44 typedef Standard_Real PERF_TIME;
45
46 #define PICK_TIME(_utime) {     \
47   Standard_Real ktime;          \
48   OSD_Chronometer::GetThreadCPU(_utime, ktime);\
49 }
50
51 typedef struct {
52   char*         name;           /* identifier */
53   PERF_TIME     cumul_time;     /* cumulative time */
54   PERF_TIME     start_time;     /* to store start time */
55   int           nb_enter;       /* number of enters */
56 } t_TimeCounter;
57
58 #define MAX_METERS 100
59
60 static t_TimeCounter MeterTable[MAX_METERS];
61 static int nb_meters = 0;
62
63 static int  find_meter (const char * const MeterName);
64 static int  _perf_init_meter (const char * const MeterName,
65                                   const int    doFind);
66
67 /*======================================================================
68 Function :      perf_init_meter
69 Purpose  :      Creates new counter (if it is absent) identified by
70                 MeterName and resets its cumulative value
71 Returns  :      iMeter if OK, -1 if alloc problem
72 ======================================================================*/
73 int perf_init_meter (const char * const MeterName)
74 {
75   return _perf_init_meter (MeterName, ~0);
76 }
77
78 /*======================================================================
79 Function :      perf_tick_meter
80 Purpose  :      Increments the counter of meter MeterName without changing
81                 its state with respect to measurement of time.
82                 creates new meter if there is no such meter
83 Returns  :      iMeter if OK, -1 if no such meter and cannot create a new one
84 ======================================================================*/
85 int perf_tick_meter (const char * const MeterName)
86 {
87   int ic = find_meter (MeterName);
88
89   if (ic == -1) {
90     /* create new meter */
91     ic = _perf_init_meter (MeterName, 0);
92   }
93
94   if (ic >= 0)
95     MeterTable[ic].nb_enter ++;
96
97   return ic;
98 }
99
100 /*======================================================================
101 Function :      perf_tick_imeter
102 Purpose  :      Increments the counter of meter iMeter without changing
103                 its state with respect to measurement of time.
104 Returns  :      iMeter if OK, -1 if no such meter
105 ======================================================================*/
106 int perf_tick_imeter (const int iMeter)
107 {
108   if (iMeter >= 0 && iMeter < nb_meters) {
109     MeterTable[iMeter].nb_enter ++;
110     return iMeter;
111   }
112   return -1;
113 }
114
115 /*======================================================================
116 Function :      perf_start_meter
117 Purpose  :      Forces meter MeterName to begin to count by remembering
118                 the current data of timer;
119                 creates new meter if there is no such meter
120 Returns  :      iMeter if OK, -1 if no such meter and cannot create a new one
121 ======================================================================*/
122 int perf_start_meter (const char * const MeterName)
123 {
124   int ic = find_meter (MeterName);
125
126   if (ic == -1) {
127     /* create new meter */
128     ic = _perf_init_meter (MeterName, 0);
129   }
130
131   if (ic >= 0)
132     PICK_TIME (MeterTable[ic].start_time)
133
134   return ic;
135 }
136
137 /*======================================================================
138 Function :      perf_start_imeter
139 Purpose  :      Forces meter with number iMeter to begin count by remembering
140                 the current data of timer;
141                 the meter must be previously created
142 Returns  :      iMeter if OK, -1 if no such meter
143 ======================================================================*/
144 int perf_start_imeter (const int iMeter)
145 {
146   if (iMeter >= 0 && iMeter < nb_meters) {
147     PICK_TIME (MeterTable[iMeter].start_time)
148     return iMeter;
149   }
150   return -1;
151 }
152
153 /*======================================================================
154 Function :      perf_stop_meter
155 Purpose  :      Forces meter MeterName to stop and cumulate time elapsed
156                 since start
157 Returns  :      iMeter if OK, -1 if no such meter or it is has not been started
158 ======================================================================*/
159 int perf_stop_meter (const char * const MeterName)
160 {
161   const int ic = find_meter (MeterName);
162
163   if (ic >= 0 && MeterTable[ic].start_time) {
164     t_TimeCounter * const ptc = &MeterTable[ic];
165     PERF_TIME utime;
166     PICK_TIME (utime)
167     ptc->cumul_time += utime - ptc->start_time;
168     ptc->start_time = 0;
169     ptc->nb_enter++;
170   }
171
172   return ic;
173 }
174
175 /*======================================================================
176 Function :      perf_stop_imeter
177 Purpose  :      Forces meter with number iMeter to stop and cumulate the time
178                 elapsed since the start
179 Returns  :      iMeter if OK, -1 if no such meter or it is has not been started
180 ======================================================================*/
181 int perf_stop_imeter (const int iMeter)
182 {
183   if (iMeter >= 0 && iMeter < nb_meters) {
184     t_TimeCounter * const ptc = &MeterTable[iMeter];
185     if (ptc->start_time) {
186       PERF_TIME utime;
187       PICK_TIME (utime)
188       ptc->cumul_time += utime - ptc->start_time;
189       ptc->start_time = 0;
190       ptc->nb_enter++;
191       return iMeter;
192     }
193   }
194   return -1;
195 }
196
197 /*======================================================================
198 Function :      perf_get_meter
199 Purpose  :      Tells the time cumulated by meter MeterName and the number
200                 of enters to this meter
201 Output   :      *nb_enter, *seconds if the pointers != NULL
202 Returns  :      iMeter if OK, -1 if no such meter
203 ======================================================================*/
204 int perf_get_meter (const char  * const MeterName,
205                     int         * nb_enter,
206                     double      * seconds)
207 {
208   const int ic = find_meter (MeterName);
209
210   if (ic >= 0) {
211     if (nb_enter) *nb_enter = MeterTable[ic].nb_enter;
212     if (seconds)  *seconds  = MeterTable[ic].cumul_time;
213   }
214   return ic;
215 }
216
217 /*======================================================================
218 Function :      perf_print_all_meters
219 Purpose  :      Prints on stdout the cumulated time and the number of
220                 enters for each meter in MeterTable;
221                 resets all meters if reset is non-null
222 ======================================================================*/
223 void perf_print_all_meters (int reset)
224 {
225   char buffer[MAX_METERS * 256];
226   perf_sprint_all_meters (buffer, MAX_METERS * 256, reset);
227   printf ("%s", buffer);
228 }
229
230 /*======================================================================
231 Function :      perf_print_all_meters
232 Purpose  :      Prints to string buffer the cumulated time and the number of
233                 enters for each meter in MeterTable;
234                 resets all meters if reset is non-null
235 ======================================================================*/
236 void perf_sprint_all_meters (char *buffer, int length, int reset)
237 {
238   char string[256];
239
240   int i;
241   for (i=0; i<nb_meters; i++) {
242     const t_TimeCounter * const ptc = &MeterTable[i];
243     if (ptc && ptc->nb_enter) {
244       int n = sprintf (string, "          Perf meter results               :   enters  seconds  microsec/enter\n");
245       if (n < length)
246       {
247         memcpy (buffer, string, n);
248         buffer += n;
249         length -= n;
250       }
251       break;
252     }
253   }
254   
255   while (i < nb_meters) {
256     t_TimeCounter * const ptc = &MeterTable[i++];
257
258     if (ptc && ptc->nb_enter) {
259       const double secs = ptc->cumul_time;
260
261       int n = 0;
262       if (ptc->start_time)
263         n = sprintf (string, "Warning : meter %42s has not been stopped\n", ptc->name);
264
265       n += sprintf (string + n, "%-42s : %7d %8.2f %10.2f\n",
266                     ptc->name, ptc->nb_enter, secs,
267                     (secs>0. ? 1000000 * secs/ptc->nb_enter : 0.));
268       if (n < length)
269       {
270         memcpy (buffer, string, n);
271         buffer += n;
272         length -= n;
273       }
274
275       if (reset)
276       {
277         ptc->cumul_time = 0;
278         ptc->start_time = 0;
279         ptc->nb_enter   = 0;
280       }
281     }
282   }
283   *buffer = '\0';
284 }
285
286 /*======================================================================
287 Function :      perf_close_meter
288 Purpose  :      Prints out a meter and resets it
289 Returns  :      none
290 ======================================================================*/
291 void perf_close_meter (const char * const MeterName)
292 {
293   perf_close_imeter (find_meter (MeterName));
294 }
295
296 /*======================================================================
297 Function :      perf_close_imeter
298 Purpose  :      Prints out a meter and resets it
299 Returns  :      none
300 ======================================================================*/
301 void perf_close_imeter (const int iMeter)
302 {
303   if (iMeter >= 0 && iMeter < nb_meters && MeterTable[iMeter].nb_enter) {
304     t_TimeCounter * const ptc = &MeterTable[iMeter];
305     if (ptc->start_time)
306       printf ("  ===> Warning : meter %s has not been stopped\n", ptc->name);
307     printf ("  ===> [%s] : %d enters, %9.3f seconds\n",
308             ptc->name, ptc->nb_enter, ptc->cumul_time);
309     ptc->cumul_time = 0;
310     ptc->start_time = 0;
311     ptc->nb_enter   = 0;
312   }
313 }
314
315 /*======================================================================
316 Function :      perf_destroy_all_meters
317 Purpose  :      Deletes all meters and frees memory
318 Returns  :      none
319 ======================================================================*/
320 void perf_destroy_all_meters (void)
321 {
322   int i;
323   for (i=0; i<nb_meters; i++)
324     free (MeterTable[i].name);
325   nb_meters = 0;
326 }
327
328 /* agv - non portable: #pragma fini (perf_print_and_destroy)
329          using atexit instead (see _perf_init_meter below)            */
330
331 void perf_print_and_destroy (void)
332 {
333   perf_print_all_meters (0);
334   perf_destroy_all_meters ();
335 }
336
337 /*======================================================================
338 Function :      _perf_init_meter
339 Purpose  :      Creates new counter (if it is absent) identified by
340                 MeterName and resets its cumulative value
341 Returns  :      index of meter if OK, -1 if alloc problem
342 Remarks  :      For internal use in this module
343 ======================================================================*/
344 static int _perf_init_meter (const char * const MeterName,
345                              const int  doFind)
346 {
347   static int hasbeencalled = 0;
348   int ic = -1;
349   if (doFind)
350     ic = find_meter (MeterName);
351
352   if (ic == -1) {
353     if (nb_meters >= MAX_METERS) return 0;
354     ic = nb_meters;
355
356     MeterTable[ic].name = strdup (MeterName);
357     if (!MeterTable[ic].name)
358       return -1;
359
360     nb_meters++;
361   }
362
363   MeterTable[ic].cumul_time = 0;
364   MeterTable[ic].start_time = 0;
365   MeterTable[ic].nb_enter   = 0;
366   if (hasbeencalled == 0) {
367     atexit (perf_print_and_destroy);
368     hasbeencalled = ~0;
369   }
370   return ic;
371 }
372
373 /*======================================================================
374 Function :      find_meter
375 Purpose  :      Finds the meter MeterName in the MeterTable
376 Returns  :      Index of meter object, -1 if not found
377 Remarks  :      For internal use in this module
378 ======================================================================*/
379 static int find_meter (const char * const MeterName)
380 {
381   int i;
382   for (i=0; i<nb_meters; i++)
383     if (!strcmp (MeterTable[i].name, MeterName)) return i;
384   return -1;
385 }