be57c92e9a9f154d0c12a0f6e1eb42efc47c6c23
[occt.git] / src / OSD / OSD_PerfMeter.c
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_PerfMeter.h>
42
43 /* ------- Definitions for Windows compiler -------- */
44 #ifdef WNT
45 #define STRICT
46 #include <windows.h>
47 typedef __int64 PERF_TIME;
48 #define PICK_TIME(_utime) {     \
49   FILETIME t1, t2, ktime;       \
50   GetThreadTimes (GetCurrentThread(), &t1, &t2, &ktime, (FILETIME *)&(_utime));\
51 }
52 #define GET_SECONDS(_utime) (((double)(_utime))/10000000.)
53
54 /* ------- POSIX Definitions  ---------------------- */
55 #else
56 #include <sys/times.h>
57 typedef clock_t PERF_TIME;
58 #define PICK_TIME(_utime) {     \
59   struct tms tmbuf;             \
60   times (&tmbuf);               \
61   (_utime) = tmbuf.tms_utime;   \
62 }
63 #define GET_SECONDS(_utime) (((double)(_utime))/CLOCKS_PER_SEC)
64 // #define GET_SECONDS(_utime) (((double)(_utime))/CLK_TCK)
65 #endif
66
67 /*======================================================================
68         DEFINITIONS
69 ======================================================================*/
70
71 typedef struct {
72   char*         name;           /* identifier */
73   PERF_TIME     cumul_time;     /* cumulative time */
74   PERF_TIME     start_time;     /* to store start time */
75   int           nb_enter;       /* number of enters */
76 } t_TimeCounter;
77
78 #define MAX_METERS 100
79
80 static t_TimeCounter MeterTable[MAX_METERS];
81 static int nb_meters = 0;
82
83 static int      find_meter       (const char * const MeterName);
84 static int      _perf_init_meter (const char * const MeterName,
85                                   const int    doFind);
86
87 /*======================================================================
88 Function :      perf_init_meter
89 Purpose  :      Creates new counter (if it is absent) identified by
90                 MeterName and resets its cumulative value
91 Returns  :      iMeter if OK, -1 if alloc problem
92 ======================================================================*/
93 int perf_init_meter (const char * const MeterName)
94 {
95   return _perf_init_meter (MeterName, ~0);
96 }
97
98 /*======================================================================
99 Function :      perf_tick_meter
100 Purpose  :      Increments the counter of meter MeterName without changing
101                 its state with respect to measurement of time.
102                 creates new meter if there is no such meter
103 Returns  :      iMeter if OK, -1 if no such meter and cannot create a new one
104 ======================================================================*/
105 int perf_tick_meter (const char * const MeterName)
106 {
107   int ic = find_meter (MeterName);
108
109   if (ic == -1) {
110     /* create new meter */
111     ic = _perf_init_meter (MeterName, 0);
112   }
113
114   if (ic >= 0)
115     MeterTable[ic].nb_enter ++;
116
117   return ic;
118 }
119
120 /*======================================================================
121 Function :      perf_tick_imeter
122 Purpose  :      Increments the counter of meter iMeter without changing
123                 its state with respect to measurement of time.
124 Returns  :      iMeter if OK, -1 if no such meter
125 ======================================================================*/
126 int perf_tick_imeter (const int iMeter)
127 {
128   if (iMeter >= 0 && iMeter < nb_meters) {
129     MeterTable[iMeter].nb_enter ++;
130     return iMeter;
131   }
132   return -1;
133 }
134
135 /*======================================================================
136 Function :      perf_start_meter
137 Purpose  :      Forces meter MeterName to begin to count by remembering
138                 the current data of timer;
139                 creates new meter if there is no such meter
140 Returns  :      iMeter if OK, -1 if no such meter and cannot create a new one
141 ======================================================================*/
142 int perf_start_meter (const char * const MeterName)
143 {
144   int ic = find_meter (MeterName);
145
146   if (ic == -1) {
147     /* create new meter */
148     ic = _perf_init_meter (MeterName, 0);
149   }
150
151   if (ic >= 0)
152     PICK_TIME (MeterTable[ic].start_time)
153
154   return ic;
155 }
156
157 /*======================================================================
158 Function :      perf_start_imeter
159 Purpose  :      Forces meter with number iMeter to begin count by remembering
160                 the current data of timer;
161                 the meter must be previously created
162 Returns  :      iMeter if OK, -1 if no such meter
163 ======================================================================*/
164 int perf_start_imeter (const int iMeter)
165 {
166   if (iMeter >= 0 && iMeter < nb_meters) {
167     PICK_TIME (MeterTable[iMeter].start_time)
168     return iMeter;
169   }
170   return -1;
171 }
172
173 /*======================================================================
174 Function :      perf_stop_meter
175 Purpose  :      Forces meter MeterName to stop and cumulate time elapsed
176                 since start
177 Returns  :      iMeter if OK, -1 if no such meter or it is has not been started
178 ======================================================================*/
179 int perf_stop_meter (const char * const MeterName)
180 {
181   const int ic = find_meter (MeterName);
182
183   if (ic >= 0 && MeterTable[ic].start_time) {
184     t_TimeCounter * const ptc = &MeterTable[ic];
185     PERF_TIME utime;
186     PICK_TIME (utime)
187     ptc->cumul_time += utime - ptc->start_time;
188     ptc->start_time = 0;
189     ptc->nb_enter++;
190   }
191
192   return ic;
193 }
194
195 /*======================================================================
196 Function :      perf_stop_imeter
197 Purpose  :      Forces meter with number iMeter to stop and cumulate the time
198                 elapsed since the start
199 Returns  :      iMeter if OK, -1 if no such meter or it is has not been started
200 ======================================================================*/
201 int perf_stop_imeter (const int iMeter)
202 {
203   if (iMeter >= 0 && iMeter < nb_meters) {
204     t_TimeCounter * const ptc = &MeterTable[iMeter];
205     if (ptc->start_time) {
206       PERF_TIME utime;
207       PICK_TIME (utime)
208       ptc->cumul_time += utime - ptc->start_time;
209       ptc->start_time = 0;
210       ptc->nb_enter++;
211       return iMeter;
212     }
213   }
214   return -1;
215 }
216
217 /*======================================================================
218 Function :      perf_get_meter
219 Purpose  :      Tells the time cumulated by meter MeterName and the number
220                 of enters to this meter
221 Output   :      *nb_enter, *seconds if the pointers != NULL
222 Returns  :      iMeter if OK, -1 if no such meter
223 ======================================================================*/
224 int perf_get_meter (const char  * const MeterName,
225                     int         * nb_enter,
226                     double      * seconds)
227 {
228   const int ic = find_meter (MeterName);
229
230   if (ic >= 0) {
231     if (nb_enter) *nb_enter = MeterTable[ic].nb_enter;
232     if (seconds)  *seconds  = GET_SECONDS(MeterTable[ic].cumul_time);
233   }
234   return ic;
235 }
236
237 /*======================================================================
238 Function :      perf_print_all_meters
239 Purpose  :      Prints on stdout the cumulated time and the number of
240                 enters for each meter in MeterTable;
241                 resets all meters
242 Output   :      none
243 Returns  :      none
244 ======================================================================*/
245 void perf_print_all_meters (void)
246 {
247   int i;
248   for (i=0; i<nb_meters; i++) {
249     const t_TimeCounter * const ptc = &MeterTable[i];
250     if (ptc && ptc->nb_enter) {
251       printf ("          Perf meter results               :"
252               "   enters  seconds  \xe6sec/enter\n");
253       break;
254     }
255   }
256   
257   while (i < nb_meters) {
258     t_TimeCounter * const ptc = &MeterTable[i++];
259
260     if (ptc && ptc->nb_enter) {
261       const double secs = GET_SECONDS(ptc->cumul_time);
262
263       if (ptc->start_time)
264         printf ("Warning : meter %s has not been stopped\n", ptc->name);
265
266       printf ("%-42s : %7d %8.2f %10.2f\n",
267               ptc->name, ptc->nb_enter, secs,
268               (secs>0. ? 1000000 * secs/ptc->nb_enter : 0.));
269
270       ptc->cumul_time = 0;
271       ptc->start_time = 0;
272       ptc->nb_enter   = 0;
273     }
274   }
275 }
276
277 /*======================================================================
278 Function :      perf_close_meter
279 Purpose  :      Prints out a meter and resets it
280 Returns  :      none
281 ======================================================================*/
282 void perf_close_meter (const char * const MeterName)
283 {
284   const int ic = find_meter (MeterName);
285   if (ic >= 0 && MeterTable[ic].nb_enter) {
286     t_TimeCounter * const ptc = &MeterTable[ic];
287     if (ptc->start_time)
288       printf ("  ===> Warning : meter %s has not been stopped\n", ptc->name);
289     printf ("  ===> [%s] : %d enters, %9.3f seconds\n",
290             ptc->name, ptc->nb_enter, GET_SECONDS(ptc->cumul_time));
291     ptc->cumul_time = 0;
292     ptc->start_time = 0;
293     ptc->nb_enter   = 0;
294   }
295 }
296
297 /*======================================================================
298 Function :      perf_close_imeter
299 Purpose  :      Prints out a meter and resets it
300 Returns  :      none
301 ======================================================================*/
302 void perf_close_imeter (const int iMeter)
303 {
304   if (iMeter >= 0 && iMeter < nb_meters && MeterTable[iMeter].nb_enter) {
305     t_TimeCounter * const ptc = &MeterTable[iMeter];
306     if (ptc->start_time)
307       printf ("  ===> Warning : meter %s has not been stopped\n", ptc->name);
308     printf ("  ===> [%s] : %d enters, %9.3f seconds\n",
309             ptc->name, ptc->nb_enter, GET_SECONDS(ptc->cumul_time));
310     ptc->cumul_time = 0;
311     ptc->start_time = 0;
312     ptc->nb_enter   = 0;
313   }
314 }
315
316 /*======================================================================
317 Function :      perf_destroy_all_meters
318 Purpose  :      Deletes all meters and frees memory
319 Returns  :      none
320 ======================================================================*/
321 void perf_destroy_all_meters (void)
322 {
323   int i;
324   for (i=0; i<nb_meters; i++)
325     free (MeterTable[i].name);
326   nb_meters = 0;
327 }
328
329 /* agv - non portable: #pragma fini (perf_print_and_destroy)
330          using atexit instead (see _perf_init_meter below)            */
331
332 void perf_print_and_destroy (void)
333 {
334   perf_print_all_meters ();
335   perf_destroy_all_meters ();
336 }
337
338 /*======================================================================
339 Function :      _perf_init_meter
340 Purpose  :      Creates new counter (if it is absent) identified by
341                 MeterName and resets its cumulative value
342 Returns  :      index of meter if OK, -1 if alloc problem
343 Remarks  :      For internal use in this module
344 ======================================================================*/
345 static int _perf_init_meter (const char * const MeterName,
346                              const int  doFind)
347 {
348   static int hasbeencalled = 0;
349   int ic = -1;
350   if (doFind)
351     ic = find_meter (MeterName);
352
353   if (ic == -1) {
354     if (nb_meters >= MAX_METERS) return 0;
355     ic = nb_meters;
356
357     MeterTable[ic].name = strdup (MeterName);
358     if (!MeterTable[ic].name)
359       return -1;
360
361     nb_meters++;
362   }
363
364   MeterTable[ic].cumul_time = 0;
365   MeterTable[ic].start_time = 0;
366   MeterTable[ic].nb_enter   = 0;
367   if (hasbeencalled == 0) {
368     atexit (perf_print_and_destroy);
369     hasbeencalled = ~0;
370   }
371   return ic;
372 }
373
374 /*======================================================================
375 Function :      find_meter
376 Purpose  :      Finds the meter MeterName in the MeterTable
377 Returns  :      Index of meter object, -1 if not found
378 Remarks  :      For internal use in this module
379 ======================================================================*/
380 static int find_meter (const char * const MeterName)
381 {
382   int i;
383   for (i=0; i<nb_meters; i++)
384     if (!strcmp (MeterTable[i].name, MeterName)) return i;
385   return -1;
386 }