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