// 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 knows // the library is being built (possibly exporting rather than importing code) #define BOOST_TIMER_SOURCE #include #include #include #include #include #include #include #include # if defined(BOOST_WINDOWS_API) # include # elif defined(BOOST_POSIX_API) # include # if !defined(__VXWORKS__) # include # endif # 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 long double sec = 1000000000.0L; nanosecond_type total = times.system + times.user; long double wall_sec = times.wall / sec; long double total_sec = 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 << times.wall / sec; break; case 'u': os << times.user / sec; break; case 's': os << 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 <= 1000000000LL); // logic doesn't handle large ticks tick_factor = 1000000000LL / 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 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)¤t.system, (LPFILETIME)¤t.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 == -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; 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() { m_is_stopped = false; get_cpu_times(m_times); } void cpu_timer::stop() { 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 { 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() { 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 try { report(); } catch (...) // eat any exceptions { } } } } // namespace timer } // namespace boost