rvm  1.11
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
timer.cc
Go to the documentation of this file.
1 #include "config.h"
2 
3 #ifdef HAVE_UNISTD_H
4 #include <unistd.h>
5 #endif
6 
7 #include <iostream>
8 #include <iomanip>
9 #include <string>
10 // #include <sstream>
11 
12 #include <time.h>
13 #include <sys/types.h>
14 
15 #include "types.h"
16 #include "error.h"
17 #include "fs.h"
18 #include "estring.h"
19 #include "strfmt.h"
20 #include "rmath.h"
21 
22 #include "timer.h"
23 
24 /** Given a timer value, return a string in the form of "YYYY.MM.DD HH:MM:SS"
25  */
26 const std::string make_time_string_(timer::value_type a_t)
27 {
28  std::string es;
29  struct tm* l = 0;
30  estring tmp_str;
31  std::string str;
32 
33  l = localtime(&a_t);
34  if (l == 0) {
35  TRY_nomem(es = "Could not convert time_t to localtime: \"");
36  TRY_nomem(es += estring(a_t));
37  TRY_nomem(es += "\"");
38  throw(ERROR(errno,es));
39  }
40 
41  TRY(str += estring(l->tm_year + 1900).fmt_str(4,estring::right,'0','x'),
42  "Error generating string from year");
43 
44  TRY_nomem(str += ".");
45 
46  TRY(str += estring(l->tm_mon + 1).fmt_str(2,estring::right,'0','x'),
47  "Error generating string from month");
48 
49  TRY_nomem(str += ".");
50 
51  TRY(str += estring(l->tm_mday).fmt_str(2,estring::right,'0','x'),
52  "Error generating string from day");
53 
54  TRY_nomem(str += " ");
55 
56  TRY(str += estring(l->tm_hour).fmt_str(2,estring::right,'0','x'),
57  "Error generating string from hour");
58 
59  TRY_nomem(str += ":");
60 
61  TRY(str += estring(l->tm_min).fmt_str(2,estring::right,'0','x'),
62  "Error generating string from minute");
63 
64  TRY_nomem(str += ":");
65 
66  TRY(str += estring(l->tm_sec).fmt_str(2,estring::right,'0','x'),
67  "Error generating string from seconds");
68 
69  return(str);
70 }
71 
72 /** C'tor */
74 {
75  clear();
76  start();
77 }
78 
79 /** C'tor */
80 timer::timer(const timer& a_timer)
81 {
82  assign(a_timer);
83 }
84 
85 /** C'tor */
86 timer::timer(const value_type a_start)
87 {
88  assign(a_start);
89 }
90 
91 /** C'tor */
92 timer::timer(const value_type a_start, const value_type a_stop)
93 {
94  assign(a_start,a_stop);
95 }
96 
97 /** Clear the timer */
98 void timer::clear(void)
99 {
100  m_start = 0;
101  m_stop = 0;
102  m_started = false;
103  m_stopped = false;
104  m_duration = 0;
105  m_use_localtime = true;
106 }
107 
108 /** Set the timer start value */
110 {
111  m_start = a_t;
112  m_started = true;
113 }
114 
115 /** Set the timer stop value */
117 {
118  m_stop = a_t;
119  m_stopped = true;
120 }
121 
122 /** Calculate the duration between start and stop */
125  const timer::value_type a_start,
126  const timer::value_type a_stop
127  ) const
128 {
130 
131  duration = difftime(a_stop,a_start);
132 
133  return(duration);
134 }
135 
136 /** Start (or restart) the timer */
137 void timer::start(void)
138 {
139  mf_start_value(time(0));
140 }
141 
142 /** Stop the timer */
143 void timer::stop(void)
144 {
145  mf_stop_value(time(0));
147 }
148 
149 /** Return the timer start value */
151 {
152  return(m_start);
153 }
154 
155 /** Return the timer stop value */
157 {
158  return(m_stop);
159 }
160 
161 /** Assign timer values from another timer instance */
162 void timer::assign(const timer& a_timer)
163 {
164  clear();
165  mf_start_value(a_timer.start_value());
166  mf_stop_value(a_timer.stop_value());
167  m_started = a_timer.is_started();
168  m_stopped = a_timer.is_stopped();
169  if (m_stopped)
171 }
172 
173 /** Assign timer from a start value */
174 void timer::assign(const timer::value_type a_start)
175 {
176  clear();
177  mf_start_value(a_start);
178 }
179 
180 /** Assign timer from start and stop values */
182  const timer::value_type a_start,
183  const timer::value_type a_stop)
184 {
185  clear();
186  mf_start_value(a_start);
187  mf_stop_value(a_stop);
189 }
190 
191 /** Assignment */
192 timer& timer::operator=(const timer& a_timer)
193 {
194  assign(a_timer);
195 
196  return(*this);
197 }
198 
199 /** Set whether to use localtime or GMT when constructing strings */
200 void timer::use_localtime(const bool a_switch)
201 {
202  m_use_localtime = a_switch;
203 }
204 
205 /** Return whether to use localtime or GMT */
206 const bool timer::use_localtime(void) const
207 {
208  return(m_use_localtime);
209 }
210 
211 /** Generate a string in a regular human-readable format */
212 const std::string timer::mf_make_timer_string(const value_type a_t) const
213 {
214  std::string es;
215  struct tm* l = 0;
216  std::string str;
217  const char* month_names[] = {
218  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
219  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
220  };
221 
222  if (m_use_localtime) {
223  l = localtime(&a_t);
224  if (l == 0) {
225  TRY_nomem(es = "Could not convert time_t to localtime: \"");
226  TRY_nomem(es += estring(a_t));
227  TRY_nomem(es += "\"");
228  throw(ERROR(errno,es));
229  }
230  }
231  else {
232  l = gmtime(&a_t);
233  if (l == 0) {
234  TRY_nomem(es = "Could not convert time_t to GMT: \"");
235  TRY_nomem(es += estring(a_t));
236  TRY_nomem(es += "\"");
237  throw(ERROR(errno,es));
238  }
239  }
240 
241  TRY(str += estring(l->tm_year + 1900).fmt_str(4,estring::right,'0','x'),
242  "Error generating string from year");
243 
244  TRY_nomem(str += " ");
245 
246  TRY(str += estring(month_names[l->tm_mon]).fmt_str(3,estring::right,' ','x'),
247  "Error generating string from month");
248 
249  TRY_nomem(str += " ");
250 
251  TRY(str += estring(l->tm_mday).fmt_str(2,estring::right,' ','x'),
252  "Error generating string from day");
253 
254  TRY_nomem(str += " ");
255 
256  TRY(str += estring(l->tm_hour).fmt_str(2,estring::right,'0','x'),
257  "Error generating string from hour");
258 
259  TRY_nomem(str += ":");
260 
261  TRY(str += estring(l->tm_min).fmt_str(2,estring::right,'0','x'),
262  "Error generating string from minute");
263 
264  TRY_nomem(str += ":");
265 
266  TRY(str += estring(l->tm_sec).fmt_str(2,estring::right,'0','x'),
267  "Error generating string from seconds");
268 
269  return(str);
270 }
271 
272 /** Generate a string in a timestamp format */
273 const std::string timer::mf_make_string(const timer::value_type a_t) const
274 {
275  std::string str;
276 
277  TRY_nomem(str = mf_make_timer_string(a_t));
278 
279  return(str);
280 }
281 
282 /** Generate a duration string */
283 const std::string timer::mf_make_string(const timer::duration_type a_d) const
284 {
285  uint64 deciseconds = 0;
286  uint64 seconds = 0;
287  uint64 minutes = 0;
288  uint64 hours = 0;
289  uint64 days = 0;
290  uint64 years = 0;
291  std::string str;
292  bool negative = false;
293 
294  if (a_d < 0) {
295  negative = true;
296  deciseconds = static_cast<uint64>(-a_d * 10.0);
297  }
298  else
299  deciseconds = static_cast<uint64>(a_d * 10.0);
300 
301  if (deciseconds >= 10) {
302  seconds = deciseconds / 10;
303  deciseconds %= 10;
304  }
305  if (seconds >= 60) {
306  minutes = seconds / 60;
307  seconds %= 60;
308  }
309  if (minutes >= 60) {
310  hours = minutes / 60;
311  minutes %= 60;
312  }
313  if (hours >= 24) {
314  days = hours / 24;
315  hours %= 24;
316  }
317  if (days >= 365) {
318  years = days / 365;
319  days %= 365;
320  }
321 
322  if (negative) {
323  TRY_nomem(str += "-");
324  }
325 
326  if (years > 0) {
327  TRY_nomem(str += estring(years));
328  TRY_nomem(str += "y ");
329  }
330 
331  if ((years > 0) || (days > 0)) {
332  TRY_nomem(str += estring(days));
333  TRY_nomem(str += "d ");
334  }
335 
336  if ((years > 0) || (days > 0) || (hours > 0)) {
337  TRY(str += estring(hours).fmt_str(2,estring::right,'0','x'),
338  "Error generating string from hours");
339  TRY_nomem(str += ":");
340  }
341 
342  TRY(str += estring(minutes).fmt_str(2,estring::right,'0','x'),
343  "Error generating string from minutes");
344 
345  TRY_nomem(str += ":");
346 
347  TRY(str += estring(seconds).fmt_str(2,estring::right,'0','x'),
348  "Error generating string from seconds");
349 
350  TRY_nomem(str += ".");
351 
352  TRY(str += estring(deciseconds).fmt_str(1,estring::right,'0','x'),
353  "Error generating string from deciseconds");
354 
355  return(str);
356 }
357 
358 /** Generate a started-at string */
359 const std::string timer::started_at(void) const
360 {
361  std::string str;
362 
363  if (!is_started())
364  throw(INTERNAL_ERROR(0,"Request for start time from an unstarted timer"));
366 
367  return(str);
368 }
369 
370 /** Generate a stopped-at string */
371 const std::string timer::stopped_at(void) const
372 {
373  std::string str;
374 
375  if (!is_started())
376  throw(INTERNAL_ERROR(0,"Request for stop time from an unstarted timer"));
377  if (!is_stopped())
378  throw(INTERNAL_ERROR(0,"Request for stop time from a running timer"));
380 
381  return(str);
382 }
383 
384 /** Generate a duration string */
385 const std::string timer::duration(void) const
386 {
387  std::string str;
388 
389  if (!is_started())
390  throw(INTERNAL_ERROR(0,"Request for stop time from an unstarted timer"));
391  if (!is_stopped())
392  throw(INTERNAL_ERROR(0,"Request for duration from a running timer"));
394 
395  return(str);
396 }
397 
398 /** Return whether or not the timer has been started */
399 const bool timer::is_started(void) const
400 {
401  return(m_started);
402 }
403 
404 /** Return whether or not the timer has been stopped */
405 const bool timer::is_stopped(void) const
406 {
407  return(m_stopped);
408 }
409 
410 /** Reutrn the duration in seconds */
412 {
413  if (!is_started())
414  throw(INTERNAL_ERROR(0,"Request for duration from an unstarted timer"));
415  if (!is_stopped())
416  throw(INTERNAL_ERROR(0,"Request for duration from a running timer"));
417 
418  return(m_duration);
419 }
420 
421 /** Return the duration in minutes */
423 {
424  duration_type value;
425 
426  value = duration_secs()/static_cast<duration_type>(60.0);
427 
428  return(value);
429 }
430 
431 /** Return the duration in hours */
433 {
434  duration_type value;
435 
436  value = duration_mins()/static_cast<duration_type>(60.0);
437 
438  return(value);
439 }
440 
441 /** Return the duration in days */
443 {
444  duration_type value;
445 
446  value = duration_hours()/static_cast<duration_type>(24.0);
447 
448  return(value);
449 }
450 
451 /** Return the duration in years */
453 {
454  duration_type value;
455 
456  value = duration_days()/static_cast<duration_type>(365.0);
457 
458  return(value);
459 }
460 
461 /** Given a percent-complete for some unknown task, estimate a time to
462  completion */
463 const std::string timer::eta(unsigned int a_percent_complete) const
464 {
465  safe_num<duration_type> total_duration;
467  std::string es;
468  std::string str;
469 
470  if (!is_started())
471  throw(INTERNAL_ERROR(0,"Attempt to calculate ETA for unstarted timer"));
472  if (!is_stopped())
473  throw(INTERNAL_ERROR(0,"Attempt to calculate ETA for a running timer"));
474  if (a_percent_complete == 0) {
475  TRY_nomem(str = "??:??.?");
476  return(str);
477  }
478 
479  TRY_nomem(es = "Could not calculate ETA");
480  TRY(
481  total_duration = m_duration;
482  total_duration *= 100;
483  total_duration /= a_percent_complete;
484  eta = total_duration - safe_num<duration_type>(m_duration);
485  ,es);
486  TRY_nomem(str = mf_make_string(eta.value()));
487 
488  return(str);
489 }
490 
491 /** Given a step number complete out of some total number of steps for some
492  unknown task, estimate a time to completion */
493 const std::string timer::eta(
494  unsigned int a_complete, unsigned int a_total) const
495 {
496  safe_num<unsigned int> percent_complete;
497  std::string es;
498  std::string str;
499 
500  if (!is_started())
501  throw(INTERNAL_ERROR(0,"Attempt to calculate ETA for unstarted timer"));
502  if (!is_stopped())
503  throw(INTERNAL_ERROR(0,"Attempt to calculate ETA for a running timer"));
504  if (a_total == 0) {
505  TRY_nomem(str = "??:??.?");
506  return(str);
507  }
508 
509  TRY_nomem(es = "Could not calculate ETA");
510  TRY(
511  percent_complete = a_complete;
512  percent_complete *= 100;
513  percent_complete /= a_total;
514  ,es);
515 
516  TRY_nomem(str = eta(percent_complete.value()));
517 
518  return(str);
519 }
520 
521 /** Given a number of bytes, estimate the BPS */
522 const std::string timer::bps(uint64 a_bytes) const
523 {
524  uint64 bps;
525  std::string str;
526 
527  if (!is_started())
528  throw(INTERNAL_ERROR(0,"Attempt to calculate bps for unstarted timer"));
529  if (!is_stopped())
530  throw(INTERNAL_ERROR(0,"Attempt to calculate bps for a running timer"));
531 
532  if (m_duration == 0)
533  bps = a_bytes;
534  else
535  bps = static_cast<uint64>(a_bytes / m_duration);
536  TRY_nomem(str = throughput_to_string(bps));
537 
538  return(str);
539 }
540 
541 /** Return the current time */
542 const std::string current_time(void)
543 {
544  std::string str;
545 
546  TRY_nomem(str = make_time_string_(time(0)));
547 
548  return(str);
549 }
550 
551 /** Generate a timstamp string */
552 std::string stamp(const pid_t a_pid, const int a_indention)
553 {
554  std::string str;
555  int indent;
556  pid_t this_pid;
557 
558  indent = a_indention;
559  TRY_nomem(str = current_time());
560  TRY_nomem(str += " [");
561  if (a_pid == 0)
562  this_pid = pid();
563  else
564  this_pid = a_pid;
565 
566  /*
567  * pid_t has to be static_cast because some compilers wind up calling
568  * estring(const long& ...) instead of estring(const unsigned long& ...),
569  * and then the value in estring can wind up being misinterpreted as a
570  * negative number.
571  *
572  * 4 digits is just a guess. I've never seen a PID over four digits. Is
573  * there an easy, portable way to determine how many digits pid_t could wind
574  * up being? If gcc 2.95.x had numeric_limits<> then it would be...
575  */
576  TRY_nomem(str +=
577  estring(static_cast<unsigned long>(this_pid)).fmt_str(
578  6,estring::right,' ',' '
579  )
580  );
581 
582  TRY_nomem(str += "]");
583  TRY_nomem(str += "> ");
584  for (; indent > 0; str += " ", --indent);
585 
586  return(str);
587 }
588 
const pid_t pid(void)
Return the PID of this process.
Definition: fs.cc:162
void mf_start_value(const value_type a_t)
Set the timer start value.
Definition: timer.cc:109
Safely manipulate numbers without worryiung about over/underflow error.
Definition: rmath.h:281
const std::string make_time_string_(timer::value_type a_t)
Given a timer value, return a string in the form of "YYYY.MM.DD HH:MM:SS".
Definition: timer.cc:26
const duration_type duration_secs(void) const
Reutrn the duration in seconds.
Definition: timer.cc:411
const bool is_stopped(void) const
Return whether or not the timer has been stopped.
Definition: timer.cc:405
Basic types definitions and templates.
void mf_stop_value(const value_type a_t)
Set the timer stop value.
Definition: timer.cc:116
An extended string class.
Definition: estring.h:52
double duration_type
Definition: timer.h:33
const std::string current_time(void)
Return the current time.
Definition: timer.cc:542
Right-justified.
Definition: estring.h:66
const bool is_started(void) const
Return whether or not the timer has been started.
Definition: timer.cc:399
const T value(void) const
Return the value.
Definition: rmath.h:311
const std::string bps(uint64 a_bytes) const
Given a number of bytes, estimate the BPS.
Definition: timer.cc:522
void clear(void)
Clear the timer.
Definition: timer.cc:98
timer()
C'tor.
Definition: timer.cc:73
const duration_type duration_hours(void) const
Return the duration in hours.
Definition: timer.cc:432
std::string stamp(const pid_t a_pid, const int a_indention)
Generate a timstamp string.
Definition: timer.cc:552
bool m_started
Definition: timer.h:75
const duration_type mf_calculate_duration(const value_type a_start, const value_type a_stop) const
Calculate the duration between start and stop.
Definition: timer.cc:124
std::string throughput_to_string(T a_t, const std::string &a_base_size_unit="b", const std::string &a_base_time_unit="s", uint16 a_width=10, uint16 a_precision=1, uint16 a_kilo=1024)
Given an integral number, return a string with the number formated as a number of machine-type size p...
Definition: strfmt.h:135
#define TRY_nomem(code)
Definition: error.h:144
void assign(const timer &a_timer)
Assign timer values from another timer instance.
Definition: timer.cc:162
void start(void)
Start (or restart) the timer.
Definition: timer.cc:137
const std::string stopped_at(void) const
Generate a stopped-at string.
Definition: timer.cc:371
value_type m_stop
Definition: timer.h:74
const value_type start_value(void) const
Return the timer start value.
Definition: timer.cc:150
value_type fmt_str(void)
Generate a formatted string.
Definition: estring.cc:688
bool m_use_localtime
Definition: timer.h:78
#define TRY(code, es)
Definition: error.h:126
const std::string mf_make_timer_string(const value_type a_t) const
Generate a string in a regular human-readable format.
Definition: timer.cc:212
#define INTERNAL_ERROR(e, s)
Definition: error.h:123
const std::string started_at(void) const
Generate a started-at string.
Definition: timer.cc:359
time_t value_type
Definition: timer.h:32
const duration_type duration_years(void) const
Return the duration in years.
Definition: timer.cc:452
const value_type stop_value(void) const
Return the timer stop value.
Definition: timer.cc:156
const std::string duration(void) const
Generate a duration string.
Definition: timer.cc:385
const std::string eta(unsigned int a_percent_complete) const
Given a percent-complete for some unknown task, estimate a time to completion.
Definition: timer.cc:463
bool m_stopped
Definition: timer.h:76
const bool use_localtime(void) const
Return whether to use localtime or GMT.
Definition: timer.cc:206
const duration_type duration_days(void) const
Return the duration in days.
Definition: timer.cc:442
#define ERROR(e, s)
Definition: error.h:120
const duration_type duration_mins(void) const
Return the duration in minutes.
Definition: timer.cc:422
duration_type m_duration
Definition: timer.h:77
timer & operator=(const timer &a_timer)
Assignment.
Definition: timer.cc:192
void stop(void)
Stop the timer.
Definition: timer.cc:143
value_type m_start
Definition: timer.h:73
const std::string mf_make_string(const value_type a_t) const
Generate a string in a timestamp format.
Definition: timer.cc:273
Used as a stopwatch.
Definition: timer.h:29