1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7 /*                            fuer Informationstechnik Berlin                */
8 /*                                                                           */
9 /*  SCIP is distributed under the terms of the ZIB Academic License.         */
10 /*                                                                           */
11 /*  You should have received a copy of the ZIB Academic License              */
12 /*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13 /*                                                                           */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file   clock.c
17  * @ingroup OTHER_CFILES
18  * @brief  methods for clocks and timing issues
19  * @author Tobias Achterberg
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include <assert.h>
25 #if defined(_WIN32) || defined(_WIN64)
26 #include <windows.h>
27 #else
28 #include <sys/times.h>
29 #include <sys/time.h>
30 #include <unistd.h>
31 #endif
32 #include <time.h>
33 
34 #include "scip/def.h"
35 #include "scip/pub_message.h"
36 #include "blockmemshell/memory.h"
37 #include "scip/set.h"
38 #include "scip/clock.h"
39 
40 #include "scip/struct_clock.h"
41 
42 /** converts CPU clock ticks into seconds */
43 static
cputime2sec(clock_t cputime)44 SCIP_Real cputime2sec(
45    clock_t               cputime             /**< clock ticks for CPU time */
46    )
47 {
48    clock_t clocks_per_second;
49 
50 #if defined(_WIN32) || defined(_WIN64)
51    clocks_per_second = 100;
52 #else
53 #ifndef CLK_TCK
54    clocks_per_second = sysconf(_SC_CLK_TCK);
55 #else
56    clocks_per_second = CLK_TCK;
57 #endif
58 #endif
59 
60    return (SCIP_Real)cputime / (SCIP_Real)clocks_per_second;
61 }
62 
63 /*lint -esym(*,timeval)*/
64 /*lint -esym(*,gettimeofday)*/
65 
66 /** converts wall clock time into seconds */
67 static
walltime2sec(long sec,long usec)68 SCIP_Real walltime2sec(
69    long                  sec,                /**< seconds counter */
70    long                  usec                /**< microseconds counter */
71    )
72 {
73    return (SCIP_Real)sec + 0.000001 * (SCIP_Real)usec;
74 }
75 
76 /** converts seconds into CPU clock ticks */
77 static
sec2cputime(SCIP_Real sec,clock_t * cputime)78 void sec2cputime(
79    SCIP_Real             sec,                /**< seconds */
80    clock_t*              cputime             /**< pointer to store clock ticks for CPU time */
81    )
82 {
83    clock_t clocks_per_second;
84 
85    assert(cputime != NULL);
86 
87 #if defined(_WIN32) || defined(_WIN64)
88    clocks_per_second = 100;
89 #else
90 #ifndef CLK_TCK
91    clocks_per_second = sysconf(_SC_CLK_TCK);
92 #else
93    clocks_per_second = CLK_TCK;
94 #endif
95 #endif
96    *cputime = (clock_t)(sec * clocks_per_second);
97 }
98 
99 /** converts wall clock time into seconds */
100 static
sec2walltime(SCIP_Real sec,long * wallsec,long * wallusec)101 void sec2walltime(
102    SCIP_Real             sec,                /**< seconds */
103    long*                 wallsec,            /**< pointer to store seconds counter */
104    long*                 wallusec            /**< pointer to store microseconds counter */
105    )
106 {
107    assert(wallsec != NULL);
108    assert(wallusec != NULL);
109 
110    *wallsec = (long)sec;
111    *wallusec = (long)((sec  - *wallsec) * 1000000.0);
112 }
113 
114 
115 /** sets the clock's type and converts the clock timer accordingly */
116 static
clockSetType(SCIP_CLOCK * clck,SCIP_CLOCKTYPE newtype)117 void clockSetType(
118    SCIP_CLOCK*           clck,               /**< clock timer */
119    SCIP_CLOCKTYPE        newtype             /**< new clock type */
120    )
121 {
122    assert(clck != NULL);
123    assert(newtype != SCIP_CLOCKTYPE_DEFAULT);
124 
125    if( clck->clocktype != newtype )
126    {
127       if( clck->clocktype == SCIP_CLOCKTYPE_DEFAULT )
128       {
129          assert(clck->nruns == 0);
130          clck->clocktype = newtype;
131          SCIPclockReset(clck);
132          SCIPdebugMessage("switched clock type to %d\n", newtype);
133       }
134       else
135       {
136          SCIP_Real sec;
137 
138          sec = SCIPclockGetTime(clck);
139          clck->clocktype = newtype;
140          SCIPclockSetTime(clck, sec);
141          SCIPdebugMessage("switched clock type to %d (%g seconds -> %g seconds)\n", newtype, sec, SCIPclockGetTime(clck));
142       }
143    }
144 }
145 
146 /** if the clock uses the default clock type and the default changed, converts the clock timer to the new type */
147 static
clockUpdateDefaultType(SCIP_CLOCK * clck,SCIP_CLOCKTYPE defaultclocktype)148 void clockUpdateDefaultType(
149    SCIP_CLOCK*           clck,               /**< clock timer */
150    SCIP_CLOCKTYPE        defaultclocktype    /**< default type of clock to use */
151    )
152 {
153    assert(clck != NULL);
154    assert(defaultclocktype != SCIP_CLOCKTYPE_DEFAULT);
155 
156    if( clck->usedefault && clck->clocktype != defaultclocktype )
157       clockSetType(clck, defaultclocktype);
158 }
159 
160 /** creates a clock and initializes it */
SCIPclockCreate(SCIP_CLOCK ** clck,SCIP_CLOCKTYPE clocktype)161 SCIP_RETCODE SCIPclockCreate(
162    SCIP_CLOCK**          clck,               /**< pointer to clock timer */
163    SCIP_CLOCKTYPE        clocktype           /**< type of clock */
164    )
165 {
166    assert(clck != NULL);
167 
168    SCIP_ALLOC( BMSallocMemory(clck) );
169 
170    SCIPclockInit(*clck, clocktype);
171 
172    return SCIP_OKAY;
173 }
174 
175 /** frees a clock */
SCIPclockFree(SCIP_CLOCK ** clck)176 void SCIPclockFree(
177    SCIP_CLOCK**          clck                /**< pointer to clock timer */
178    )
179 {
180    assert(clck != NULL);
181 
182    BMSfreeMemory(clck);
183 }
184 
185 /** initializes and resets a clock */
SCIPclockInit(SCIP_CLOCK * clck,SCIP_CLOCKTYPE clocktype)186 void SCIPclockInit(
187    SCIP_CLOCK*           clck,               /**< clock timer */
188    SCIP_CLOCKTYPE        clocktype           /**< type of clock */
189    )
190 {
191    assert(clck != NULL);
192 
193    SCIPdebugMessage("initializing clock %p of type %d\n", (void*)clck, clocktype);
194    clck->enabled = TRUE;
195    clck->lasttime = 0.0;
196    SCIPclockSetType(clck, clocktype);
197 }
198 
199 /** completely stop the clock and reset the clock's counter to zero */
SCIPclockReset(SCIP_CLOCK * clck)200 void SCIPclockReset(
201    SCIP_CLOCK*           clck                /**< clock timer */
202    )
203 {
204    assert(clck != NULL);
205 
206    SCIPdebugMessage("resetting clock %p of type %d (usedefault=%u)\n", (void*)clck, clck->clocktype, clck->usedefault);
207    switch( clck->clocktype )
208    {
209    case SCIP_CLOCKTYPE_DEFAULT:
210       break;
211    case SCIP_CLOCKTYPE_CPU:
212       clck->data.cpuclock.user = 0;
213       break;
214    case SCIP_CLOCKTYPE_WALL:
215       clck->data.wallclock.sec = 0;
216       clck->data.wallclock.usec = 0;
217       break;
218    default:
219       SCIPerrorMessage("invalid clock type\n");
220       SCIPABORT();
221    }
222    clck->nruns = 0;
223 }
224 
225 /** enables the clock */
SCIPclockEnable(SCIP_CLOCK * clck)226 void SCIPclockEnable(
227    SCIP_CLOCK*           clck                /**< clock timer */
228    )
229 {
230    assert(clck != NULL);
231 
232    SCIPdebugMessage("enabling clock %p of type %d (usedefault=%u)\n", (void*)clck, clck->clocktype, clck->usedefault);
233 
234    clck->enabled = TRUE;
235 }
236 
237 /** disables and resets the clock */
SCIPclockDisable(SCIP_CLOCK * clck)238 void SCIPclockDisable(
239    SCIP_CLOCK*           clck                /**< clock timer */
240    )
241 {
242    assert(clck != NULL);
243 
244    SCIPdebugMessage("disabling clock %p of type %d (usedefault=%u)\n", (void*)clck, clck->clocktype, clck->usedefault);
245 
246    clck->enabled = FALSE;
247    SCIPclockReset(clck);
248 }
249 
250 /** enables or disables \p clck, depending on the value of the flag */
SCIPclockEnableOrDisable(SCIP_CLOCK * clck,SCIP_Bool enable)251 void SCIPclockEnableOrDisable(
252    SCIP_CLOCK*           clck,               /**< the clock to be disabled/enabled */
253    SCIP_Bool             enable              /**< should the clock be enabled? */
254    )
255 {
256    assert(clck != NULL);
257 
258    if( enable )
259       SCIPclockEnable(clck);
260    else
261       SCIPclockDisable(clck);
262 }
263 
264 /** sets the type of the clock, overriding the default clock type, and resets the clock */
SCIPclockSetType(SCIP_CLOCK * clck,SCIP_CLOCKTYPE clocktype)265 void SCIPclockSetType(
266    SCIP_CLOCK*           clck,               /**< clock timer */
267    SCIP_CLOCKTYPE        clocktype           /**< type of clock */
268    )
269 {
270    assert(clck != NULL);
271 
272    SCIPdebugMessage("setting type of clock %p (type %d, usedefault=%u) to %d\n",
273       (void*)clck, clck->clocktype, clck->usedefault, clocktype);
274 
275    clck->clocktype = clocktype;
276    clck->usedefault = (clocktype == SCIP_CLOCKTYPE_DEFAULT);
277    SCIPclockReset(clck);
278 }
279 
280 /** starts measurement of time in the given clock */
SCIPclockStart(SCIP_CLOCK * clck,SCIP_SET * set)281 void SCIPclockStart(
282    SCIP_CLOCK*           clck,               /**< clock timer */
283    SCIP_SET*             set                 /**< global SCIP settings */
284    )
285 {
286    assert(clck != NULL);
287    assert(set != NULL);
288 
289    if( set->time_enabled && clck->enabled )
290    {
291       clockUpdateDefaultType(clck, set->time_clocktype);
292 
293       if( clck->nruns == 0 )
294       {
295 #if defined(_WIN32) || defined(_WIN64)
296          FILETIME creationtime;
297          FILETIME exittime;
298          FILETIME kerneltime;
299          FILETIME usertime;
300 #else
301          struct timeval tp; /*lint !e86*/
302          struct tms now;
303 #endif
304 
305          SCIPdebugMessage("starting clock %p (type %d, usedefault=%u)\n", (void*)clck, clck->clocktype, clck->usedefault);
306 
307          switch( clck->clocktype )
308          {
309          case SCIP_CLOCKTYPE_CPU:
310 #if defined(_WIN32) || defined(_WIN64)
311             GetProcessTimes(GetCurrentProcess(), &creationtime, &exittime, &kerneltime, &usertime);
312             clck->data.cpuclock.user -= usertime.dwHighDateTime * 42950 + usertime.dwLowDateTime / 100000L;
313 #else
314             (void)times(&now);
315             clck->data.cpuclock.user -= now.tms_utime;
316 #endif
317             clck->lasttime = cputime2sec(clck->data.cpuclock.user);
318             break;
319 
320          case SCIP_CLOCKTYPE_WALL:
321 #if defined(_WIN32) || defined(_WIN64)
322             clck->data.wallclock.sec -= time(NULL);
323 #else
324             gettimeofday(&tp, NULL);
325             if( tp.tv_usec > clck->data.wallclock.usec ) /*lint !e115 !e40*/
326             {
327                clck->data.wallclock.sec -= (tp.tv_sec + 1); /*lint !e115 !e40*/
328                clck->data.wallclock.usec += (1000000 - tp.tv_usec); /*lint !e115 !e40*/
329             }
330             else
331             {
332                clck->data.wallclock.sec -= tp.tv_sec; /*lint !e115 !e40*/
333                clck->data.wallclock.usec -= tp.tv_usec; /*lint !e115 !e40*/
334             }
335 #endif
336             clck->lasttime = walltime2sec(clck->data.wallclock.sec, clck->data.wallclock.usec);
337             break;
338 
339          case SCIP_CLOCKTYPE_DEFAULT:
340          default:
341             SCIPerrorMessage("invalid clock type\n");
342             SCIPABORT();
343          }
344       }
345 
346       clck->nruns++;
347    }
348 }
349 
350 /** stops measurement of time in the given clock */
SCIPclockStop(SCIP_CLOCK * clck,SCIP_SET * set)351 void SCIPclockStop(
352    SCIP_CLOCK*           clck,               /**< clock timer */
353    SCIP_SET*             set                 /**< global SCIP settings */
354    )
355 {
356    assert(clck != NULL);
357    assert(set != NULL);
358 
359    if( set->time_enabled && clck->enabled )
360    {
361       assert(clck->nruns >= 1);
362 
363       clck->nruns--;
364       if( clck->nruns == 0 )
365       {
366 #if defined(_WIN32) || defined(_WIN64)
367          FILETIME creationtime;
368          FILETIME exittime;
369          FILETIME kerneltime;
370          FILETIME usertime;
371 #else
372          struct timeval tp; /*lint !e86*/
373          struct tms now;
374 #endif
375 
376          SCIPdebugMessage("stopping clock %p (type %d, usedefault=%u)\n", (void*)clck, clck->clocktype, clck->usedefault);
377 
378          switch( clck->clocktype )
379          {
380          case SCIP_CLOCKTYPE_CPU:
381 #if defined(_WIN32) || defined(_WIN64)
382             GetProcessTimes(GetCurrentProcess(), &creationtime, &exittime, &kerneltime, &usertime);
383             clck->data.cpuclock.user += usertime.dwHighDateTime * 42950 + usertime.dwLowDateTime / 100000L;
384 #else
385             (void)times(&now);
386             clck->data.cpuclock.user += now.tms_utime;
387 #endif
388             break;
389 
390          case SCIP_CLOCKTYPE_WALL:
391 #if defined(_WIN32) || defined(_WIN64)
392             clck->data.wallclock.sec += time(NULL);
393 #else
394             gettimeofday(&tp, NULL);
395             if( tp.tv_usec + clck->data.wallclock.usec > 1000000 ) /*lint !e115 !e40*/
396             {
397                clck->data.wallclock.sec += (tp.tv_sec + 1); /*lint !e115 !e40*/
398                clck->data.wallclock.usec -= (1000000 - tp.tv_usec); /*lint !e115 !e40*/
399             }
400             else
401             {
402                clck->data.wallclock.sec += tp.tv_sec; /*lint !e115 !e40*/
403                clck->data.wallclock.usec += tp.tv_usec; /*lint !e115 !e40*/
404             }
405 #endif
406             break;
407 
408          case SCIP_CLOCKTYPE_DEFAULT:
409          default:
410             SCIPerrorMessage("invalid clock type\n");
411             SCIPABORT();
412          }
413       }
414    }
415 }
416 
417 /** returns whether the clock is currently running */
SCIPclockIsRunning(SCIP_CLOCK * clck)418 SCIP_Bool SCIPclockIsRunning(
419    SCIP_CLOCK*           clck                /**< clock timer */
420    )
421 {
422    assert(clck != NULL);
423 
424    return (clck->nruns > 0);
425 }
426 
427 
428 /** gets the used time of this clock in seconds */
SCIPclockGetTime(SCIP_CLOCK * clck)429 SCIP_Real SCIPclockGetTime(
430    SCIP_CLOCK*           clck                /**< clock timer */
431    )
432 {
433    SCIP_Real result;
434    assert(clck != NULL);
435    result = 0.0;
436 
437    SCIPdebugMessage("getting time of clock %p (type %d, usedefault=%u, nruns=%d)\n",
438       (void*)clck, clck->clocktype, clck->usedefault, clck->nruns);
439 
440    if( clck->nruns == 0 )
441    {
442       /* the clock is not running: convert the clocks timer into seconds */
443       switch( clck->clocktype )
444       {
445       case SCIP_CLOCKTYPE_DEFAULT:
446          break;
447       case SCIP_CLOCKTYPE_CPU:
448          result = cputime2sec(clck->data.cpuclock.user);
449          break;
450       case SCIP_CLOCKTYPE_WALL:
451          result = walltime2sec(clck->data.wallclock.sec, clck->data.wallclock.usec);
452          break;
453       default:
454          SCIPerrorMessage("invalid clock type\n");
455          SCIPABORT();
456          result = 0.0; /*lint !e527*/
457       }
458    }
459    else
460    {
461 #if defined(_WIN32) || defined(_WIN64)
462       FILETIME creationtime;
463       FILETIME exittime;
464       FILETIME kerneltime;
465       FILETIME usertime;
466 #else
467       struct timeval tp; /*lint !e86*/
468       struct tms now;
469 #endif
470 
471       /* the clock is currently running: we have to add the current time to the clocks timer */
472       switch( clck->clocktype )
473       {
474       case SCIP_CLOCKTYPE_CPU:
475 #if defined(_WIN32) || defined(_WIN64)
476           GetProcessTimes(GetCurrentProcess(), &creationtime, &exittime, &kerneltime, &usertime);
477           result = cputime2sec(clck->data.cpuclock.user + usertime.dwHighDateTime * 42950 + usertime.dwLowDateTime / 100000L);
478 #else
479          (void)times(&now);
480          result = cputime2sec(clck->data.cpuclock.user + now.tms_utime);
481 #endif
482          break;
483       case SCIP_CLOCKTYPE_WALL:
484 #if defined(_WIN32) || defined(_WIN64)
485          result = walltime2sec(clck->data.wallclock.sec + time(NULL), 0);
486 #else
487          gettimeofday(&tp, NULL);
488          if( tp.tv_usec + clck->data.wallclock.usec > 1000000 ) /*lint !e115 !e40*/
489             result = walltime2sec(clck->data.wallclock.sec + tp.tv_sec + 1, /*lint !e115 !e40*/
490                (clck->data.wallclock.usec - 1000000) + tp.tv_usec); /*lint !e115 !e40*/
491          else
492             result = walltime2sec(clck->data.wallclock.sec + tp.tv_sec, /*lint !e115 !e40*/
493                clck->data.wallclock.usec + tp.tv_usec); /*lint !e115 !e40*/
494 #endif
495          break;
496       case SCIP_CLOCKTYPE_DEFAULT:
497       default:
498          SCIPerrorMessage("invalid clock type\n");
499          SCIPABORT();
500          result = 0.0; /*lint !e527*/
501       }
502    }
503 
504    clck->lasttime = result;
505    return result;
506 }
507 
508 /** gets the last validated time of this clock in seconds */
SCIPclockGetLastTime(SCIP_CLOCK * clck)509 SCIP_Real SCIPclockGetLastTime(
510    SCIP_CLOCK*           clck                /**< clock timer */
511    )
512 {
513    assert(clck != NULL);
514 
515    return clck->lasttime;
516 }
517 
518 /** sets the used time of this clock in seconds */
SCIPclockSetTime(SCIP_CLOCK * clck,SCIP_Real sec)519 void SCIPclockSetTime(
520    SCIP_CLOCK*           clck,               /**< clock timer */
521    SCIP_Real             sec                 /**< time in seconds to set the clock's timer to */
522    )
523 {
524    assert(clck != NULL);
525 
526    SCIPdebugMessage("setting time of clock %p (type %d, usedefault=%u, nruns=%d) to %g\n",
527       (void*)clck, clck->clocktype, clck->usedefault, clck->nruns, sec);
528 
529    /* if the clock type is not yet set, set it to an arbitrary value to be able to store the number */
530    if( clck->clocktype == SCIP_CLOCKTYPE_DEFAULT )
531       clockSetType(clck, SCIP_CLOCKTYPE_WALL);
532 
533    switch( clck->clocktype )
534    {
535    case SCIP_CLOCKTYPE_CPU:
536       sec2cputime(sec, &clck->data.cpuclock.user);
537       break;
538 
539    case SCIP_CLOCKTYPE_WALL:
540       sec2walltime(sec, &clck->data.wallclock.sec, &clck->data.wallclock.usec);
541       break;
542 
543    case SCIP_CLOCKTYPE_DEFAULT:
544    default:
545       SCIPerrorMessage("invalid clock type\n");
546       SCIPABORT();
547    }
548 
549    if( clck->nruns >= 1 )
550    {
551 #if defined(_WIN32) || defined(_WIN64)
552       FILETIME creationtime;
553       FILETIME exittime;
554       FILETIME kerneltime;
555       FILETIME usertime;
556 #else
557       struct timeval tp; /*lint !e86*/
558       struct tms now;
559 #endif
560 
561       /* the clock is currently running: we have to subtract the current time from the new timer value */
562       switch( clck->clocktype )
563       {
564       case SCIP_CLOCKTYPE_CPU:
565 #if defined(_WIN32) || defined(_WIN64)
566          GetProcessTimes(GetCurrentProcess(), &creationtime, &exittime, &kerneltime, &usertime);
567          clck->data.cpuclock.user -= usertime.dwHighDateTime * 42950 + usertime.dwLowDateTime / 100000L;
568 #else
569          (void)times(&now);
570          clck->data.cpuclock.user -= now.tms_utime;
571 #endif
572          break;
573 
574       case SCIP_CLOCKTYPE_WALL:
575 #if defined(_WIN32) || defined(_WIN64)
576          clck->data.wallclock.sec -= time(NULL);
577 #else
578          gettimeofday(&tp, NULL);
579          if( tp.tv_usec > clck->data.wallclock.usec ) /*lint !e115 !e40*/
580          {
581             clck->data.wallclock.sec -= (tp.tv_sec + 1); /*lint !e115 !e40*/
582             clck->data.wallclock.usec += (1000000 - tp.tv_usec); /*lint !e115 !e40*/
583          }
584          else
585          {
586             clck->data.wallclock.sec -= tp.tv_sec; /*lint !e115 !e40*/
587             clck->data.wallclock.usec -= tp.tv_usec; /*lint !e115 !e40*/
588          }
589 #endif
590          break;
591 
592       case SCIP_CLOCKTYPE_DEFAULT:
593       default:
594          SCIPerrorMessage("invalid clock type\n");
595          SCIPABORT();
596       }
597    }
598 }
599 
600 /** gets current time of day in seconds (standard time zone) */
SCIPclockGetTimeOfDay(void)601 SCIP_Real SCIPclockGetTimeOfDay(
602    void
603    )
604 {
605 #if defined(_WIN32) || defined(_WIN64)
606    time_t now;
607    now = time(NULL);
608    return (SCIP_Real)(now % (24*3600));
609 #else
610    struct timeval tp; /*lint !e86*/
611 
612    gettimeofday(&tp, NULL);
613 
614    return (SCIP_Real)(tp.tv_sec % (24*3600)) + (SCIP_Real)tp.tv_usec / 1e+6; /*lint !e40 !e115*/
615 #endif
616 }
617