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