Ticket #7726: cpu_timer.cpp

File cpu_timer.cpp, 7.2 KB (added by p.brockamp@…, 10 years ago)

Timer

Line 
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#define BOOST_TIMER_SOURCE
15
16#include <boost/timer/timer.hpp>
17#include <boost/chrono/chrono.hpp>
18#include <boost/io/ios_state.hpp>
19#include <boost/throw_exception.hpp>
20#include <boost/cerrno.hpp>
21#include <cstring>
22#include <sstream>
23#include <cassert>
24
25# if defined(BOOST_WINDOWS_API)
26# include <windows.h>
27# elif defined(BOOST_POSIX_API)
28# include <unistd.h>
29# if !defined(__VXWORKS__)
30# include <sys/times.h>
31# endif
32# else
33# error unknown API
34# endif
35
36using boost::timer::nanosecond_type;
37using boost::timer::cpu_times;
38using boost::system::error_code;
39
40namespace
41{
42
43 void show_time(const cpu_times& times,
44 std::ostream& os, const std::string& fmt, short places)
45 // NOTE WELL: Will truncate least-significant digits to LDBL_DIG, which may
46 // be as low as 10, although will be 15 for many common platforms.
47 {
48 if (places > 9)
49 places = 9;
50 else if (places < 0)
51 places = boost::timer::default_places;
52
53 boost::io::ios_flags_saver ifs(os);
54 boost::io::ios_precision_saver ips(os);
55 os.setf(std::ios_base::fixed, std::ios_base::floatfield);
56 os.precision(places);
57
58 const long double sec = 1000000000.0L;
59 nanosecond_type total = times.system + times.user;
60 long double wall_sec = times.wall / sec;
61 long double total_sec = total / sec;
62
63 for (const char* format = fmt.c_str(); *format; ++format)
64 {
65 if (*format != '%' || !*(format+1) || !std::strchr("wustp", *(format+1)))
66 os << *format; // anything except % followed by a valid format character
67 // gets sent to the output stream
68 else
69 {
70 ++format;
71 switch (*format)
72 {
73 case 'w':
74 os << times.wall / sec;
75 break;
76 case 'u':
77 os << times.user / sec;
78 break;
79 case 's':
80 os << times.system / sec;
81 break;
82 case 't':
83 os << total / sec;
84 break;
85 case 'p':
86 os.precision(1);
87 if (wall_sec > 0.001L && total_sec > 0.001L)
88 os << (total_sec/wall_sec) * 100.0;
89 else
90 os << "n/a";
91 os.precision(places);
92 break;
93 }
94 }
95 }
96 }
97
98# if defined(BOOST_POSIX_API)
99 boost::int_least64_t tick_factor() // multiplier to convert ticks
100 // to nanoseconds; -1 if unknown
101 {
102 static boost::int_least64_t tick_factor = 0;
103 if (!tick_factor)
104 {
105 if ((tick_factor = ::sysconf(_SC_CLK_TCK)) <= 0)
106 tick_factor = -1;
107 else
108 {
109 assert(tick_factor <= 1000000000LL); // logic doesn't handle large ticks
110 tick_factor = 1000000000LL / tick_factor; // compute factor
111 if (!tick_factor)
112 tick_factor = -1;
113 }
114 }
115 return tick_factor;
116 }
117# endif
118
119 void get_cpu_times(boost::timer::cpu_times& current)
120 {
121 boost::chrono::duration<boost::int64_t, boost::nano>
122 x (boost::chrono::high_resolution_clock::now().time_since_epoch());
123 current.wall = x.count();
124
125# if defined(BOOST_WINDOWS_API)
126
127 FILETIME creation, exit;
128 if (::GetProcessTimes(::GetCurrentProcess(), &creation, &exit,
129 (LPFILETIME)&current.system, (LPFILETIME)&current.user))
130 {
131 current.user *= 100; // Windows uses 100 nanosecond ticks
132 current.system *= 100;
133 }
134 else
135 {
136 current.system = current.user = boost::timer::nanosecond_type(-1);
137 }
138# else
139 tms tm;
140 clock_t c = ::times(&tm);
141 if (c == -1) // error
142 {
143 current.system = current.user = boost::timer::nanosecond_type(-1);
144 }
145 else
146 {
147 current.system = boost::timer::nanosecond_type(tm.tms_stime + tm.tms_cstime);
148 current.user = boost::timer::nanosecond_type(tm.tms_utime + tm.tms_cutime);
149 boost::int_least64_t factor;
150 if ((factor = tick_factor()) != -1)
151 {
152 current.user *= factor;
153 current.system *= factor;
154 }
155 else
156 {
157 current.user = current.system = boost::timer::nanosecond_type(-1);
158 }
159 }
160# endif
161 }
162
163 // CAUTION: must be identical to same constant in auto_timers_construction.cpp
164 const std::string default_fmt(" %ws wall, %us user + %ss system = %ts CPU (%p%)\n");
165
166} // unnamed namespace
167
168namespace boost
169{
170 namespace timer
171 {
172 // format ------------------------------------------------------------------------//
173
174 BOOST_TIMER_DECL
175 std::string format(const cpu_times& times, short places, const std::string& fmt)
176 {
177 std::stringstream ss;
178 show_time(times, ss, fmt, places);
179 return ss.str();
180 }
181
182 BOOST_TIMER_DECL
183 std::string format(const cpu_times& times, short places)
184 {
185 return format(times, places, default_fmt);
186 }
187
188 // cpu_timer ---------------------------------------------------------------------//
189
190 void cpu_timer::start()
191 {
192 m_is_stopped = false;
193 get_cpu_times(m_times);
194 }
195
196 void cpu_timer::stop()
197 {
198 if (is_stopped())
199 return;
200 m_is_stopped = true;
201
202 cpu_times current;
203 get_cpu_times(current);
204 m_times.wall = (current.wall - m_times.wall);
205 m_times.user = (current.user - m_times.user);
206 m_times.system = (current.system - m_times.system);
207 }
208
209 cpu_times cpu_timer::elapsed() const
210 {
211 if (is_stopped())
212 return m_times;
213 cpu_times current;
214 get_cpu_times(current);
215 current.wall -= m_times.wall;
216 current.user -= m_times.user;
217 current.system -= m_times.system;
218 return current;
219 }
220
221 void cpu_timer::resume()
222 {
223 if (is_stopped())
224 {
225 cpu_times current (m_times);
226 start();
227 m_times.wall -= current.wall;
228 m_times.user -= current.user;
229 m_times.system -= current.system;
230 }
231 }
232
233 // auto_cpu_timer ----------------------------------------------------------------//
234
235 auto_cpu_timer::auto_cpu_timer(std::ostream& os, short places) // #5
236 : m_places(places), m_os(&os), m_format(default_fmt)
237 {
238 start();
239 }
240
241 void auto_cpu_timer::report()
242 {
243 show_time(elapsed(), ostream(), format_string(), places());
244 }
245
246 auto_cpu_timer::~auto_cpu_timer()
247 {
248 if (!is_stopped())
249 {
250 stop(); // the sooner we stop(), the better
251 try
252 {
253 report();
254 }
255 catch (...) // eat any exceptions
256 {
257 }
258 }
259 }
260
261 } // namespace timer
262} // namespace boost