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