1 | // boost cpu_timer.cpp ---------------------------------------------------------------// |
2 | |
3 | // Copyright Beman Dawes 1994-2006, 2011 |
4 | |
5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | // See http://www.boost.org/libs/timer for documentation. |
9 | |
10 | //--------------------------------------------------------------------------------------// |
11 | |
12 | // define BOOST_TIMER_SOURCE so that <boost/timer/config.hpp> knows |
13 | // the library is being built (possibly exporting rather than importing code) |
14 | #ifndef BOOST_TIMER_SOURCE |
15 | # define BOOST_TIMER_SOURCE |
16 | #endif |
17 | |
18 | #include <boost/timer/timer.hpp> |
19 | #include <boost/io/ios_state.hpp> |
20 | #include <boost/predef.h> |
21 | #include <boost/config.hpp> |
22 | #include <cstring> |
23 | #include <sstream> |
24 | #include <cassert> |
25 | |
26 | #if defined(_WIN32) |
27 | # include <windows.h> |
28 | #else |
29 | # include <unistd.h> |
30 | # include <sys/times.h> |
31 | #endif |
32 | |
33 | using boost::timer::nanosecond_type; |
34 | using boost::timer::cpu_times; |
35 | |
36 | namespace |
37 | { |
38 | |
39 | void show_time(const cpu_times& times, |
40 | std::ostream& os, const std::string& fmt, short places) |
41 | // NOTE WELL: Will truncate least-significant digits to LDBL_DIG, which may |
42 | // be as low as 10, although will be 15 for many common platforms. |
43 | { |
44 | if (places > 9) |
45 | places = 9; |
46 | else if (places < 0) |
47 | places = boost::timer::default_places; |
48 | |
49 | boost::io::ios_flags_saver ifs(os); |
50 | boost::io::ios_precision_saver ips(os); |
51 | os.setf(fmtfl: std::ios_base::fixed, mask: std::ios_base::floatfield); |
52 | os.precision(prec: places); |
53 | |
54 | const double sec = 1000000000.0L; |
55 | nanosecond_type total = times.system + times.user; |
56 | double wall_sec = static_cast<double>(times.wall) / sec; |
57 | double total_sec = static_cast<double>(total) / sec; |
58 | |
59 | for (const char* format = fmt.c_str(); *format; ++format) |
60 | { |
61 | if (*format != '%' || !*(format+1) || !std::strchr(s: "wustp" , c: *(format+1))) |
62 | os << *format; // anything except % followed by a valid format character |
63 | // gets sent to the output stream |
64 | else |
65 | { |
66 | ++format; |
67 | switch (*format) |
68 | { |
69 | case 'w': |
70 | os << wall_sec; |
71 | break; |
72 | case 'u': |
73 | os << static_cast<double>(times.user) / sec; |
74 | break; |
75 | case 's': |
76 | os << static_cast<double>(times.system) / sec; |
77 | break; |
78 | case 't': |
79 | os << total_sec; |
80 | break; |
81 | case 'p': |
82 | os.precision(prec: 1); |
83 | if (wall_sec > 0.001L && total_sec > 0.001L) |
84 | os << (total_sec/wall_sec) * 100.0; |
85 | else |
86 | os << "n/a" ; |
87 | os.precision(prec: places); |
88 | break; |
89 | } |
90 | } |
91 | } |
92 | } |
93 | |
94 | #if defined(_WIN32) |
95 | |
96 | boost::long_long_type query_performance_frequency() |
97 | { |
98 | LARGE_INTEGER li; |
99 | ::QueryPerformanceFrequency( &li ); // never fails |
100 | |
101 | return li.QuadPart; |
102 | } |
103 | |
104 | void get_cpu_times( boost::timer::cpu_times& current ) |
105 | { |
106 | static const boost::long_long_type freq = query_performance_frequency(); |
107 | |
108 | LARGE_INTEGER li; |
109 | ::QueryPerformanceCounter( &li ); // never fails |
110 | |
111 | boost::long_long_type ctr = li.QuadPart; |
112 | |
113 | boost::long_long_type const nano = INT64_C( 1000000000 ); // ns |
114 | |
115 | // ctr * nano / freq, but with less overflow |
116 | |
117 | boost::long_long_type whole = (ctr / freq) * nano; |
118 | boost::long_long_type part = (ctr % freq) * nano / freq; |
119 | |
120 | current.wall = whole + part; |
121 | current.user = boost::timer::nanosecond_type( -1 ); |
122 | current.system = boost::timer::nanosecond_type( -1 ); |
123 | |
124 | #if BOOST_PLAT_WINDOWS_DESKTOP |
125 | |
126 | FILETIME creation, exit, kernel, user; |
127 | |
128 | if( !::GetProcessTimes( ::GetCurrentProcess(), &creation, &exit, &kernel, &user ) ) |
129 | { |
130 | return; |
131 | } |
132 | |
133 | // Windows uses 100 nanosecond ticks |
134 | |
135 | current.system = ( ( boost::timer::nanosecond_type( kernel.dwHighDateTime ) << 32 ) + kernel.dwLowDateTime ) * 100; |
136 | current.user = ( ( boost::timer::nanosecond_type( user.dwHighDateTime ) << 32 ) + user.dwLowDateTime ) * 100; |
137 | |
138 | #endif |
139 | } |
140 | |
141 | #else |
142 | |
143 | // multiplier to convert ticks to nanoseconds; -1 if unknown |
144 | boost::int_least64_t tick_factor() |
145 | { |
146 | boost::int_least64_t tf = ::sysconf( _SC_CLK_TCK ); |
147 | if( tf <= 0 ) return -1; |
148 | |
149 | tf = INT64_C( 1000000000 ) / tf; // compute factor |
150 | if( tf == 0 ) tf = -1; |
151 | |
152 | return tf; |
153 | } |
154 | |
155 | void get_cpu_times( boost::timer::cpu_times& current ) |
156 | { |
157 | current.wall = boost::timer::nanosecond_type( -1 ); |
158 | current.user = boost::timer::nanosecond_type( -1 ); |
159 | current.system = boost::timer::nanosecond_type( -1 ); |
160 | |
161 | static boost::int_least64_t tf = tick_factor(); |
162 | |
163 | if( tf == -1 ) return; |
164 | |
165 | tms tm; |
166 | clock_t c = ::times( buffer: &tm ); |
167 | |
168 | if( c == static_cast<clock_t>( -1 ) ) return; |
169 | |
170 | current.wall = boost::timer::nanosecond_type( c ) * tf; |
171 | current.system = boost::timer::nanosecond_type( tm.tms_stime + tm.tms_cstime ) * tf; |
172 | current.user = boost::timer::nanosecond_type( tm.tms_utime + tm.tms_cutime ) * tf; |
173 | } |
174 | |
175 | #endif |
176 | |
177 | // CAUTION: must be identical to same constant in auto_timers_construction.cpp |
178 | const std::string default_fmt(" %ws wall, %us user + %ss system = %ts CPU (%p%)\n" ); |
179 | |
180 | } // unnamed namespace |
181 | |
182 | namespace boost |
183 | { |
184 | namespace timer |
185 | { |
186 | // format ------------------------------------------------------------------------// |
187 | |
188 | BOOST_TIMER_DECL |
189 | std::string format(const cpu_times& times, short places, const std::string& fmt) |
190 | { |
191 | std::stringstream ss; |
192 | ss.exceptions(except: std::ios_base::badbit | std::ios_base::failbit); |
193 | show_time(times, os&: ss, fmt, places); |
194 | return ss.str(); |
195 | } |
196 | |
197 | BOOST_TIMER_DECL |
198 | std::string format(const cpu_times& times, short places) |
199 | { |
200 | return format(times, places, fmt: default_fmt); |
201 | } |
202 | |
203 | // cpu_timer ---------------------------------------------------------------------// |
204 | |
205 | void cpu_timer::start() BOOST_NOEXCEPT |
206 | { |
207 | m_is_stopped = false; |
208 | get_cpu_times(current&: m_times); |
209 | } |
210 | |
211 | void cpu_timer::stop() BOOST_NOEXCEPT |
212 | { |
213 | if (is_stopped()) |
214 | return; |
215 | m_is_stopped = true; |
216 | |
217 | cpu_times current; |
218 | get_cpu_times(current); |
219 | m_times.wall = (current.wall - m_times.wall); |
220 | m_times.user = (current.user - m_times.user); |
221 | m_times.system = (current.system - m_times.system); |
222 | } |
223 | |
224 | cpu_times cpu_timer::elapsed() const BOOST_NOEXCEPT |
225 | { |
226 | if (is_stopped()) |
227 | return m_times; |
228 | cpu_times current; |
229 | get_cpu_times(current); |
230 | current.wall -= m_times.wall; |
231 | current.user -= m_times.user; |
232 | current.system -= m_times.system; |
233 | return current; |
234 | } |
235 | |
236 | void cpu_timer::resume() BOOST_NOEXCEPT |
237 | { |
238 | if (is_stopped()) |
239 | { |
240 | cpu_times current (m_times); |
241 | start(); |
242 | m_times.wall -= current.wall; |
243 | m_times.user -= current.user; |
244 | m_times.system -= current.system; |
245 | } |
246 | } |
247 | |
248 | // auto_cpu_timer ----------------------------------------------------------------// |
249 | |
250 | auto_cpu_timer::auto_cpu_timer(std::ostream& os, short places) // #5 |
251 | : m_places(places), m_os(&os), m_format(default_fmt) |
252 | { |
253 | start(); |
254 | } |
255 | |
256 | void auto_cpu_timer::report() |
257 | { |
258 | show_time(times: elapsed(), os&: ostream(), fmt: format_string(), places: places()); |
259 | } |
260 | |
261 | auto_cpu_timer::~auto_cpu_timer() |
262 | { |
263 | if (!is_stopped()) |
264 | { |
265 | stop(); // the sooner we stop(), the better |
266 | #ifndef BOOST_NO_EXCEPTIONS |
267 | try |
268 | { |
269 | #endif |
270 | report(); |
271 | #ifndef BOOST_NO_EXCEPTIONS |
272 | } |
273 | catch (...) // eat any exceptions |
274 | { |
275 | } |
276 | #endif |
277 | } |
278 | } |
279 | |
280 | } // namespace timer |
281 | } // namespace boost |
282 | |