libmoost
|
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 }