1 /*
2 % Copyright (C) 2003-2020 GraphicsMagick Group
3 % Copyright (C) 2002 ImageMagick Studio
4 %
5 % This program is covered by multiple licenses, which are described in
6 % Copyright.txt. You should have received a copy of Copyright.txt with this
7 % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
8 %
9 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10 %                                                                             %
11 %                                                                             %
12 %                                                                             %
13 %                    TTTTT  IIIII  M   M  EEEEE  RRRR                         %
14 %                      T      I    MM MM  E      R   R                        %
15 %                      T      I    M M M  EEE    RRRR                         %
16 %                      T      I    M   M  E      R R                          %
17 %                      T    IIIII  M   M  EEEEE  R  R                         %
18 %                                                                             %
19 %                                                                             %
20 %                      GraphicsMagick Timing Methods                          %
21 %                                                                             %
22 %                                                                             %
23 %                             Software Design                                 %
24 %                               John Cristy                                   %
25 %                              January 1993                                   %
26 %                                                                             %
27 %                                                                             %
28 %                                                                             %
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30 %
31 %  Contributed by Bill Radcliffe and Bob Friesenhahn.
32 %
33 */
34 
35 /*
36   Include declarations.
37 */
38 #include "magick/studio.h"
39 
40 /*
41   Define declarations.
42 */
43 #if !defined(CLK_TCK)
44 #  define CLK_TCK  sysconf(_SC_CLK_TCK)
45 #endif
46 #if defined(HAVE_CLOCK_GETTIME)
47 #  define NANOSECONDS_PER_SECOND 1000000000.0
48 #  if defined(CLOCK_HIGHRES) /* Solaris */
49 #    define CLOCK_ID CLOCK_HIGHRES
50 #  elif defined(CLOCK_MONOTONIC_RAW) /* Linux */
51 #    define CLOCK_ID CLOCK_MONOTONIC_RAW
52 #  elif defined(CLOCK_MONOTONIC_PRECISE) /* FreeBSD */
53 #    define CLOCK_ID CLOCK_MONOTONIC_PRECISE
54 #  elif defined(CLOCK_MONOTONIC) /* Linux & FreeBSD */
55 #    define CLOCK_ID CLOCK_MONOTONIC
56 #  else
57 #    define CLOCK_ID CLOCK_REALTIME /* Fallback */
58 #  endif
59 #endif
60 
61 /*
62   Forward declarations.
63 */
64 static double
65   UserTime(void);
66 
67 /*
68 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69 %                                                                             %
70 %                                                                             %
71 %                                                                             %
72 %   C o n t i n u e T i m e r                                                 %
73 %                                                                             %
74 %                                                                             %
75 %                                                                             %
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %
78 %  Method ContinueTimer resumes a stopped stopwatch. The stopwatch continues
79 %  counting from the last StartTimer() onwards.
80 %
81 %  The format of the ContinueTimer method is:
82 %
83 %      unsigned int ContinueTimer(TimerInfo *time_info)
84 %
85 %  A description of each parameter follows.
86 %
87 %    o  time_info: Time statistics structure.
88 %
89 */
ContinueTimer(TimerInfo * time_info)90 MagickExport unsigned int ContinueTimer(TimerInfo *time_info)
91 {
92   assert(time_info != (TimerInfo *) NULL);
93   assert(time_info->signature == MagickSignature);
94   if (time_info->state == UndefinedTimerState)
95     return(False);
96   if (time_info->state == StoppedTimerState)
97     {
98       time_info->user.total-=time_info->user.stop-time_info->user.start;
99       time_info->elapsed.total-=
100         time_info->elapsed.stop-time_info->elapsed.start;
101     }
102   time_info->state=RunningTimerState;
103   return(True);
104 }
105 
106 /*
107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108 %                                                                             %
109 %                                                                             %
110 %                                                                             %
111 +   E l a p s e d T i m e                                                     %
112 %                                                                             %
113 %                                                                             %
114 %                                                                             %
115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 %
117 %  Method ElapsedTime returns the elapsed time (in seconds) since the last
118 %  call to StartTimer().
119 %
120 %  The format of the ElapsedTime method is:
121 %
122 %      double ElapsedTime()
123 %
124 */
ElapsedTime(void)125 static double ElapsedTime(void)
126 {
127 #if defined(HAVE_CLOCK_GETTIME)
128   struct timespec timer;
129   (void) clock_gettime(CLOCK_ID, &timer);
130 
131   return((double) timer.tv_sec + timer.tv_nsec/NANOSECONDS_PER_SECOND);
132 #elif defined(HAVE_TIMES)
133   struct tms
134     timer;
135 
136   return((double) times(&timer)/CLK_TCK);
137 #else
138 #if defined(MSWINDOWS)
139   return(NTElapsedTime());
140 #else
141   return((double) clock()/CLK_TCK);
142 #endif
143 #endif
144 }
145 
146 /*
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 %                                                                             %
149 %                                                                             %
150 %                                                                             %
151 %   G e t E l a p s e d T i m e                                               %
152 %                                                                             %
153 %                                                                             %
154 %                                                                             %
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156 %
157 %  Method GetElapsedTime returns the elapsed time (in seconds) passed between
158 %  the start and stop events. If the stopwatch is still running, it is stopped
159 %  first.
160 %
161 %  The format of the GetElapsedTime method is:
162 %
163 %      double GetElapsedTime(TimerInfo *time_info)
164 %
165 %  A description of each parameter follows.
166 %
167 %    o  time_info: Timer statistics structure.
168 %
169 */
GetElapsedTime(TimerInfo * time_info)170 MagickExport double GetElapsedTime(TimerInfo *time_info)
171 {
172   assert(time_info != (TimerInfo *) NULL);
173   assert(time_info->signature == MagickSignature);
174   if (time_info->state == UndefinedTimerState)
175     return(0.0);
176   if (time_info->state == RunningTimerState)
177     StopTimer(time_info);
178   return(time_info->elapsed.total);
179 }
180 
181 /*
182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
183 %                                                                             %
184 %                                                                             %
185 %                                                                             %
186 %   G e t T i m e r I n f o                                                   %
187 %                                                                             %
188 %                                                                             %
189 %                                                                             %
190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191 %
192 %  Method GetTimerInfo initializes the TimerInfo structure.
193 %
194 %  The format of the GetTimerInfo method is:
195 %
196 %      void GetTimerInfo(TimerInfo *time_info)
197 %
198 %  A description of each parameter follows.
199 %
200 %    o  time_info: Timer statistics structure.
201 %
202 */
GetTimerInfo(TimerInfo * time_info)203 MagickExport void GetTimerInfo(TimerInfo *time_info)
204 {
205   /*
206     Create a stopwatch and start it.
207   */
208   assert(time_info != (TimerInfo *) NULL);
209   (void) memset(time_info,0,sizeof(TimerInfo));
210   time_info->state=UndefinedTimerState;
211   time_info->signature=MagickSignature;
212   StartTimer(time_info,True);
213 }
214 
215 /*
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 %                                                                             %
218 %                                                                             %
219 %                                                                             %
220 %   G e t T i m e r R e s o l u t i o n                                       %
221 %                                                                             %
222 %                                                                             %
223 %                                                                             %
224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225 %
226 %  Obtain the measurement resolution of the timer.
227 %
228 %  The format of the GetTimerResolution method is:
229 %
230 %      void GetTimerInfo(TimerInfo *time_info)
231 %
232 %  A description of each parameter follows.
233 %
234 %    o  time_info: Timer statistics structure.
235 %
236 */
GetTimerResolution(void)237 MagickExport double GetTimerResolution(void)
238 {
239 #if defined(HAVE_CLOCK_GETRES)
240   struct timespec timer;
241   (void) clock_getres(CLOCK_ID, &timer);
242 
243   return((double) timer.tv_sec + (double) timer.tv_nsec/NANOSECONDS_PER_SECOND);
244 #elif defined(MSWINDOWS)
245   return (0.02);
246 #else
247   return (1.0/CLK_TCK);
248 #endif
249 }
250 
251 /*
252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253 %                                                                             %
254 %                                                                             %
255 %                                                                             %
256 %   G e t U s e r T i m e                                                     %
257 %                                                                             %
258 %                                                                             %
259 %                                                                             %
260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261 %
262 %  Method GetUserTime returns the User time (user and system) by the operating
263 %  system (in seconds) between the start and stop events. If the stopwatch is
264 %  still running, it is stopped first.
265 %
266 %  The format of the GetUserTime method is:
267 %
268 %      double GetUserTime(TimerInfo *time_info)
269 %
270 %  A description of each parameter follows.
271 %
272 %    o  time_info: Timer statistics structure.
273 %
274 */
GetUserTime(TimerInfo * time_info)275 MagickExport double GetUserTime(TimerInfo *time_info)
276 {
277   assert(time_info != (TimerInfo *) NULL);
278   assert(time_info->signature == MagickSignature);
279   if (time_info->state == UndefinedTimerState)
280     return(0.0);
281   if (time_info->state == RunningTimerState)
282     StopTimer(time_info);
283   return(time_info->user.total);
284 }
285 
286 /*
287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 %                                                                             %
289 %                                                                             %
290 %                                                                             %
291 %   R e s e t T i m e r                                                       %
292 %                                                                             %
293 %                                                                             %
294 %                                                                             %
295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 %
297 %  Method ResetTimer resets the stopwatch.
298 %
299 %  The format of the ResetTimer method is:
300 %
301 %      void ResetTimer(TimerInfo *time_info)
302 %
303 %  A description of each parameter follows.
304 %
305 %    o  time_info: Timer statistics structure.
306 %
307 */
ResetTimer(TimerInfo * time_info)308 MagickExport void ResetTimer(TimerInfo *time_info)
309 {
310   assert(time_info != (TimerInfo *) NULL);
311   assert(time_info->signature == MagickSignature);
312   StopTimer(time_info);
313   time_info->elapsed.stop=0.0;
314   time_info->user.stop=0.0;
315 }
316 
317 /*
318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 %                                                                             %
320 %                                                                             %
321 %                                                                             %
322 +   S t a r t T i m e r                                                       %
323 %                                                                             %
324 %                                                                             %
325 %                                                                             %
326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327 %
328 %  Method StartTimer starts the stopwatch.
329 %
330 %  The format of the StartTimer method is:
331 %
332 %      void StartTimer(TimerInfo *time_info,const unsigned int reset)
333 %
334 %  A description of each parameter follows.
335 %
336 %    o  time_info: Timer statistics structure.
337 %
338 %    o  reset: If reset is True, then the stopwatch is reset prior to starting.
339 %       If reset is False, then timing is continued without resetting the
340 %       stopwatch.
341 %
342 */
StartTimer(TimerInfo * time_info,const unsigned int reset)343 MagickExport void StartTimer(TimerInfo *time_info,const unsigned int reset)
344 {
345   assert(time_info != (TimerInfo *) NULL);
346   assert(time_info->signature == MagickSignature);
347   if (reset)
348     {
349       /*
350         Reset the stopwatch before starting it.
351       */
352       time_info->user.total=0.0;
353       time_info->elapsed.total=0.0;
354     }
355   if (time_info->state != RunningTimerState)
356     {
357       time_info->elapsed.start=ElapsedTime();
358       time_info->user.start=UserTime();
359     }
360   time_info->state=RunningTimerState;
361 }
362 
363 /*
364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 %                                                                             %
366 %                                                                             %
367 %                                                                             %
368 +   S t o p T i m e r                                                         %
369 %                                                                             %
370 %                                                                             %
371 %                                                                             %
372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373 %
374 %  Method StopTimer stops the stopwatch.
375 %
376 %  The format of the StopTimer method is:
377 %
378 %      void StopTimer(TimerInfo *time_info)
379 %
380 %  A description of each parameter follows.
381 %
382 %    o  time_info: Timer statistics structure.
383 %
384 */
StopTimer(TimerInfo * time_info)385 MagickExport void StopTimer(TimerInfo *time_info)
386 {
387   assert(time_info != (TimerInfo *) NULL);
388   assert(time_info->signature == MagickSignature);
389   time_info->elapsed.stop=ElapsedTime();
390   time_info->user.stop=UserTime();
391   if (time_info->state == RunningTimerState)
392     {
393       time_info->user.total+=
394         time_info->user.stop-time_info->user.start+MagickEpsilon;
395       time_info->elapsed.total+=
396         time_info->elapsed.stop-time_info->elapsed.start+MagickEpsilon;
397     }
398   time_info->state=StoppedTimerState;
399 }
400 
401 /*
402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403 %                                                                             %
404 %                                                                             %
405 %                                                                             %
406 +   U s e r T i m e                                                           %
407 %                                                                             %
408 %                                                                             %
409 %                                                                             %
410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 %
412 %  Method UserTime returns the total time the process has been scheduled (in
413 %  seconds) since the last call to StartTimer().
414 %
415 %  The format of the UserTime method is:
416 %
417 %      double UserTime()
418 %
419 */
UserTime(void)420 static double UserTime(void)
421 {
422 #if defined(HAVE_TIMES)
423   struct tms
424     timer;
425 
426   (void) times(&timer);
427   return((double) (timer.tms_utime+timer.tms_stime)/CLK_TCK);
428 #else
429 #if defined(MSWINDOWS)
430   return(NTUserTime());
431 #else
432   return((double) clock()/CLK_TCK);
433 #endif
434 #endif
435 }
436