rvm 1.08
|
00001 #include "config.h" 00002 00003 #ifdef HAVE_UNISTD_H 00004 #include <unistd.h> 00005 #endif 00006 00007 #include <iostream> 00008 #include <iomanip> 00009 #include <string> 00010 // #include <sstream> 00011 00012 #include <time.h> 00013 #include <sys/types.h> 00014 00015 #include "types.h" 00016 #include "error.h" 00017 #include "fs.h" 00018 #include "estring.h" 00019 #include "strfmt.h" 00020 #include "rmath.h" 00021 00022 #include "timer.h" 00023 00024 /** Given a timer value, return a string in the form of "YYYY.MM.DD HH:MM:SS" 00025 */ 00026 const std::string make_time_string_(timer::value_type a_t) 00027 { 00028 std::string es; 00029 struct tm* l = 0; 00030 estring tmp_str; 00031 std::string str; 00032 00033 l = localtime(&a_t); 00034 if (l == 0) { 00035 TRY_nomem(es = "Could not convert time_t to localtime: \""); 00036 TRY_nomem(es += estring(a_t)); 00037 TRY_nomem(es += "\""); 00038 throw(ERROR(errno,es)); 00039 } 00040 00041 TRY(str += estring(l->tm_year + 1900).fmt_str(4,estring::right,'0','x'), 00042 "Error generating string from year"); 00043 00044 TRY_nomem(str += "."); 00045 00046 TRY(str += estring(l->tm_mon + 1).fmt_str(2,estring::right,'0','x'), 00047 "Error generating string from month"); 00048 00049 TRY_nomem(str += "."); 00050 00051 TRY(str += estring(l->tm_mday).fmt_str(2,estring::right,'0','x'), 00052 "Error generating string from day"); 00053 00054 TRY_nomem(str += " "); 00055 00056 TRY(str += estring(l->tm_hour).fmt_str(2,estring::right,'0','x'), 00057 "Error generating string from hour"); 00058 00059 TRY_nomem(str += ":"); 00060 00061 TRY(str += estring(l->tm_min).fmt_str(2,estring::right,'0','x'), 00062 "Error generating string from minute"); 00063 00064 TRY_nomem(str += ":"); 00065 00066 TRY(str += estring(l->tm_sec).fmt_str(2,estring::right,'0','x'), 00067 "Error generating string from seconds"); 00068 00069 return(str); 00070 } 00071 00072 /** C'tor */ 00073 timer::timer() 00074 { 00075 clear(); 00076 start(); 00077 } 00078 00079 /** C'tor */ 00080 timer::timer(const timer& a_timer) 00081 { 00082 assign(a_timer); 00083 } 00084 00085 /** C'tor */ 00086 timer::timer(const value_type a_start) 00087 { 00088 assign(a_start); 00089 } 00090 00091 /** C'tor */ 00092 timer::timer(const value_type a_start, const value_type a_stop) 00093 { 00094 assign(a_start,a_stop); 00095 } 00096 00097 /** Clear the timer */ 00098 void timer::clear(void) 00099 { 00100 m_start = 0; 00101 m_stop = 0; 00102 m_started = false; 00103 m_stopped = false; 00104 m_duration = 0; 00105 m_use_localtime = true; 00106 } 00107 00108 /** Set the timer start value */ 00109 void timer::mf_start_value(const timer::value_type a_t) 00110 { 00111 m_start = a_t; 00112 m_started = true; 00113 } 00114 00115 /** Set the timer stop value */ 00116 void timer::mf_stop_value(const timer::value_type a_t) 00117 { 00118 m_stop = a_t; 00119 m_stopped = true; 00120 } 00121 00122 /** Calculate the duration between start and stop */ 00123 const timer::duration_type 00124 timer::mf_calculate_duration( 00125 const timer::value_type a_start, 00126 const timer::value_type a_stop 00127 ) const 00128 { 00129 duration_type duration; 00130 00131 duration = difftime(a_stop,a_start); 00132 00133 return(duration); 00134 } 00135 00136 /** Start (or restart) the timer */ 00137 void timer::start(void) 00138 { 00139 mf_start_value(time(0)); 00140 } 00141 00142 /** Stop the timer */ 00143 void timer::stop(void) 00144 { 00145 mf_stop_value(time(0)); 00146 m_duration = mf_calculate_duration(m_start,m_stop); 00147 } 00148 00149 /** Return the timer start value */ 00150 const timer::value_type timer::start_value(void) const 00151 { 00152 return(m_start); 00153 } 00154 00155 /** Return the timer stop value */ 00156 const timer::value_type timer::stop_value(void) const 00157 { 00158 return(m_stop); 00159 } 00160 00161 /** Assign timer values from another timer instance */ 00162 void timer::assign(const timer& a_timer) 00163 { 00164 clear(); 00165 mf_start_value(a_timer.start_value()); 00166 mf_stop_value(a_timer.stop_value()); 00167 m_started = a_timer.is_started(); 00168 m_stopped = a_timer.is_stopped(); 00169 if (m_stopped) 00170 m_duration = mf_calculate_duration(m_start,m_stop); 00171 } 00172 00173 /** Assign timer from a start value */ 00174 void timer::assign(const timer::value_type a_start) 00175 { 00176 clear(); 00177 mf_start_value(a_start); 00178 } 00179 00180 /** Assign timer from start and stop values */ 00181 void timer::assign( 00182 const timer::value_type a_start, 00183 const timer::value_type a_stop) 00184 { 00185 clear(); 00186 mf_start_value(a_start); 00187 mf_stop_value(a_stop); 00188 m_duration = mf_calculate_duration(m_start,m_stop); 00189 } 00190 00191 /** Assignment */ 00192 timer& timer::operator=(const timer& a_timer) 00193 { 00194 assign(a_timer); 00195 00196 return(*this); 00197 } 00198 00199 /** Set whether to use localtime or GMT when constructing strings */ 00200 void timer::use_localtime(const bool a_switch) 00201 { 00202 m_use_localtime = a_switch; 00203 } 00204 00205 /** Return whether to use localtime or GMT */ 00206 const bool timer::use_localtime(void) const 00207 { 00208 return(m_use_localtime); 00209 } 00210 00211 /** Generate a string in a regular human-readable format */ 00212 const std::string timer::mf_make_timer_string(const value_type a_t) const 00213 { 00214 std::string es; 00215 struct tm* l = 0; 00216 std::string str; 00217 const char* month_names[] = { 00218 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 00219 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 00220 }; 00221 00222 if (m_use_localtime) { 00223 l = localtime(&a_t); 00224 if (l == 0) { 00225 TRY_nomem(es = "Could not convert time_t to localtime: \""); 00226 TRY_nomem(es += estring(a_t)); 00227 TRY_nomem(es += "\""); 00228 throw(ERROR(errno,es)); 00229 } 00230 } 00231 else { 00232 l = gmtime(&a_t); 00233 if (l == 0) { 00234 TRY_nomem(es = "Could not convert time_t to GMT: \""); 00235 TRY_nomem(es += estring(a_t)); 00236 TRY_nomem(es += "\""); 00237 throw(ERROR(errno,es)); 00238 } 00239 } 00240 00241 TRY(str += estring(l->tm_year + 1900).fmt_str(4,estring::right,'0','x'), 00242 "Error generating string from year"); 00243 00244 TRY_nomem(str += " "); 00245 00246 TRY(str += estring(month_names[l->tm_mon]).fmt_str(3,estring::right,' ','x'), 00247 "Error generating string from month"); 00248 00249 TRY_nomem(str += " "); 00250 00251 TRY(str += estring(l->tm_mday).fmt_str(2,estring::right,' ','x'), 00252 "Error generating string from day"); 00253 00254 TRY_nomem(str += " "); 00255 00256 TRY(str += estring(l->tm_hour).fmt_str(2,estring::right,'0','x'), 00257 "Error generating string from hour"); 00258 00259 TRY_nomem(str += ":"); 00260 00261 TRY(str += estring(l->tm_min).fmt_str(2,estring::right,'0','x'), 00262 "Error generating string from minute"); 00263 00264 TRY_nomem(str += ":"); 00265 00266 TRY(str += estring(l->tm_sec).fmt_str(2,estring::right,'0','x'), 00267 "Error generating string from seconds"); 00268 00269 return(str); 00270 } 00271 00272 /** Generate a string in a timestamp format */ 00273 const std::string timer::mf_make_string(const timer::value_type a_t) const 00274 { 00275 std::string str; 00276 00277 TRY_nomem(str = mf_make_timer_string(a_t)); 00278 00279 return(str); 00280 } 00281 00282 /** Generate a duration string */ 00283 const std::string timer::mf_make_string(const timer::duration_type a_d) const 00284 { 00285 uint64 deciseconds = 0; 00286 uint64 seconds = 0; 00287 uint64 minutes = 0; 00288 uint64 hours = 0; 00289 uint64 days = 0; 00290 uint64 years = 0; 00291 std::string str; 00292 bool negative = false; 00293 00294 if (a_d < 0) { 00295 negative = true; 00296 deciseconds = static_cast<uint64>(-a_d * 10.0); 00297 } 00298 else 00299 deciseconds = static_cast<uint64>(a_d * 10.0); 00300 00301 if (deciseconds >= 10) { 00302 seconds = deciseconds / 10; 00303 deciseconds %= 10; 00304 } 00305 if (seconds >= 60) { 00306 minutes = seconds / 60; 00307 seconds %= 60; 00308 } 00309 if (minutes >= 60) { 00310 hours = minutes / 60; 00311 minutes %= 60; 00312 } 00313 if (hours >= 24) { 00314 days = hours / 24; 00315 hours %= 24; 00316 } 00317 if (days >= 365) { 00318 years = days / 365; 00319 days %= 365; 00320 } 00321 00322 if (negative) { 00323 TRY_nomem(str += "-"); 00324 } 00325 00326 if (years > 0) { 00327 TRY_nomem(str += estring(years)); 00328 TRY_nomem(str += "y "); 00329 } 00330 00331 if ((years > 0) || (days > 0)) { 00332 TRY_nomem(str += estring(days)); 00333 TRY_nomem(str += "d "); 00334 } 00335 00336 if ((years > 0) || (days > 0) || (hours > 0)) { 00337 TRY(str += estring(hours).fmt_str(2,estring::right,'0','x'), 00338 "Error generating string from hours"); 00339 TRY_nomem(str += ":"); 00340 } 00341 00342 TRY(str += estring(minutes).fmt_str(2,estring::right,'0','x'), 00343 "Error generating string from minutes"); 00344 00345 TRY_nomem(str += ":"); 00346 00347 TRY(str += estring(seconds).fmt_str(2,estring::right,'0','x'), 00348 "Error generating string from seconds"); 00349 00350 TRY_nomem(str += "."); 00351 00352 TRY(str += estring(deciseconds).fmt_str(1,estring::right,'0','x'), 00353 "Error generating string from deciseconds"); 00354 00355 return(str); 00356 } 00357 00358 /** Generate a started-at string */ 00359 const std::string timer::started_at(void) const 00360 { 00361 std::string str; 00362 00363 if (!is_started()) 00364 throw(INTERNAL_ERROR(0,"Request for start time from an unstarted timer")); 00365 TRY_nomem(str = mf_make_string(m_start)); 00366 00367 return(str); 00368 } 00369 00370 /** Generate a stopped-at string */ 00371 const std::string timer::stopped_at(void) const 00372 { 00373 std::string str; 00374 00375 if (!is_started()) 00376 throw(INTERNAL_ERROR(0,"Request for stop time from an unstarted timer")); 00377 if (!is_stopped()) 00378 throw(INTERNAL_ERROR(0,"Request for stop time from a running timer")); 00379 TRY_nomem(str = mf_make_string(m_stop)); 00380 00381 return(str); 00382 } 00383 00384 /** Generate a duration string */ 00385 const std::string timer::duration(void) const 00386 { 00387 std::string str; 00388 00389 if (!is_started()) 00390 throw(INTERNAL_ERROR(0,"Request for stop time from an unstarted timer")); 00391 if (!is_stopped()) 00392 throw(INTERNAL_ERROR(0,"Request for duration from a running timer")); 00393 TRY_nomem(str = mf_make_string(m_duration)); 00394 00395 return(str); 00396 } 00397 00398 /** Return whether or not the timer has been started */ 00399 const bool timer::is_started(void) const 00400 { 00401 return(m_started); 00402 } 00403 00404 /** Return whether or not the timer has been stopped */ 00405 const bool timer::is_stopped(void) const 00406 { 00407 return(m_stopped); 00408 } 00409 00410 /** Reutrn the duration in seconds */ 00411 const timer::duration_type timer::duration_secs(void) const 00412 { 00413 if (!is_started()) 00414 throw(INTERNAL_ERROR(0,"Request for duration from an unstarted timer")); 00415 if (!is_stopped()) 00416 throw(INTERNAL_ERROR(0,"Request for duration from a running timer")); 00417 00418 return(m_duration); 00419 } 00420 00421 /** Return the duration in minutes */ 00422 const timer::duration_type timer::duration_mins(void) const 00423 { 00424 duration_type value; 00425 00426 value = duration_secs()/static_cast<duration_type>(60.0); 00427 00428 return(value); 00429 } 00430 00431 /** Return the duration in hours */ 00432 const timer::duration_type timer::duration_hours(void) const 00433 { 00434 duration_type value; 00435 00436 value = duration_mins()/static_cast<duration_type>(60.0); 00437 00438 return(value); 00439 } 00440 00441 /** Return the duration in days */ 00442 const timer::duration_type timer::duration_days(void) const 00443 { 00444 duration_type value; 00445 00446 value = duration_hours()/static_cast<duration_type>(24.0); 00447 00448 return(value); 00449 } 00450 00451 /** Return the duration in years */ 00452 const timer::duration_type timer::duration_years(void) const 00453 { 00454 duration_type value; 00455 00456 value = duration_days()/static_cast<duration_type>(365.0); 00457 00458 return(value); 00459 } 00460 00461 /** Given a percent-complete for some unknown task, estimate a time to 00462 completion */ 00463 const std::string timer::eta(unsigned int a_percent_complete) const 00464 { 00465 safe_num<duration_type> total_duration; 00466 safe_num<duration_type> eta; 00467 std::string es; 00468 std::string str; 00469 00470 if (!is_started()) 00471 throw(INTERNAL_ERROR(0,"Attempt to calculate ETA for unstarted timer")); 00472 if (!is_stopped()) 00473 throw(INTERNAL_ERROR(0,"Attempt to calculate ETA for a running timer")); 00474 if (a_percent_complete == 0) { 00475 TRY_nomem(str = "??:??.?"); 00476 return(str); 00477 } 00478 00479 TRY_nomem(es = "Could not calculate ETA"); 00480 TRY( 00481 total_duration = m_duration; 00482 total_duration *= 100; 00483 total_duration /= a_percent_complete; 00484 eta = total_duration - safe_num<duration_type>(m_duration); 00485 ,es); 00486 TRY_nomem(str = mf_make_string(eta.value())); 00487 00488 return(str); 00489 } 00490 00491 /** Given a step number complete out of some total number of steps for some 00492 unknown task, estimate a time to completion */ 00493 const std::string timer::eta( 00494 unsigned int a_complete, unsigned int a_total) const 00495 { 00496 safe_num<unsigned int> percent_complete; 00497 std::string es; 00498 std::string str; 00499 00500 if (!is_started()) 00501 throw(INTERNAL_ERROR(0,"Attempt to calculate ETA for unstarted timer")); 00502 if (!is_stopped()) 00503 throw(INTERNAL_ERROR(0,"Attempt to calculate ETA for a running timer")); 00504 if (a_total == 0) { 00505 TRY_nomem(str = "??:??.?"); 00506 return(str); 00507 } 00508 00509 TRY_nomem(es = "Could not calculate ETA"); 00510 TRY( 00511 percent_complete = a_complete; 00512 percent_complete *= 100; 00513 percent_complete /= a_total; 00514 ,es); 00515 00516 TRY_nomem(str = eta(percent_complete.value())); 00517 00518 return(str); 00519 } 00520 00521 /** Given a number of bytes, estimate the BPS */ 00522 const std::string timer::bps(uint64 a_bytes) const 00523 { 00524 uint64 bps; 00525 std::string str; 00526 00527 if (!is_started()) 00528 throw(INTERNAL_ERROR(0,"Attempt to calculate bps for unstarted timer")); 00529 if (!is_stopped()) 00530 throw(INTERNAL_ERROR(0,"Attempt to calculate bps for a running timer")); 00531 00532 if (m_duration == 0) 00533 bps = a_bytes; 00534 else 00535 bps = static_cast<uint64>(a_bytes / m_duration); 00536 TRY_nomem(str = throughput_to_string(bps)); 00537 00538 return(str); 00539 } 00540 00541 /** Return the current time */ 00542 const std::string current_time(void) 00543 { 00544 std::string str; 00545 00546 TRY_nomem(str = make_time_string_(time(0))); 00547 00548 return(str); 00549 } 00550 00551 /** Generate a timstamp string */ 00552 std::string stamp(const pid_t a_pid, const int a_indention) 00553 { 00554 std::string str; 00555 int indent; 00556 pid_t this_pid; 00557 00558 indent = a_indention; 00559 TRY_nomem(str = current_time()); 00560 TRY_nomem(str += " ["); 00561 if (a_pid == 0) 00562 this_pid = pid(); 00563 else 00564 this_pid = a_pid; 00565 00566 /* 00567 * pid_t has to be static_cast because some compilers wind up calling 00568 * estring(const long& ...) instead of estring(const unsigned long& ...), 00569 * and then the value in estring can wind up being misinterpreted as a 00570 * negative number. 00571 * 00572 * 4 digits is just a guess. I've never seen a PID over four digits. Is 00573 * there an easy, portable way to determine how many digits pid_t could wind 00574 * up being? If gcc 2.95.x had numeric_limits<> then it would be... 00575 */ 00576 TRY_nomem(str += 00577 estring(static_cast<unsigned long>(this_pid)).fmt_str( 00578 6,estring::right,' ',' ' 00579 ) 00580 ); 00581 00582 TRY_nomem(str += "]"); 00583 TRY_nomem(str += "> "); 00584 for (; indent > 0; str += " ", --indent); 00585 00586 return(str); 00587 } 00588