1 // -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=8 sw=2 sts=2:
3 
4 //make sure clock_gettime is available
5 #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE < 199309L
6 #undef _POSIX_C_SOURCE
7 #endif
8 #if !defined(_POSIX_C_SOURCE) && !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__DragonFly__)
9 #define _POSIX_C_SOURCE 199309L
10 #endif
11 
12 //make sure gettimeofday is available
13 #ifndef _DEFAULT_SOURCE
14 #define _DEFAULT_SOURCE
15 #endif
16 
17 #if HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include <cerrno>
22 #include <iomanip>
23 #include <ostream>
24 #include <sstream>
25 #include <string>
26 
27 #include <sys/resource.h>
28 #include <sys/time.h>
29 #include <time.h>
30 #include <unistd.h>
31 
32 #include <dune/common/exceptions.hh>
33 
34 #include "clock.hh"
35 
36 namespace Dune {
37   namespace PDELab {
38 
operator <<(std::ostream & s,const TimeSpec & t)39     std::ostream &operator<<(std::ostream &s, const TimeSpec &t) {
40       std::ostringstream tmp;
41       tmp << t.tv_sec << '.' << std::setfill('0') << std::setw(9) << t.tv_nsec;
42       std::string tmpstr = tmp.str();
43       if(s.precision() < 9)
44         tmpstr.resize(tmpstr.size() - ( 9 - s.precision() ));
45       if(s.precision() == 0)
46         tmpstr.resize(tmpstr.size() - 1);
47       s << tmpstr;
48       return s;
49     }
50 
51     //////////////////////////////////////////////////////////////////////
52     //
53     //  Wall time
54     //
55 
56 #if HAVE_POSIX_CLOCK
posixGetWallTime()57     TimeSpec posixGetWallTime() {
58       timespec result;
59       if(clock_gettime(CLOCK_REALTIME, &result) < 0)
60         DUNE_THROW(ClockError, "clock_gettime(CLOCK_REALTIME, ...) failed: "
61                    "errno = " << errno);
62       TimeSpec tmp = { result.tv_sec, result.tv_nsec };
63       return tmp;
64     }
65 
posixGetWallTimeResolution()66     TimeSpec posixGetWallTimeResolution() {
67       timespec result;
68       if(clock_getres(CLOCK_REALTIME, &result) < 0)
69         DUNE_THROW(ClockError, "clock_getres(CLOCK_REALTIME, ...) failed: "
70                    "errno = " << errno);
71       TimeSpec tmp = { result.tv_sec, result.tv_nsec };
72       return tmp;
73     }
74 
checkPOSIXGetWallTime()75     bool checkPOSIXGetWallTime() {
76 # if _POSIX_TIMERS == 0
77       return sysconf(_SC_TIMERS) > 0;
78 # else // _POSIX_TIMERS > 0
79       return true;
80 # endif // _POSIX_TIMERS > 0
81     }
82 #endif // HAVE_POSIX_CLOCK
83 
gettimeofdayWallTime()84     TimeSpec gettimeofdayWallTime() {
85       timeval result;
86       if(gettimeofday(&result, NULL) < 0)
87         DUNE_THROW(ClockError, "gettimeofday() failed: errno = " << errno);
88       TimeSpec tmp = { result.tv_sec, 1000*result.tv_usec };
89       return tmp;
90     }
91 
gettimeofdayWallTimeResolution()92     const TimeSpec &gettimeofdayWallTimeResolution() {
93       static const TimeSpec res = { 0, 1000 };
94       return res;
95     }
96 
97     struct WallTimeClock {
98       TimeSpec (*clock)();
99       TimeSpec resolution;
100       std::string clockName;
101 
instanceDune::PDELab::WallTimeClock102       static const WallTimeClock &instance() {
103         static const WallTimeClock clock;
104         return clock;
105       }
106 
107     private:
WallTimeClockDune::PDELab::WallTimeClock108       WallTimeClock() {
109 #if HAVE_POSIX_CLOCK
110         if(checkPOSIXGetWallTime()) {
111           clock = posixGetWallTime;
112           resolution = posixGetWallTimeResolution();
113           clockName = "clock_gettime(CLOCK_REALTIME, ...)";
114           return;
115         }
116 #endif // HAVE_POSIX_CLOCK
117         {
118           clock = gettimeofdayWallTime;
119           resolution = gettimeofdayWallTimeResolution();
120           clockName = "gettimeofday(...)";
121           return;
122         }
123       }
124     };
getWallTime()125     TimeSpec getWallTime() { return WallTimeClock::instance().clock(); }
getWallTimeResolution()126     TimeSpec getWallTimeResolution()
127     { return WallTimeClock::instance().resolution; }
getWallTimeImp()128     const std::string &getWallTimeImp()
129     { return WallTimeClock::instance().clockName; }
130 
131     //////////////////////////////////////////////////////////////////////
132     //
133     //  Process Time
134     //
135 
136 #if HAVE_POSIX_CLOCK && _POSIX_CPUTIME >= 0
posixGetProcessTime()137     TimeSpec posixGetProcessTime() {
138       // Use clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) even though that may
139       // be problematic in the context of process migration between cores.  In
140       // practice, it appears to still be far better then the next best
141       // alternative, getrusage(), which will only update the clock every
142       // jiffy.
143       timespec result;
144       if(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &result) < 0)
145         DUNE_THROW(ClockError, "clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) "
146                    "failed: errno = " << errno);
147       TimeSpec tmp = { result.tv_sec, result.tv_nsec };
148       return tmp;
149     }
150 
posixGetProcessTimeResolution()151     TimeSpec posixGetProcessTimeResolution() {
152       timespec result;
153       if(clock_getres(CLOCK_PROCESS_CPUTIME_ID, &result) < 0)
154         DUNE_THROW(ClockError, "clock_getres(CLOCK_PROCESS_CPUTIME_ID, ...) "
155                    "failed: errno = " << errno);
156       TimeSpec tmp = { result.tv_sec, result.tv_nsec };
157       return tmp;
158     }
159 
checkPOSIXGetProcessTime()160     bool checkPOSIXGetProcessTime() {
161 # if _POSIX_CPUTIME == 0
162       return sysconf(_SC_CPUTIME) > 0;
163 # else // _POSIX_CPUTIME > 0
164       return true;
165 # endif // _POSIX_CPUTIME > 0
166     }
167 #endif // HAVE_POSIX_CLOCK && _POSIX_CPUTIME >= 0
168 
getrusageProcessTime()169     TimeSpec getrusageProcessTime() {
170       rusage ru;
171       if(getrusage(RUSAGE_SELF, &ru) < 0)
172         DUNE_THROW(ClockError, "getrusage(RUSAGE_SELF, ...) failed: errno = "
173                    << errno);
174       TimeSpec time = { ru.ru_utime.tv_sec, 1000*ru.ru_utime.tv_usec };
175       TimeSpec tmp = { ru.ru_stime.tv_sec, 1000*ru.ru_stime.tv_usec };
176       time += tmp;
177       return time;
178     }
179 
getrusageProcessTimeResolution()180     const TimeSpec &getrusageProcessTimeResolution() {
181       static const TimeSpec res = { 0, 1000 };
182       return res;
183     }
184 
185     struct ProcessTimeClock {
186       TimeSpec (*clock)();
187       TimeSpec resolution;
188       std::string clockName;
189 
instanceDune::PDELab::ProcessTimeClock190       static const ProcessTimeClock &instance() {
191         static const ProcessTimeClock clock;
192         return clock;
193       }
194 
195     private:
ProcessTimeClockDune::PDELab::ProcessTimeClock196       ProcessTimeClock() {
197 #if HAVE_POSIX_CLOCK && _POSIX_CPUTIME >= 0
198         if(checkPOSIXGetProcessTime())
199         {
200           clock = posixGetProcessTime;
201           resolution = posixGetProcessTimeResolution();
202           clockName = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)";
203           return;
204         }
205 #endif // HAVE_POSIX_CLOCK && _POSIX_CPUTIME
206         {
207           clock = getrusageProcessTime;
208           resolution = getrusageProcessTimeResolution();
209           clockName = "getrusage(RUSAGE_SELF, ...)";
210         }
211       }
212     };
getProcessTime()213     TimeSpec getProcessTime() { return ProcessTimeClock::instance().clock(); }
getProcessTimeResolution()214     TimeSpec getProcessTimeResolution()
215     { return ProcessTimeClock::instance().resolution; }
getProcessTimeImp()216     const std::string &getProcessTimeImp()
217     { return ProcessTimeClock::instance().clockName; }
218 
219   } // namespace PDELab
220 } // namespace Dune
221