MagickCore  7.1.2-29
Convert, Edit, Or Compose Bitmap Images
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 */
68 static double
69  UserTime(void);
70 
71 static void
72  StopTimer(TimerInfo *);
73 ␌
74 /*
75  Static declarations.
76 */
77 static ssize_t
78  date_precision = -1;
79 
80 static time_t
81  magick_epoch = (time_t) 0;
82 
83 static 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 */
105 MagickExport 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 */
140 MagickExport 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 */
178 MagickExport 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 */
206 static 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 */
272 MagickExport 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 */
329 MagickExport 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 */
358 static 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 
380 MagickExport 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 */
414 MagickExport 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 */
450 MagickExport 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 */
482 MagickExport 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 */
510 MagickExport 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 */
541 MagickPrivate 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 */
572 MagickExport 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 */
614 static 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 */
649 static 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 }