1 /*
2  * Copyright (C) 2013-2016 Christoph L. Spiel
3  *
4  * This file is part of Enblend.
5  *
6  * Enblend is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Enblend is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Enblend; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 
22 #include "timer.h"
23 
24 
25 namespace timer
26 {
27     inline static double
clock_in_seconds(clock_t a_clock_time)28     clock_in_seconds(clock_t a_clock_time)
29     {
30         return static_cast<double>(a_clock_time) / static_cast<double>(CLOCKS_PER_SEC);
31     }
32 
33 
StandardWallClock()34     StandardWallClock::StandardWallClock()
35     {
36         start();
37     }
38 
39 
40     void
start()41     StandardWallClock::start()
42     {
43         value_ = clock_t();
44         start_ = clock();
45         stop_ = start_;
46     }
47 
48 
49     void
stop()50     StandardWallClock::stop()
51     {
52         stop_ = clock();
53         value_ += stop_ - start_;
54         start_ = stop_;
55     }
56 
57 
58     void
restart()59     StandardWallClock::restart()
60     {
61         start_ = clock();
62         stop_ = start_;
63     }
64 
65 
66     double
value() const67     StandardWallClock::value() const
68     {
69         return clock_in_seconds(value_);
70     }
71 
72 
73 #ifdef HAVE_CLOCK_GETTIME
74     inline static std::uint64_t
timespec_in_nano_seconds(const struct timespec & a_timespec)75     timespec_in_nano_seconds(const struct timespec& a_timespec)
76     {
77         return
78             static_cast<std::uint64_t>(a_timespec.tv_sec) * 1000000000UL +
79             static_cast<std::uint64_t>(a_timespec.tv_nsec);
80     }
81 
82 
RealTimeWallClock()83     RealTimeWallClock::RealTimeWallClock()
84     {
85         start();
86     }
87 
88 
89     void
start()90     RealTimeWallClock::start()
91     {
92         value_ = value_t();
93         clock_gettime(CLOCK_REALTIME, &start_);
94         stop_.tv_sec = start_.tv_sec;
95         stop_.tv_nsec = long();
96     }
97 
98 
99     void
stop()100     RealTimeWallClock::stop()
101     {
102         clock_gettime(CLOCK_REALTIME, &stop_);
103         value_ += timespec_in_nano_seconds(stop_) - timespec_in_nano_seconds(start_);
104         start_ = stop_;
105     }
106 
107 
108     void
restart()109     RealTimeWallClock::restart()
110     {
111         clock_gettime(CLOCK_REALTIME, &start_);
112         stop_ = start_;
113     }
114 
115 
116     double
value() const117     RealTimeWallClock::value() const
118     {
119         return static_cast<double>(value_) * 1e-9;
120     }
121 #endif // HAVE_CLOCK_GETTIME
122 
123 
124 #ifdef WIN32
125     inline static ULONGLONG
filetime_in_100nanoseconds(const _FILETIME & a_filetime)126     filetime_in_100nanoseconds(const _FILETIME& a_filetime)
127     {
128         return
129             (static_cast<ULONGLONG>(a_filetime.dwHighDateTime) << 32) +
130              static_cast<ULONGLONG>(a_filetime.dwLowDateTime);
131     }
132 
133 
ProcessorTime()134     ProcessorTime::ProcessorTime()
135     {
136         start();
137     }
138 
139 
140     void
start()141     ProcessorTime::start()
142     {
143         _FILETIME idle;
144         _FILETIME kernel;
145         _FILETIME user;
146 
147         user_value_ = ULONGLONG();
148         system_value_ = ULONGLONG();
149 
150         GetSystemTimes(&idle, &kernel, &user);
151         start_idle_value_ = filetime_in_100nanoseconds(idle);
152         start_system_value_ = filetime_in_100nanoseconds(kernel);
153         start_user_value_ = filetime_in_100nanoseconds(user);
154     }
155 
156 
157     void
stop()158     ProcessorTime::stop()
159     {
160         _FILETIME idle;
161         _FILETIME kernel;
162         _FILETIME user;
163 
164         GetSystemTimes(&idle, &kernel, &user);
165         const ULONGLONG stop_idle_value = filetime_in_100nanoseconds(idle);
166         const ULONGLONG stop_system_value = filetime_in_100nanoseconds(kernel);
167         const ULONGLONG stop_user_value = filetime_in_100nanoseconds(user);
168 
169         system_value_ = stop_system_value - start_system_value_ - (stop_idle_value - start_idle_value_);
170         user_value_ = stop_user_value - start_user_value_;
171         start_idle_value_ = stop_idle_value;
172         start_system_value_ = stop_system_value;
173         start_user_value_ = stop_user_value;
174     }
175 
176 
177     void
restart()178     ProcessorTime::restart()
179     {
180         _FILETIME idle;
181         _FILETIME kernel;
182         _FILETIME user;
183 
184         GetSystemTimes(&idle, &kernel, &user);
185         start_idle_value_ = filetime_in_100nanoseconds(idle);
186         start_system_value_ = filetime_in_100nanoseconds(kernel);
187         start_user_value_ = filetime_in_100nanoseconds(user);
188     }
189 
190 
191     double
value() const192     UserTime::value() const
193     {
194         return user_value_ / 1.0E7;
195     }
196 
197 
198     double
value() const199     SystemTime::value() const
200     {
201         return system_value_ / 1.0E7;
202     }
203 
204 #elif defined(HAVE_SYS_TIMES_H)
205 
ProcessorTime()206     ProcessorTime::ProcessorTime()
207     {
208         start();
209     }
210 
211 
212     void
start()213     ProcessorTime::start()
214     {
215         user_value_ = clock_t();
216         system_value_ = clock_t();
217         times(&start_);
218         stop_.tms_utime = start_.tms_utime;
219         stop_.tms_stime = start_.tms_stime;
220     }
221 
222 
223     void
stop()224     ProcessorTime::stop()
225     {
226         times(&stop_);
227         user_value_ = stop_.tms_utime - start_.tms_utime;
228         system_value_ = stop_.tms_stime - start_.tms_stime;
229         start_.tms_utime = stop_.tms_utime;
230         start_.tms_stime = stop_.tms_stime;
231     }
232 
233 
234     void
restart()235     ProcessorTime::restart()
236     {
237         times(&start_);
238         stop_.tms_utime = start_.tms_utime;
239         stop_.tms_stime = start_.tms_stime;
240     }
241 
242 
243     double
value() const244     UserTime::value() const
245     {
246         return clock_in_seconds(user_value_);
247     }
248 
249 
250     double
value() const251     SystemTime::value() const
252     {
253         return clock_in_seconds(system_value_);
254     }
255 
256 #else
257 
258     double
value() const259     UserTime::value() const
260     {
261         return 0.0;
262     }
263 
264 
265     double
value() const266     SystemTime::value() const
267     {
268         return 0.0;
269     }
270 #endif
271 } // namespace timer
272