1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                    TTTTT  IIIII  M   M  EEEEE  RRRR                         %
7 %                      T      I    MM MM  E      R   R                        %
8 %                      T      I    M M M  EEE    RRRR                         %
9 %                      T      I    M   M  E      R R                          %
10 %                      T    IIIII  M   M  EEEEE  R  R                         %
11 %                                                                             %
12 %                                                                             %
13 %                         MagickCore Timing Methods                           %
14 %                                                                             %
15 %                             Software Design                                 %
16 %                                  Cristy                                     %
17 %                              January 1993                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    https://imagemagick.org/script/license.php                               %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %  Contributed by Bill Radcliffe and Bob Friesenhahn.
37 %
38 */
39 
40 /*
41   Include declarations.
42 */
43 #include "magick/studio.h"
44 #include "magick/exception.h"
45 #include "magick/exception-private.h"
46 #include "magick/locale_.h"
47 #include "magick/log.h"
48 #include "magick/memory_.h"
49 #include "magick/nt-base-private.h"
50 #include "magick/string-private.h"
51 #include "magick/timer.h"
52 #include "magick/timer-private.h"
53 
54 /*
55   Define declarations.
56 */
57 #if !defined(CLOCKS_PER_SEC)
58 #define CLOCKS_PER_SEC  100
59 #endif
60 
61 /*
62   Forward declarations.
63 */
64 static double
65   UserTime(void);
66 
67 static void
68   StopTimer(TimerInfo *);
69 
70 /*
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 %                                                                             %
73 %                                                                             %
74 %                                                                             %
75 %   A c q u i r e T i m e r I n f o                                           %
76 %                                                                             %
77 %                                                                             %
78 %                                                                             %
79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 %
81 %  AcquireTimerInfo() initializes the TimerInfo structure.  It effectively
82 %  creates a stopwatch and starts it.
83 %
84 %  The format of the AcquireTimerInfo method is:
85 %
86 %      TimerInfo *AcquireTimerInfo(void)
87 %
88 */
AcquireTimerInfo(void)89 MagickExport TimerInfo *AcquireTimerInfo(void)
90 {
91   TimerInfo
92     *timer_info;
93 
94   timer_info=(TimerInfo *) AcquireMagickMemory(sizeof(*timer_info));
95   if (timer_info == (TimerInfo *) NULL)
96     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
97   (void) memset(timer_info,0,sizeof(*timer_info));
98   timer_info->signature=MagickCoreSignature;
99   GetTimerInfo(timer_info);
100   return(timer_info);
101 }
102 
103 /*
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 %                                                                             %
106 %                                                                             %
107 %                                                                             %
108 %   C o n t i n u e T i m e r                                                 %
109 %                                                                             %
110 %                                                                             %
111 %                                                                             %
112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113 %
114 %  ContinueTimer() resumes a stopped stopwatch. The stopwatch continues
115 %  counting from the last StartTimer() onwards.
116 %
117 %  The format of the ContinueTimer method is:
118 %
119 %      MagickBooleanType ContinueTimer(TimerInfo *time_info)
120 %
121 %  A description of each parameter follows.
122 %
123 %    o  time_info: Time statistics structure.
124 %
125 */
ContinueTimer(TimerInfo * time_info)126 MagickExport MagickBooleanType ContinueTimer(TimerInfo *time_info)
127 {
128   assert(time_info != (TimerInfo *) NULL);
129   assert(time_info->signature == MagickCoreSignature);
130   if (time_info->state == UndefinedTimerState)
131     return(MagickFalse);
132   if (time_info->state == StoppedTimerState)
133     {
134       time_info->user.total-=time_info->user.stop-time_info->user.start;
135       time_info->elapsed.total-=time_info->elapsed.stop-
136         time_info->elapsed.start;
137     }
138   time_info->state=RunningTimerState;
139   return(MagickTrue);
140 }
141 
142 /*
143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144 %                                                                             %
145 %                                                                             %
146 %                                                                             %
147 %   D e s t r o y T i m e r I n f o                                           %
148 %                                                                             %
149 %                                                                             %
150 %                                                                             %
151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152 %
153 %  DestroyTimerInfo() zeros memory associated with the TimerInfo structure.
154 %
155 %  The format of the DestroyTimerInfo method is:
156 %
157 %      TimerInfo *DestroyTimerInfo(TimerInfo *timer_info)
158 %
159 %  A description of each parameter follows:
160 %
161 %    o timer_info: The cipher context.
162 %
163 */
DestroyTimerInfo(TimerInfo * timer_info)164 MagickExport TimerInfo *DestroyTimerInfo(TimerInfo *timer_info)
165 {
166   assert(timer_info != (TimerInfo *) NULL);
167   assert(timer_info->signature == MagickCoreSignature);
168   timer_info->signature=(~MagickCoreSignature);
169   timer_info=(TimerInfo *) RelinquishMagickMemory(timer_info);
170   return(timer_info);
171 }
172 
173 /*
174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
175 %                                                                             %
176 %                                                                             %
177 %                                                                             %
178 +   E l a p s e d T i m e                                                     %
179 %                                                                             %
180 %                                                                             %
181 %                                                                             %
182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
183 %
184 %  ElapsedTime() returns the elapsed time (in seconds) since the last call to
185 %  StartTimer().
186 %
187 %  The format of the ElapsedTime method is:
188 %
189 %      double ElapsedTime()
190 %
191 */
ElapsedTime(void)192 static double ElapsedTime(void)
193 {
194 #if defined(MAGICKCORE_HAVE_CLOCK_GETTIME)
195 #define NANOSECONDS_PER_SECOND  1000000000.0
196 #if defined(CLOCK_HIGHRES)
197 #  define CLOCK_ID CLOCK_HIGHRES
198 #elif defined(CLOCK_MONOTONIC_RAW)
199 #  define CLOCK_ID CLOCK_MONOTONIC_RAW
200 #elif defined(CLOCK_MONOTONIC_PRECISE)
201 #  define CLOCK_ID CLOCK_MONOTONIC_PRECISE
202 #elif defined(CLOCK_MONOTONIC)
203 #  define CLOCK_ID CLOCK_MONOTONIC
204 #else
205 #  define CLOCK_ID CLOCK_REALTIME
206 #endif
207 
208   struct timespec
209     timer;
210 
211   (void) clock_gettime(CLOCK_ID,&timer);
212   return((double) timer.tv_sec+timer.tv_nsec/NANOSECONDS_PER_SECOND);
213 #elif defined(MAGICKCORE_HAVE_TIMES) && defined(MAGICKCORE_HAVE_SYSCONF)
214   struct tms
215     timer;
216 
217   return((double) times(&timer)/sysconf(_SC_CLK_TCK));
218 #else
219 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
220   return(NTElapsedTime());
221 #else
222   return((double) clock()/CLOCKS_PER_SEC);
223 #endif
224 #endif
225 }
226 
227 /*
228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229 %                                                                             %
230 %                                                                             %
231 %                                                                             %
232 %  F o r m a t M a g i c k T i m e                                            %
233 %                                                                             %
234 %                                                                             %
235 %                                                                             %
236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 %
238 %  FormatMagickTime() returns the specified time in the Internet date/time
239 %  format and the length of the timestamp.
240 %
241 %  The format of the FormatMagickTime method is:
242 %
243 %      ssize_t FormatMagickTime(const time_t time,const size_t length,
244 %        char *timestamp)
245 %
246 %  A description of each parameter follows.
247 %
248 %   o time:  the time since the Epoch (00:00:00 UTC, January 1, 1970),
249 %     measured in seconds.
250 %
251 %   o length: the maximum length of the string.
252 %
253 %   o timestamp:  Return the Internet date/time here.
254 %
255 */
FormatMagickTime(const time_t time,const size_t length,char * timestamp)256 MagickExport ssize_t FormatMagickTime(const time_t time,const size_t length,
257   char *timestamp)
258 {
259   ssize_t
260     count;
261 
262   struct tm
263     utc_time;
264 
265   assert(timestamp != (char *) NULL);
266   GetMagickUTCtime(&time,&utc_time);
267   count=FormatLocaleString(timestamp,length,
268     "%04d-%02d-%02dT%02d:%02d:%02d%+03d:00",utc_time.tm_year+1900,
269     utc_time.tm_mon+1,utc_time.tm_mday,utc_time.tm_hour,utc_time.tm_min,
270     utc_time.tm_sec,0);
271   return(count);
272 }
273 
274 /*
275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276 %                                                                             %
277 %                                                                             %
278 %                                                                             %
279 %   G e t E l a p s e d T i m e                                               %
280 %                                                                             %
281 %                                                                             %
282 %                                                                             %
283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284 %
285 %  GetElapsedTime() returns the elapsed time (in seconds) passed between the
286 %  start and stop events. If the stopwatch is still running, it is stopped
287 %  first.
288 %
289 %  The format of the GetElapsedTime method is:
290 %
291 %      double GetElapsedTime(TimerInfo *time_info)
292 %
293 %  A description of each parameter follows.
294 %
295 %    o  time_info: Timer statistics structure.
296 %
297 */
GetElapsedTime(TimerInfo * time_info)298 MagickExport double GetElapsedTime(TimerInfo *time_info)
299 {
300   assert(time_info != (TimerInfo *) NULL);
301   assert(time_info->signature == MagickCoreSignature);
302   if (time_info->state == UndefinedTimerState)
303     return(0.0);
304   if (time_info->state == RunningTimerState)
305     StopTimer(time_info);
306   return(time_info->elapsed.total);
307 }
308 
309 /*
310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
311 %                                                                             %
312 %                                                                             %
313 %                                                                             %
314 +   G e t M a g i c k T i m e                                                 %
315 %                                                                             %
316 %                                                                             %
317 %                                                                             %
318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 %
320 %  GetMagickTime() returns the time as the number of seconds since the Epoch.
321 %
322 %  The format of the GetElapsedTime method is:
323 %
324 %      time_t GetElapsedTime(void)
325 %
326 */
GetMagickTime(void)327 MagickExport time_t GetMagickTime(void)
328 {
329   static const char
330     *source_date_epoch = (const char *) NULL;
331 
332   static MagickBooleanType
333     epoch_initalized = MagickFalse;
334 
335   if (epoch_initalized == MagickFalse)
336     {
337       source_date_epoch=getenv("SOURCE_DATE_EPOCH");
338       epoch_initalized=MagickTrue;
339     }
340   if (source_date_epoch != (const char *) NULL)
341     {
342       time_t
343         epoch;
344 
345       epoch=(time_t) StringToDouble(source_date_epoch,(char **) NULL);
346       if ((epoch > 0) && (epoch <= time((time_t *) NULL)))
347         return(epoch);
348     }
349   return(time((time_t *) NULL));
350 }
351 
352 /*
353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354 %                                                                             %
355 %                                                                             %
356 %                                                                             %
357 +   G e t T i m e r I n f o                                                   %
358 %                                                                             %
359 %                                                                             %
360 %                                                                             %
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 %
363 %  GetTimerInfo() initializes the TimerInfo structure.
364 %
365 %  The format of the GetTimerInfo method is:
366 %
367 %      void GetTimerInfo(TimerInfo *time_info)
368 %
369 %  A description of each parameter follows.
370 %
371 %    o  time_info: Timer statistics structure.
372 %
373 */
GetTimerInfo(TimerInfo * time_info)374 MagickExport void GetTimerInfo(TimerInfo *time_info)
375 {
376   /*
377     Create a stopwatch and start it.
378   */
379   assert(time_info != (TimerInfo *) NULL);
380   (void) memset(time_info,0,sizeof(*time_info));
381   time_info->state=UndefinedTimerState;
382   time_info->signature=MagickCoreSignature;
383   StartTimer(time_info,MagickTrue);
384 }
385 
386 /*
387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388 %                                                                             %
389 %                                                                             %
390 %                                                                             %
391 %   G e t U s e r T i m e                                                     %
392 %                                                                             %
393 %                                                                             %
394 %                                                                             %
395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396 %
397 %  GetUserTime() returns the User time (user and system) by the operating
398 %  system (in seconds) between the start and stop events. If the stopwatch is
399 %  still running, it is stopped first.
400 %
401 %  The format of the GetUserTime method is:
402 %
403 %      double GetUserTime(TimerInfo *time_info)
404 %
405 %  A description of each parameter follows.
406 %
407 %    o  time_info: Timer statistics structure.
408 %
409 */
GetUserTime(TimerInfo * time_info)410 MagickExport double GetUserTime(TimerInfo *time_info)
411 {
412   assert(time_info != (TimerInfo *) NULL);
413   assert(time_info->signature == MagickCoreSignature);
414   if (time_info->state == UndefinedTimerState)
415     return(0.0);
416   if (time_info->state == RunningTimerState)
417     StopTimer(time_info);
418   return(time_info->user.total);
419 }
420 
421 /*
422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
423 %                                                                             %
424 %                                                                             %
425 %                                                                             %
426 %   R e s e t T i m e r                                                       %
427 %                                                                             %
428 %                                                                             %
429 %                                                                             %
430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431 %
432 %  ResetTimer() resets the stopwatch.
433 %
434 %  The format of the ResetTimer method is:
435 %
436 %      void ResetTimer(TimerInfo *time_info)
437 %
438 %  A description of each parameter follows.
439 %
440 %    o  time_info: Timer statistics structure.
441 %
442 */
ResetTimer(TimerInfo * time_info)443 MagickExport void ResetTimer(TimerInfo *time_info)
444 {
445   assert(time_info != (TimerInfo *) NULL);
446   assert(time_info->signature == MagickCoreSignature);
447   StopTimer(time_info);
448   time_info->elapsed.stop=0.0;
449   time_info->user.stop=0.0;
450 }
451 
452 /*
453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454 %                                                                             %
455 %                                                                             %
456 %                                                                             %
457 +   S t a r t T i m e r                                                       %
458 %                                                                             %
459 %                                                                             %
460 %                                                                             %
461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
462 %
463 %  StartTimer() starts the stopwatch.
464 %
465 %  The format of the StartTimer method is:
466 %
467 %      void StartTimer(TimerInfo *time_info,const MagickBooleanType reset)
468 %
469 %  A description of each parameter follows.
470 %
471 %    o  time_info: Timer statistics structure.
472 %
473 %    o  reset: If reset is MagickTrue, then the stopwatch is reset prior to
474 %       starting.  If reset is MagickFalse, then timing is continued without
475 %       resetting the stopwatch.
476 %
477 */
StartTimer(TimerInfo * time_info,const MagickBooleanType reset)478 MagickExport void StartTimer(TimerInfo *time_info,const MagickBooleanType reset)
479 {
480   assert(time_info != (TimerInfo *) NULL);
481   assert(time_info->signature == MagickCoreSignature);
482   if (reset != MagickFalse)
483     {
484       /*
485         Reset the stopwatch before starting it.
486       */
487       time_info->user.total=0.0;
488       time_info->elapsed.total=0.0;
489     }
490   if (time_info->state != RunningTimerState)
491     {
492       time_info->elapsed.start=ElapsedTime();
493       time_info->user.start=UserTime();
494     }
495   time_info->state=RunningTimerState;
496 }
497 
498 /*
499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500 %                                                                             %
501 %                                                                             %
502 %                                                                             %
503 +   S t o p T i m e r                                                         %
504 %                                                                             %
505 %                                                                             %
506 %                                                                             %
507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508 %
509 %  StopTimer() stops the stopwatch.
510 %
511 %  The format of the StopTimer method is:
512 %
513 %      void StopTimer(TimerInfo *time_info)
514 %
515 %  A description of each parameter follows.
516 %
517 %    o  time_info: Timer statistics structure.
518 %
519 */
StopTimer(TimerInfo * time_info)520 static void StopTimer(TimerInfo *time_info)
521 {
522   assert(time_info != (TimerInfo *) NULL);
523   assert(time_info->signature == MagickCoreSignature);
524   time_info->elapsed.stop=ElapsedTime();
525   time_info->user.stop=UserTime();
526   if (time_info->state == RunningTimerState)
527     {
528       time_info->user.total+=time_info->user.stop-
529         time_info->user.start+MagickEpsilon;
530       time_info->elapsed.total+=time_info->elapsed.stop-
531         time_info->elapsed.start+MagickEpsilon;
532     }
533   time_info->state=StoppedTimerState;
534 }
535 
536 /*
537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
538 %                                                                             %
539 %                                                                             %
540 %                                                                             %
541 +   U s e r T i m e                                                           %
542 %                                                                             %
543 %                                                                             %
544 %                                                                             %
545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546 %
547 %  UserTime() returns the total time the process has been scheduled (in
548 %  seconds) since the last call to StartTimer().
549 %
550 %  The format of the UserTime method is:
551 %
552 %      double UserTime()
553 %
554 */
UserTime(void)555 static double UserTime(void)
556 {
557 #if defined(MAGICKCORE_HAVE_TIMES) && defined(MAGICKCORE_HAVE_SYSCONF)
558   struct tms
559     timer;
560 
561   (void) times(&timer);
562   return((double) (timer.tms_utime+timer.tms_stime)/sysconf(_SC_CLK_TCK));
563 #else
564 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
565   return(NTUserTime());
566 #else
567   return((double) clock()/CLOCKS_PER_SEC);
568 #endif
569 #endif
570 }
571