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
33using boost::timer::nanosecond_type;
34using boost::timer::cpu_times;
35
36namespace
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
96boost::long_long_type query_performance_frequency()
97{
98 LARGE_INTEGER li;
99 ::QueryPerformanceFrequency( &li ); // never fails
100
101 return li.QuadPart;
102}
103
104void 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
144boost::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
155void 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
178const std::string default_fmt(" %ws wall, %us user + %ss system = %ts CPU (%p%)\n");
179
180} // unnamed namespace
181
182namespace 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

source code of boost/libs/timer/src/cpu_timer.cpp