aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/libs/timer/src/cpu_timer.cpp
blob: 0802e9856090095fec5176a85a412d0bb37ed6b7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
//  boost cpu_timer.cpp  ---------------------------------------------------------------//

//  Copyright Beman Dawes 1994-2006, 2011

//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/timer for documentation.

//--------------------------------------------------------------------------------------//

// define BOOST_TIMER_SOURCE so that <boost/timer/config.hpp> knows
// the library is being built (possibly exporting rather than importing code)
#define BOOST_TIMER_SOURCE

#include <boost/timer/timer.hpp>
#include <boost/chrono/chrono.hpp>
#include <boost/io/ios_state.hpp>
#include <boost/throw_exception.hpp>
#include <boost/cerrno.hpp>
#include <cstring>
#include <sstream>
#include <cassert>

# if defined(BOOST_WINDOWS_API)
#   include <windows.h>
# elif defined(BOOST_POSIX_API)
#   include <unistd.h>
#   include <sys/times.h>
# else
# error unknown API
# endif

using boost::timer::nanosecond_type;
using boost::timer::cpu_times;
using boost::system::error_code;

namespace
{

  void show_time(const cpu_times& times,
    std::ostream& os, const std::string& fmt, short places)
  //  NOTE WELL: Will truncate least-significant digits to LDBL_DIG, which may
  //  be as low as 10, although will be 15 for many common platforms.
  {
    if (places > 9)
      places = 9;
    else if (places < 0)
      places = boost::timer::default_places;
 
    boost::io::ios_flags_saver ifs(os);
    boost::io::ios_precision_saver ips(os);
    os.setf(std::ios_base::fixed, std::ios_base::floatfield);
    os.precision(places);

    const double sec = 1000000000.0L;
    nanosecond_type total = times.system + times.user;
    double wall_sec = static_cast<double>(times.wall) / sec;
    double total_sec = static_cast<double>(total) / sec;

    for (const char* format = fmt.c_str(); *format; ++format)
    {
      if (*format != '%' || !*(format+1) || !std::strchr("wustp", *(format+1)))
        os << *format;  // anything except % followed by a valid format character
                        // gets sent to the output stream
      else
      {
        ++format;
        switch (*format)
        {
        case 'w':
          os << wall_sec;
          break;
        case 'u':
          os << static_cast<double>(times.user) / sec;
          break;
        case 's':
          os << static_cast<double>(times.system) / sec;
          break;
        case 't':
          os << total_sec;
          break;
        case 'p':
          os.precision(1);
          if (wall_sec > 0.001L && total_sec > 0.001L)
            os << (total_sec/wall_sec) * 100.0;
          else
            os << "n/a";
          os.precision(places);
          break;
        }
      }
    }
  }

# if defined(BOOST_POSIX_API)
  boost::int_least64_t tick_factor() // multiplier to convert ticks
                                     //  to nanoseconds; -1 if unknown
  {
    static boost::int_least64_t tick_factor = 0;
    if (!tick_factor)
    {
      if ((tick_factor = ::sysconf(_SC_CLK_TCK)) <= 0)
        tick_factor = -1;
      else
      {
        assert(tick_factor <= INT64_C(1000000000)); // logic doesn't handle large ticks
        tick_factor = INT64_C(1000000000) / tick_factor;  // compute factor
        if (!tick_factor)
          tick_factor = -1;
      }
    }
    return tick_factor;
  }
# endif

  void get_cpu_times(boost::timer::cpu_times& current)
  {
    boost::chrono::duration<boost::int64_t, boost::nano>
      x (boost::chrono::high_resolution_clock::now().time_since_epoch());
    current.wall = x.count();

# if defined(BOOST_WINDOWS_API)

    FILETIME creation, exit;
    if (::GetProcessTimes(::GetCurrentProcess(), &creation, &exit,
            (LPFILETIME)&current.system, (LPFILETIME)&current.user))
    {
      current.user   *= 100;  // Windows uses 100 nanosecond ticks
      current.system *= 100;
    }
    else
    {
      current.system = current.user = boost::timer::nanosecond_type(-1);
    }
# else
    tms tm;
    clock_t c = ::times(&tm);
    if (c == static_cast<clock_t>(-1)) // error
    {
      current.system = current.user = boost::timer::nanosecond_type(-1);
    }
    else
    {
      current.system = boost::timer::nanosecond_type(tm.tms_stime + tm.tms_cstime);
      current.user = boost::timer::nanosecond_type(tm.tms_utime + tm.tms_cutime);
      boost::int_least64_t factor;
      if ((factor = tick_factor()) != -1)
      {
        current.user *= factor;
        current.system *= factor;
      }
      else
      {
        current.user = current.system = boost::timer::nanosecond_type(-1);
      }
    }
# endif
  }

  // CAUTION: must be identical to same constant in auto_timers_construction.cpp
  const std::string default_fmt(" %ws wall, %us user + %ss system = %ts CPU (%p%)\n");

} // unnamed namespace

namespace boost
{
  namespace timer
  {
    //  format  ------------------------------------------------------------------------//

    BOOST_TIMER_DECL
    std::string format(const cpu_times& times, short places, const std::string& fmt)
    {
      std::stringstream ss;
      ss.exceptions(std::ios_base::badbit | std::ios_base::failbit);
      show_time(times, ss, fmt, places);
      return ss.str();
    }
 
    BOOST_TIMER_DECL
    std::string format(const cpu_times& times, short places)
    {
      return format(times, places, default_fmt);
    }

    //  cpu_timer  ---------------------------------------------------------------------//

    void cpu_timer::start() BOOST_NOEXCEPT
    {
      m_is_stopped = false;
      get_cpu_times(m_times);
    }

    void cpu_timer::stop() BOOST_NOEXCEPT
    {
      if (is_stopped())
        return;
      m_is_stopped = true;
      
      cpu_times current;
      get_cpu_times(current);
      m_times.wall = (current.wall - m_times.wall);
      m_times.user = (current.user - m_times.user);
      m_times.system = (current.system - m_times.system);
    }

    cpu_times cpu_timer::elapsed() const BOOST_NOEXCEPT
    {
      if (is_stopped())
        return m_times;
      cpu_times current;
      get_cpu_times(current);
      current.wall -= m_times.wall;
      current.user -= m_times.user;
      current.system -= m_times.system;
      return current;
    }

    void cpu_timer::resume() BOOST_NOEXCEPT
    {
      if (is_stopped())
      {
        cpu_times current (m_times);
        start();
        m_times.wall   -= current.wall;
        m_times.user   -= current.user;
        m_times.system -= current.system;
      }
    }

    //  auto_cpu_timer  ----------------------------------------------------------------//

    auto_cpu_timer::auto_cpu_timer(std::ostream& os, short places)        // #5
      : m_places(places), m_os(&os), m_format(default_fmt)
    { 
      start();
    }

    void auto_cpu_timer::report()
    {
        show_time(elapsed(), ostream(), format_string(), places());
    }

    auto_cpu_timer::~auto_cpu_timer()
    { 
      if (!is_stopped())
      {
        stop();  // the sooner we stop(), the better
#ifndef BOOST_NO_EXCEPTIONS
        try
        {
#endif
          report();
#ifndef BOOST_NO_EXCEPTIONS
        }
        catch (...) // eat any exceptions
        {
        }
#endif
      }
    }

  } // namespace timer
} // namespace boost