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 <boost/predef.h> 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 38 namespace 39 { 40 show_time(const cpu_times & times,std::ostream & os,const std::string & fmt,short places)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) tick_factor()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 tick_factor = INT64_C(1000000000) / tick_factor; // compute factor 108 if (!tick_factor) 109 tick_factor = -1; 110 } 111 } 112 return tick_factor; 113 } 114 # endif 115 get_cpu_times(boost::timer::cpu_times & current)116 void get_cpu_times(boost::timer::cpu_times& current) 117 { 118 boost::chrono::duration<boost::int64_t, boost::nano> 119 x (boost::chrono::high_resolution_clock::now().time_since_epoch()); 120 current.wall = x.count(); 121 122 # if defined(BOOST_WINDOWS_API) 123 124 # if BOOST_PLAT_WINDOWS_DESKTOP || defined(__CYGWIN__) 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 # endif 134 { 135 current.system = current.user = boost::timer::nanosecond_type(-1); 136 } 137 # else 138 tms tm; 139 clock_t c = ::times(&tm); 140 if (c == static_cast<clock_t>(-1)) // error 141 { 142 current.system = current.user = boost::timer::nanosecond_type(-1); 143 } 144 else 145 { 146 current.system = boost::timer::nanosecond_type(tm.tms_stime + tm.tms_cstime); 147 current.user = boost::timer::nanosecond_type(tm.tms_utime + tm.tms_cutime); 148 boost::int_least64_t factor; 149 if ((factor = tick_factor()) != -1) 150 { 151 current.user *= factor; 152 current.system *= factor; 153 } 154 else 155 { 156 current.user = current.system = boost::timer::nanosecond_type(-1); 157 } 158 } 159 # endif 160 } 161 162 // CAUTION: must be identical to same constant in auto_timers_construction.cpp 163 const std::string default_fmt(" %ws wall, %us user + %ss system = %ts CPU (%p%)\n"); 164 165 } // unnamed namespace 166 167 namespace boost 168 { 169 namespace timer 170 { 171 // format ------------------------------------------------------------------------// 172 173 BOOST_TIMER_DECL format(const cpu_times & times,short places,const std::string & fmt)174 std::string format(const cpu_times& times, short places, const std::string& fmt) 175 { 176 std::stringstream ss; 177 ss.exceptions(std::ios_base::badbit | std::ios_base::failbit); 178 show_time(times, ss, fmt, places); 179 return ss.str(); 180 } 181 182 BOOST_TIMER_DECL format(const cpu_times & times,short places)183 std::string format(const cpu_times& times, short places) 184 { 185 return format(times, places, default_fmt); 186 } 187 188 // cpu_timer ---------------------------------------------------------------------// 189 start()190 void cpu_timer::start() BOOST_NOEXCEPT 191 { 192 m_is_stopped = false; 193 get_cpu_times(m_times); 194 } 195 stop()196 void cpu_timer::stop() BOOST_NOEXCEPT 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 elapsed() const209 cpu_times cpu_timer::elapsed() const BOOST_NOEXCEPT 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 resume()221 void cpu_timer::resume() BOOST_NOEXCEPT 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 auto_cpu_timer(std::ostream & os,short places)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 report()241 void auto_cpu_timer::report() 242 { 243 show_time(elapsed(), ostream(), format_string(), places()); 244 } 245 ~auto_cpu_timer()246 auto_cpu_timer::~auto_cpu_timer() 247 { 248 if (!is_stopped()) 249 { 250 stop(); // the sooner we stop(), the better 251 #ifndef BOOST_NO_EXCEPTIONS 252 try 253 { 254 #endif 255 report(); 256 #ifndef BOOST_NO_EXCEPTIONS 257 } 258 catch (...) // eat any exceptions 259 { 260 } 261 #endif 262 } 263 } 264 265 } // namespace timer 266 } // namespace boost 267