| 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 |
|
|---|
| 36 | using boost::timer::nanosecond_type;
|
|---|
| 37 | using boost::timer::cpu_times;
|
|---|
| 38 | using boost::system::error_code;
|
|---|
| 39 |
|
|---|
| 40 | namespace
|
|---|
| 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)¤t.system, (LPFILETIME)¤t.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 |
|
|---|
| 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 | 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
|
|---|