rvm 1.08

timer.cc

Go to the documentation of this file.
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 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines