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 ======================================================================*/
perf_init_meter(const char * const MeterName)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 ======================================================================*/
perf_tick_meter(const char * const MeterName)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 ======================================================================*/
perf_tick_imeter(const int iMeter)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 ======================================================================*/
perf_start_meter(const char * const MeterName)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 ======================================================================*/
perf_start_imeter(const int iMeter)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 ======================================================================*/
perf_stop_meter(const char * const MeterName)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 ======================================================================*/
perf_stop_imeter(const int iMeter)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 ======================================================================*/
perf_get_meter(const char * const MeterName,int * nb_enter,double * seconds)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 ======================================================================*/
perf_print_all_meters(int reset)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 ======================================================================*/
perf_sprint_all_meters(char * buffer,int length,int reset)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 ======================================================================*/
perf_close_meter(const char * const MeterName)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 ======================================================================*/
perf_close_imeter(const int iMeter)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 ======================================================================*/
perf_destroy_all_meters(void)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
perf_print_and_destroy(void)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 ======================================================================*/
_perf_init_meter(const char * const MeterName,const int doFind)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 ======================================================================*/
find_meter(const char * const MeterName)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 }
386