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