0023237: OSD_PerfMeter reports wrong (zero) times
[occt.git] / src / OSD / OSD_PerfMeter.cxx
CommitLineData
b311480e 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.
7fd59977 13
b311480e 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/*======================================================================*/
7fd59977 36#include <string.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <limits.h>
40#include <time.h>
c2ae831c 41#include <OSD_Chronometer.hxx>
7fd59977 42#include <OSD_PerfMeter.h>
43
7fd59977 44
45/*======================================================================
46 DEFINITIONS
47======================================================================*/
48
c2ae831c 49typedef Standard_Real PERF_TIME;
50
51#define PICK_TIME(_utime) { \
52 Standard_Real ktime; \
53 OSD_Chronometer::GetThreadCPU(_utime, ktime);\
54}
55
7fd59977 56typedef 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
65static t_TimeCounter MeterTable[MAX_METERS];
66static int nb_meters = 0;
67
c2ae831c 68static int find_meter (const char * const MeterName);
69static int _perf_init_meter (const char * const MeterName,
7fd59977 70 const int doFind);
71
72/*======================================================================
73Function : perf_init_meter
74Purpose : Creates new counter (if it is absent) identified by
75 MeterName and resets its cumulative value
76Returns : iMeter if OK, -1 if alloc problem
77======================================================================*/
78int perf_init_meter (const char * const MeterName)
79{
80 return _perf_init_meter (MeterName, ~0);
81}
82
83/*======================================================================
84Function : perf_tick_meter
85Purpose : 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
88Returns : iMeter if OK, -1 if no such meter and cannot create a new one
89======================================================================*/
90int 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/*======================================================================
106Function : perf_tick_imeter
107Purpose : Increments the counter of meter iMeter without changing
108 its state with respect to measurement of time.
109Returns : iMeter if OK, -1 if no such meter
110======================================================================*/
111int 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/*======================================================================
121Function : perf_start_meter
122Purpose : 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
125Returns : iMeter if OK, -1 if no such meter and cannot create a new one
126======================================================================*/
127int 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/*======================================================================
143Function : perf_start_imeter
144Purpose : Forces meter with number iMeter to begin count by remembering
145 the current data of timer;
146 the meter must be previously created
147Returns : iMeter if OK, -1 if no such meter
148======================================================================*/
149int 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/*======================================================================
159Function : perf_stop_meter
160Purpose : Forces meter MeterName to stop and cumulate time elapsed
161 since start
162Returns : iMeter if OK, -1 if no such meter or it is has not been started
163======================================================================*/
164int 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/*======================================================================
181Function : perf_stop_imeter
182Purpose : Forces meter with number iMeter to stop and cumulate the time
183 elapsed since the start
184Returns : iMeter if OK, -1 if no such meter or it is has not been started
185======================================================================*/
186int 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/*======================================================================
203Function : perf_get_meter
204Purpose : Tells the time cumulated by meter MeterName and the number
205 of enters to this meter
206Output : *nb_enter, *seconds if the pointers != NULL
207Returns : iMeter if OK, -1 if no such meter
208======================================================================*/
209int 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;
c2ae831c 217 if (seconds) *seconds = MeterTable[ic].cumul_time;
7fd59977 218 }
219 return ic;
220}
221
222/*======================================================================
223Function : perf_print_all_meters
224Purpose : Prints on stdout the cumulated time and the number of
225 enters for each meter in MeterTable;
226 resets all meters
227Output : none
228Returns : none
229======================================================================*/
230void 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) {
c2ae831c 246 const double secs = ptc->cumul_time;
7fd59977 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/*======================================================================
263Function : perf_close_meter
264Purpose : Prints out a meter and resets it
265Returns : none
266======================================================================*/
267void 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",
c2ae831c 275 ptc->name, ptc->nb_enter, ptc->cumul_time);
7fd59977 276 ptc->cumul_time = 0;
277 ptc->start_time = 0;
278 ptc->nb_enter = 0;
279 }
280}
281
282/*======================================================================
283Function : perf_close_imeter
284Purpose : Prints out a meter and resets it
285Returns : none
286======================================================================*/
287void 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",
c2ae831c 294 ptc->name, ptc->nb_enter, ptc->cumul_time);
7fd59977 295 ptc->cumul_time = 0;
296 ptc->start_time = 0;
297 ptc->nb_enter = 0;
298 }
299}
300
301/*======================================================================
302Function : perf_destroy_all_meters
303Purpose : Deletes all meters and frees memory
304Returns : none
305======================================================================*/
306void 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
317void perf_print_and_destroy (void)
318{
319 perf_print_all_meters ();
320 perf_destroy_all_meters ();
321}
322
323/*======================================================================
324Function : _perf_init_meter
325Purpose : Creates new counter (if it is absent) identified by
326 MeterName and resets its cumulative value
327Returns : index of meter if OK, -1 if alloc problem
328Remarks : For internal use in this module
329======================================================================*/
330static 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/*======================================================================
360Function : find_meter
361Purpose : Finds the meter MeterName in the MeterTable
362Returns : Index of meter object, -1 if not found
363Remarks : For internal use in this module
364======================================================================*/
365static 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}