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