• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)&current.system, (LPFILETIME)&current.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