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