Scippy

SCIP

Solving Constraint Integer Programs

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