]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
92f5a8d4 | 21 | #include <boost/predef.h> |
7c673cae FG |
22 | #include <cstring> |
23 | #include <sstream> | |
24 | #include <cassert> | |
25 | ||
26 | # if defined(BOOST_WINDOWS_API) | |
27 | # include <windows.h> | |
28 | # elif defined(BOOST_POSIX_API) | |
29 | # include <unistd.h> | |
30 | # include <sys/times.h> | |
31 | # else | |
32 | # error unknown API | |
33 | # endif | |
34 | ||
35 | using boost::timer::nanosecond_type; | |
36 | using boost::timer::cpu_times; | |
37 | using boost::system::error_code; | |
38 | ||
39 | namespace | |
40 | { | |
41 | ||
42 | void show_time(const cpu_times& times, | |
43 | std::ostream& os, const std::string& fmt, short places) | |
44 | // NOTE WELL: Will truncate least-significant digits to LDBL_DIG, which may | |
45 | // be as low as 10, although will be 15 for many common platforms. | |
46 | { | |
47 | if (places > 9) | |
48 | places = 9; | |
49 | else if (places < 0) | |
50 | places = boost::timer::default_places; | |
51 | ||
52 | boost::io::ios_flags_saver ifs(os); | |
53 | boost::io::ios_precision_saver ips(os); | |
54 | os.setf(std::ios_base::fixed, std::ios_base::floatfield); | |
55 | os.precision(places); | |
56 | ||
57 | const double sec = 1000000000.0L; | |
58 | nanosecond_type total = times.system + times.user; | |
59 | double wall_sec = static_cast<double>(times.wall) / sec; | |
60 | double total_sec = static_cast<double>(total) / sec; | |
61 | ||
62 | for (const char* format = fmt.c_str(); *format; ++format) | |
63 | { | |
64 | if (*format != '%' || !*(format+1) || !std::strchr("wustp", *(format+1))) | |
65 | os << *format; // anything except % followed by a valid format character | |
66 | // gets sent to the output stream | |
67 | else | |
68 | { | |
69 | ++format; | |
70 | switch (*format) | |
71 | { | |
72 | case 'w': | |
73 | os << wall_sec; | |
74 | break; | |
75 | case 'u': | |
76 | os << static_cast<double>(times.user) / sec; | |
77 | break; | |
78 | case 's': | |
79 | os << static_cast<double>(times.system) / sec; | |
80 | break; | |
81 | case 't': | |
82 | os << total_sec; | |
83 | break; | |
84 | case 'p': | |
85 | os.precision(1); | |
86 | if (wall_sec > 0.001L && total_sec > 0.001L) | |
87 | os << (total_sec/wall_sec) * 100.0; | |
88 | else | |
89 | os << "n/a"; | |
90 | os.precision(places); | |
91 | break; | |
92 | } | |
93 | } | |
94 | } | |
95 | } | |
96 | ||
97 | # if defined(BOOST_POSIX_API) | |
98 | boost::int_least64_t tick_factor() // multiplier to convert ticks | |
99 | // to nanoseconds; -1 if unknown | |
100 | { | |
101 | static boost::int_least64_t tick_factor = 0; | |
102 | if (!tick_factor) | |
103 | { | |
104 | if ((tick_factor = ::sysconf(_SC_CLK_TCK)) <= 0) | |
105 | tick_factor = -1; | |
106 | else | |
107 | { | |
b32b8144 | 108 | tick_factor = INT64_C(1000000000) / tick_factor; // compute factor |
7c673cae FG |
109 | if (!tick_factor) |
110 | tick_factor = -1; | |
111 | } | |
112 | } | |
113 | return tick_factor; | |
114 | } | |
115 | # endif | |
116 | ||
117 | void get_cpu_times(boost::timer::cpu_times& current) | |
118 | { | |
119 | boost::chrono::duration<boost::int64_t, boost::nano> | |
120 | x (boost::chrono::high_resolution_clock::now().time_since_epoch()); | |
121 | current.wall = x.count(); | |
122 | ||
123 | # if defined(BOOST_WINDOWS_API) | |
124 | ||
92f5a8d4 | 125 | # if BOOST_PLAT_WINDOWS_DESKTOP || defined(__CYGWIN__) |
7c673cae FG |
126 | FILETIME creation, exit; |
127 | if (::GetProcessTimes(::GetCurrentProcess(), &creation, &exit, | |
128 | (LPFILETIME)¤t.system, (LPFILETIME)¤t.user)) | |
129 | { | |
130 | current.user *= 100; // Windows uses 100 nanosecond ticks | |
131 | current.system *= 100; | |
132 | } | |
133 | else | |
92f5a8d4 | 134 | # endif |
7c673cae FG |
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 == static_cast<clock_t>(-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 | ||
168 | namespace 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 | ss.exceptions(std::ios_base::badbit | std::ios_base::failbit); | |
179 | show_time(times, ss, fmt, places); | |
180 | return ss.str(); | |
181 | } | |
182 | ||
183 | BOOST_TIMER_DECL | |
184 | std::string format(const cpu_times& times, short places) | |
185 | { | |
186 | return format(times, places, default_fmt); | |
187 | } | |
188 | ||
189 | // cpu_timer ---------------------------------------------------------------------// | |
190 | ||
191 | void cpu_timer::start() BOOST_NOEXCEPT | |
192 | { | |
193 | m_is_stopped = false; | |
194 | get_cpu_times(m_times); | |
195 | } | |
196 | ||
197 | void cpu_timer::stop() BOOST_NOEXCEPT | |
198 | { | |
199 | if (is_stopped()) | |
200 | return; | |
201 | m_is_stopped = true; | |
202 | ||
203 | cpu_times current; | |
204 | get_cpu_times(current); | |
205 | m_times.wall = (current.wall - m_times.wall); | |
206 | m_times.user = (current.user - m_times.user); | |
207 | m_times.system = (current.system - m_times.system); | |
208 | } | |
209 | ||
210 | cpu_times cpu_timer::elapsed() const BOOST_NOEXCEPT | |
211 | { | |
212 | if (is_stopped()) | |
213 | return m_times; | |
214 | cpu_times current; | |
215 | get_cpu_times(current); | |
216 | current.wall -= m_times.wall; | |
217 | current.user -= m_times.user; | |
218 | current.system -= m_times.system; | |
219 | return current; | |
220 | } | |
221 | ||
222 | void cpu_timer::resume() BOOST_NOEXCEPT | |
223 | { | |
224 | if (is_stopped()) | |
225 | { | |
226 | cpu_times current (m_times); | |
227 | start(); | |
228 | m_times.wall -= current.wall; | |
229 | m_times.user -= current.user; | |
230 | m_times.system -= current.system; | |
231 | } | |
232 | } | |
233 | ||
234 | // auto_cpu_timer ----------------------------------------------------------------// | |
235 | ||
236 | auto_cpu_timer::auto_cpu_timer(std::ostream& os, short places) // #5 | |
237 | : m_places(places), m_os(&os), m_format(default_fmt) | |
238 | { | |
239 | start(); | |
240 | } | |
241 | ||
242 | void auto_cpu_timer::report() | |
243 | { | |
244 | show_time(elapsed(), ostream(), format_string(), places()); | |
245 | } | |
246 | ||
247 | auto_cpu_timer::~auto_cpu_timer() | |
248 | { | |
249 | if (!is_stopped()) | |
250 | { | |
251 | stop(); // the sooner we stop(), the better | |
b32b8144 | 252 | #ifndef BOOST_NO_EXCEPTIONS |
7c673cae FG |
253 | try |
254 | { | |
b32b8144 | 255 | #endif |
7c673cae | 256 | report(); |
b32b8144 | 257 | #ifndef BOOST_NO_EXCEPTIONS |
7c673cae FG |
258 | } |
259 | catch (...) // eat any exceptions | |
260 | { | |
261 | } | |
b32b8144 | 262 | #endif |
7c673cae FG |
263 | } |
264 | } | |
265 | ||
266 | } // namespace timer | |
267 | } // namespace boost |