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