b311480e |
1 | /* |
2 | Created on: 2000-08-10 |
3 | Created by: Michael SAZONOV |
973c2be1 |
4 | Copyright (c) 2000-2014 OPEN CASCADE SAS |
b311480e |
5 | |
973c2be1 |
6 | This file is part of Open CASCADE Technology software library. |
b311480e |
7 | |
d5f74e42 |
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 |
973c2be1 |
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. |
b311480e |
13 | |
973c2be1 |
14 | Alternatively, this file may be used under the terms of Open CASCADE |
15 | commercial license or contractual agreement. |
b311480e |
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 | /*======================================================================*/ |
7fd59977 |
31 | #include <string.h> |
32 | #include <stdio.h> |
33 | #include <stdlib.h> |
34 | #include <limits.h> |
35 | #include <time.h> |
c2ae831c |
36 | #include <OSD_Chronometer.hxx> |
7fd59977 |
37 | #include <OSD_PerfMeter.h> |
38 | |
7fd59977 |
39 | |
40 | /*====================================================================== |
41 | DEFINITIONS |
42 | ======================================================================*/ |
43 | |
c2ae831c |
44 | typedef Standard_Real PERF_TIME; |
45 | |
46 | #define PICK_TIME(_utime) { \ |
47 | Standard_Real ktime; \ |
48 | OSD_Chronometer::GetThreadCPU(_utime, ktime);\ |
49 | } |
50 | |
7fd59977 |
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 | |
c2ae831c |
63 | static int find_meter (const char * const MeterName); |
64 | static int _perf_init_meter (const char * const MeterName, |
7fd59977 |
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; |
c2ae831c |
212 | if (seconds) *seconds = MeterTable[ic].cumul_time; |
7fd59977 |
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; |
618617fe |
221 | resets all meters if reset is non-null |
7fd59977 |
222 | ======================================================================*/ |
618617fe |
223 | void perf_print_all_meters (int reset) |
7fd59977 |
224 | { |
618617fe |
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 | |
7fd59977 |
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) { |
936f43da |
244 | int n = sprintf (string, " Perf meter results : enters seconds microsec/enter\n"); |
618617fe |
245 | if (n < length) |
246 | { |
247 | memcpy (buffer, string, n); |
248 | buffer += n; |
249 | length -= n; |
250 | } |
7fd59977 |
251 | break; |
252 | } |
253 | } |
254 | |
255 | while (i < nb_meters) { |
256 | t_TimeCounter * const ptc = &MeterTable[i++]; |
257 | |
258 | if (ptc && ptc->nb_enter) { |
c2ae831c |
259 | const double secs = ptc->cumul_time; |
7fd59977 |
260 | |
618617fe |
261 | int n = 0; |
7fd59977 |
262 | if (ptc->start_time) |
618617fe |
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 | } |
7fd59977 |
281 | } |
282 | } |
618617fe |
283 | *buffer = '\0'; |
7fd59977 |
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 | { |
618617fe |
293 | perf_close_imeter (find_meter (MeterName)); |
7fd59977 |
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", |
c2ae831c |
308 | ptc->name, ptc->nb_enter, ptc->cumul_time); |
7fd59977 |
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 | { |
618617fe |
333 | perf_print_all_meters (0); |
7fd59977 |
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 | } |