libmoost
/home/mhx/git/github/libmoost/src/timer.cpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #include "../include/moost/timer.h"
00029 #include <boost/cstdint.hpp>
00030 
00031 using boost::int64_t;
00032 using namespace moost;
00033 
00034 timer::scoped_time::scoped_time(timer & timer_)
00035 : m_timer(timer_),
00036 m_stopped(false),
00037 m_time(boost::posix_time::microsec_clock::local_time())
00038 {
00039 }
00040 
00041 timer::scoped_time::~scoped_time()
00042 {
00043    stop();
00044 }
00045 
00046 void timer::scoped_time::stop()
00047 {
00048    if (m_stopped)
00049       return;
00050    m_stopped = true;
00051    m_timer.time(m_time);
00052 }
00053 
00054 boost::posix_time::ptime timer::scoped_time::get_time() const
00055 {
00056    return m_time;
00057 }
00058 
00059 timer::timer(size_t resolution /* = 4096 */, int max_threshold_time_ms, size_t threshold_resolution)
00060 : m_max_threshold_time_ms(max_threshold_time_ms)
00061 {
00062    if (resolution <= 0)
00063       throw std::runtime_error("resolution must be > 0");
00064    m_times.resize(resolution);
00065 
00066    if ( max_threshold_time_ms < (std::numeric_limits<int>::max)() )
00067       m_threshold_times.resize(threshold_resolution);
00068 
00069    reset();
00070 }
00071 
00072 void timer::time(const boost::posix_time::ptime & start)
00073 {
00074    boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
00075    int total_ms = static_cast<int>((now - start).total_milliseconds());
00076 
00077    boost::mutex::scoped_lock lock(m_mutex);
00078 
00079    // bounds-check the pointers
00080    if (m_times_p == m_times_end)
00081    {
00082       if (m_times_end == m_times.end())
00083          m_times_p = m_times.begin();
00084       else
00085          ++m_times_end;
00086    }
00087 
00088    *m_times_p++ = total_ms;
00089 
00090    if (m_min_time == -1 || total_ms < m_min_time)
00091       m_min_time = total_ms;
00092    if (total_ms > m_max_time)
00093       m_max_time = total_ms;
00094 
00095    // keep track of the entries that pass the threshold?
00096    if ( total_ms > m_max_threshold_time_ms )
00097    {
00098       if ( m_threshold_times_p == m_threshold_times_end )
00099       {
00100          if ( m_threshold_times_end == m_threshold_times.end() )
00101             m_threshold_times_p = m_threshold_times.begin();
00102          else
00103             ++m_threshold_times_end;
00104       }
00105 
00106       *m_threshold_times_p++ = std::make_pair(total_ms, now);
00107    }
00108 
00109    ++m_count;
00110 }
00111 
00112 int timer::min_time() const
00113 {
00114    boost::mutex::scoped_lock lock(m_mutex);
00115    return m_min_time;
00116 }
00117 
00118 float timer::avg_time() const
00119 {
00120    float total = 0;
00121    boost::mutex::scoped_lock lock(m_mutex);
00122    if (m_times.begin() == m_times_end)
00123       return -1.0F;
00124    for (std::vector<int>::const_iterator it = m_times.begin(); it != m_times_end; ++it)
00125       total += *it;
00126    return total / static_cast<float>(m_times_end - m_times.begin());
00127 }
00128 
00129 void timer::avg_stddev_time( float& avg, float& std_dev ) const
00130 {
00131    avg = this->avg_time();
00132    std_dev = -1;
00133    if ( avg < 0 )
00134       return;
00135 
00136    std_dev = 0;
00137    {
00138       boost::mutex::scoped_lock lock(m_mutex);
00139       for (std::vector<int>::const_iterator it = m_times.begin(); it != m_times_end; ++it)
00140          std_dev += (*it - avg)*(*it - avg);
00141    }
00142 
00143    std_dev = sqrt( std_dev /
00144       (m_times_end - m_times.begin())
00145       );
00146 }
00147 
00148 int timer::median_time() const
00149 {
00150    boost::mutex::scoped_lock lock(m_mutex);
00151 
00152    std::vector<int> m_times_copy(m_times.begin(), std::vector<int>::const_iterator(m_times_end));
00153    std::vector<int>::iterator it_median = m_times_copy.begin() + (m_times_copy.size() / 2);
00154    std::nth_element(m_times_copy.begin(), it_median, m_times_copy.end());
00155 
00156    if (it_median == m_times_copy.end())
00157       return -1;
00158    else
00159       return *it_median;
00160 }
00161 
00162 int timer::max_time() const
00163 {
00164    boost::mutex::scoped_lock lock(m_mutex);
00165    return m_max_time;
00166 }
00167 
00168 double timer::count_per_second() const
00169 {
00170    boost::mutex::scoped_lock lock(m_mutex);
00171 
00172    boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
00173    int64_t total_ms = (now - m_start_time).total_milliseconds();
00174 
00175    if (total_ms == 0)
00176       return 0;
00177 
00178    return (m_count * 1000.0) / total_ms;
00179 }
00180 
00181 size_t timer::count() const
00182 {
00183    boost::mutex::scoped_lock lock(m_mutex);
00184    return m_count;
00185 }
00186 
00187 void timer::reset()
00188 {
00189    boost::mutex::scoped_lock lock(m_mutex);
00190 
00191    m_times_p   = m_times.begin();
00192    m_times_end = m_times.begin();
00193    m_count = 0;
00194    m_min_time = -1;
00195    m_max_time = -1;
00196 
00197    m_threshold_times_p = m_threshold_times.begin();
00198    m_threshold_times_end = m_threshold_times.begin();
00199 
00200    m_start_time = boost::posix_time::microsec_clock::local_time();
00201 }
00202 
00203 moost::timer::threshold_times_type moost::timer::past_threshold_times( int num ) const/* will return the last num entries */
00204 {
00205    threshold_times_type ret;
00206    boost::mutex::scoped_lock lock(m_mutex);
00207 
00208    if ( m_threshold_times_end == m_threshold_times.begin() )
00209       return ret;
00210 
00211    threshold_times_type::const_iterator it = m_threshold_times_p;
00212    int i = 0;
00213    --it;
00214    for ( ; it != m_threshold_times.begin() && i < num; --it, ++i )
00215       ret.push_back(*it);
00216 
00217    if ( i < num && it == m_threshold_times.begin() )
00218    {
00219       ++i;
00220       ret.push_back( *m_threshold_times.begin() );
00221    }
00222 
00223    // roll over?
00224    if ( i < num && m_threshold_times_end == m_threshold_times.end() )
00225    {
00226       it = m_threshold_times.end();
00227       --it;
00228       for ( ; it != m_threshold_times_p && i < num; --it, ++i )
00229          ret.push_back(*it);
00230       if ( i < num && it == m_threshold_times_p )
00231          ret.push_back( *it );
00232    }
00233 
00234    return ret;
00235 }
00236 
00237 // -----------------------------------------------------------------------------
00238 // -----------------------------------------------------------------------------
00239 
00240 multi_timer::reassignable_scoped_time::reassignable_scoped_time(multi_timer & mt, const std::string & name, int max_threshold_time_ms)
00241 : m_multi_timer(mt),
00242   m_stopped(false),
00243   m_time(boost::posix_time::microsec_clock::local_time()),
00244   m_max_threshold_time_ms(max_threshold_time_ms)
00245 {
00246    boost::mutex::scoped_lock lock(m_multi_timer.m_mutex);
00247    multi_timer::iterator it = m_multi_timer.m_timers.find(name);
00248 
00249    if ( it == m_multi_timer.m_timers.end() )
00250    {
00251       m_timer.reset(new timer(m_multi_timer.m_resolution, max_threshold_time_ms));
00252       m_multi_timer.m_timers[name] = m_timer;
00253    }
00254    else
00255       m_timer = it->second;
00256 }
00257 
00258 multi_timer::reassignable_scoped_time::~reassignable_scoped_time()
00259 {
00260    stop();
00261 }
00262 
00263 void multi_timer::reassignable_scoped_time::stop()
00264 {
00265    if (m_stopped)
00266       return;
00267    m_stopped = true;
00268 
00269    boost::mutex::scoped_lock lock(m_reassign_mutex);
00270    if ( m_timer )
00271       m_timer->time(m_time);
00272 }
00273 
00274 void multi_timer::reassignable_scoped_time::reassign(const std::string& name)
00275 {
00276    boost::mutex::scoped_lock lock(m_multi_timer.m_mutex);
00277    multi_timer::iterator it = m_multi_timer.m_timers.find(name);
00278    if ( it == m_multi_timer.m_timers.end() )
00279    {
00280       boost::mutex::scoped_lock lock(m_reassign_mutex);
00281       m_timer.reset(new timer(m_multi_timer.m_resolution, m_max_threshold_time_ms));
00282       m_multi_timer.m_timers[name] = m_timer;
00283    }
00284    else
00285    {
00286       boost::mutex::scoped_lock lock(m_reassign_mutex);
00287       m_timer = it->second;
00288    }
00289 }
00290 
00291 void multi_timer::reassignable_scoped_time::discard()
00292 {
00293    boost::mutex::scoped_lock lock(m_reassign_mutex);
00294    m_timer.reset();
00295 }
00296 
00297 boost::posix_time::ptime multi_timer::reassignable_scoped_time::get_time() const
00298 {
00299    return m_time;
00300 }