update to set up make variables for compiling modules with libhrtime
[dyninst.git] / common / src / Time.C
1 #include <iostream.h>
2 #include <time.h>
3 #include <string.h>
4 #include <iomanip.h>
5 #include <stdio.h>
6 #include <assert.h>
7 #include <limits.h>
8 #include "common/h/Time.h"
9 #include "common/h/int64iostream.h"
10
11
12 timeUnit::ostream_fmt timeUnit::curFmt = timeUnit::sparse;
13
14 const timeUnit *timeUnit::_ns = NULL;
15 const timeUnit *timeUnit::_us = NULL;
16 const timeUnit *timeUnit::_ms = NULL;
17 const timeUnit *timeUnit::_sec = NULL;
18 const timeUnit *timeUnit::_min = NULL;
19 const timeUnit *timeUnit::_hour = NULL;
20 const timeUnit *timeUnit::_day = NULL;
21 const timeUnit *timeUnit::_year = NULL;
22
23 // these helper functions will help reduce code bloat
24 // The ...Help functions are not inlined (or not included with their inlined
25 // user functions) because the Help functions call constructors which are
26 // also inlined and the result is the possibility for a lot of code bloat.
27 // So the reference is inlined, but the creation step (which only will happen
28 // once) is not inlined.
29
30 const timeUnit *timeUnit::nsHelp() {
31   return new timeUnit(fraction(1));
32 }
33 const timeUnit *timeUnit::usHelp() {
34   return new timeUnit(fraction(1000));
35 }
36 const timeUnit *timeUnit::msHelp() {
37   return new timeUnit(fraction(1000000));
38 }
39 const timeUnit *timeUnit::secHelp() {
40   return new timeUnit(fraction(1000000000));
41 }
42 const timeUnit *timeUnit::minHelp() {
43   int64_t ns_per_sec = sec().get_ns_per_unit().getNumer();
44   return new timeUnit(fraction(I64_C(60) * ns_per_sec));
45 }
46 const timeUnit *timeUnit::hourHelp() {
47   int64_t ns_per_min = min().get_ns_per_unit().getNumer();
48   return new timeUnit(fraction(I64_C(60) * ns_per_min));
49 }
50 const timeUnit *timeUnit::dayHelp() {
51   int64_t ns_per_hour = hour().get_ns_per_unit().getNumer();
52   return new timeUnit(fraction(I64_C(24) * ns_per_hour));
53 }
54 const timeUnit *timeUnit::yearHelp() {
55   double ns_per_day =static_cast<double>(day().get_ns_per_unit().getNumer());
56   fraction ratio(static_cast<int64_t>(365.25 * ns_per_day));
57   return new timeUnit(ratio);
58 }
59
60 const timeBase *timeBase::_bStd = NULL;
61 const timeBase *timeBase::_b1970 = NULL;
62
63 const timeBase *timeBase::bStdHelp() {
64   return new timeBase(0);
65 }
66 const timeBase *timeBase::b1970Help() {
67   int64_t nsPerYear = timeUnit::year().get_ns_per_unit().getNumer();
68   return new timeBase((StdBaseMark-1970) * nsPerYear);
69 }
70
71
72 int64_t timeUnit::cvtTo_ns(double units) const {
73   double tns = ns_per_unit * units;
74   return static_cast<int64_t>(tns);
75 }
76
77 int64_t timeUnit::cvtTo_ns(int64_t units) const {
78   int64_t nsec;
79   nsec = ns_per_unit.multReturnInt64(units);
80   return nsec;
81 }
82
83 double timeUnit::cvtFrom_nsD(int64_t nsec) const {
84   return (fraction &)units_per_ns * (double)nsec;
85 }
86
87 int64_t timeUnit::cvtFrom_nsI(int64_t nsec) const {
88   int64_t units;
89   units = units_per_ns.multReturnInt64(nsec);
90   return units;
91 }
92
93 int64_t timeParent::getRolloverTime(double dt) {
94   // a modulus with doubles
95   int num = (int) (dt / (double)I64_MAX);
96   double rolloverAmt = dt - ((double) num * (double)I64_MAX);
97   return (int64_t) rolloverAmt;
98 }
99
100 const timeStamp *timeStamp::_ts1970 = NULL;
101 const timeStamp *timeStamp::_tsStd  = NULL;
102 const timeStamp *timeStamp::_ts2200  = NULL;
103
104 const timeStamp *timeStamp::ts1970Help() {
105   return new timeStamp(0, timeUnit::sec(), timeBase::b1970());
106 }
107
108 const timeStamp *timeStamp::tsStdHelp() {
109   int y19702Std = timeBase::StdBaseMark - 1970;
110   return new timeStamp(y19702Std, timeUnit::year(), timeBase::b1970());
111 }
112
113 const timeStamp *timeStamp::ts2200Help() {
114   return new timeStamp(230, timeUnit::year(), timeBase::b1970());
115 }
116
117 void timeStamp::initI(int64_t iTime, const timeUnit &u, timeBase b) {
118   assign( b.cvtTo_bStd( u.cvtTo_ns(iTime)));
119   /*  // if we allow exceptions in the future, we will be able to handle
120       // nicely cases of overflows in the fraction class
121       } catch(finalMultOverflowExc &) {
122       double dRes = static_cast<double>(b.cvtTo_bStd( u.cvtTo_ns(
123       static_cast<double>(iTime))));
124       assign( getRolloverTime(dRes));
125       }
126   */
127 }
128
129 void timeLength::initI(int64_t iTime, const timeUnit &u) {
130   assign( u.cvtTo_ns(iTime));
131   /*  // if we allow exceptions in the future, we will be able to handle
132       // nicely cases of overflows in the fraction class  
133       } catch(finalMultOverflowExc &) {
134       double dRes= static_cast<double>(u.cvtTo_ns(static_cast<double>(iTime)));
135       assign( getRolloverTime(dRes));
136       }
137   */
138 }
139
140 timeStamp::timeStamp(double dTime, const timeUnit &u, timeBase b): timeParent()
141 {
142   double dRes = static_cast<double>(b.cvtTo_bStd( u.cvtTo_ns(dTime)));
143   if(dRes <= static_cast<double>(I64_MAX)) 
144     assign( static_cast<int64_t>(dRes));
145   else
146     assign( getRolloverTime(dRes));
147 }
148
149 const timeLength *timeLength::_zero = NULL;
150 const timeLength *timeLength::ZeroHelp() {
151   return new timeLength(0, timeUnit::sec());
152 }
153 const timeLength *timeLength::_ns = NULL;
154 const timeLength *timeLength::nsHelp() {
155   return new timeLength(1, timeUnit::ns());
156 }
157 const timeLength *timeLength::_us = NULL;
158 const timeLength *timeLength::usHelp() {
159   return new timeLength(1, timeUnit::us());
160 }
161 const timeLength *timeLength::_ms = NULL;
162 const timeLength *timeLength::msHelp() {
163   return new timeLength(1, timeUnit::ms());
164 }
165 const timeLength *timeLength::_sec = NULL;
166 const timeLength *timeLength::secHelp() {
167   return new timeLength(1, timeUnit::sec());
168 }
169 const timeLength *timeLength::_min = NULL;
170 const timeLength *timeLength::minHelp() {
171   return new timeLength(1, timeUnit::min());
172 }
173 const timeLength *timeLength::_hour = NULL;
174 const timeLength *timeLength::hourHelp() {
175   return new timeLength(1, timeUnit::hour());
176 }
177 const timeLength *timeLength::_day = NULL;
178 const timeLength *timeLength::dayHelp() {
179   return new timeLength(1, timeUnit::day());
180 }
181 const timeLength *timeLength::_year = NULL;
182 const timeLength *timeLength::yearHelp() {
183   return new timeLength(1, timeUnit::year());
184 }
185
186 timeLength::timeLength(double dTime, const timeUnit &u) : timeParent() {
187   double dRes = static_cast<double>(u.cvtTo_ns(dTime));
188   if(dRes <= static_cast<double>(I64_MAX)) 
189     assign( static_cast<int64_t>(dRes));
190   else
191     assign( getRolloverTime(dRes));
192 }
193
194 ostream& operator<<(ostream&s, const timeUnit::ostream_fmt &u) {
195   timeUnit::curFmt = u;
196   return s;
197 }
198
199 ostream& operator<<(ostream&s, const timeUnit &u) {
200   if(timeUnit::curFmt == timeUnit::sparse) {
201     s << "["<< fraction::sparse << u.get_ns_per_unit()<<"]";
202   } else { // timeUnit::verbose
203     s << fraction::verbose << "[ns_per_unit: " << u.get_ns_per_unit() 
204       << ", units_per_ns: " << u.get_units_per_ns() << "]";
205   }
206   return s;
207 }
208
209 ostream& operator<<(ostream&s, timeBase b) {
210   s << "[ns2nearestCenturyMark: " << b.get_ns2StdBaseMark() << "]";
211   return s;
212 }
213
214 /*
215 ostream& operator<<(ostream& s, const timeParent &tp) {
216   return tp.put(s);
217 }
218 */
219
220 // only handles positives right now
221 // string buffer should be atleast 16
222 void insCommas(int num, char strbuf[]) {
223     char nsStr[20];
224     sprintf(nsStr,"%12d",num);
225     int nextIdx=0;
226     if(num>=1000000000) {
227       strncpy(&strbuf[nextIdx], &nsStr[0], 3);
228       nextIdx+=3;
229       strbuf[nextIdx++] = ',';  
230     }
231     if(num>=1000000) {
232       strncpy(&strbuf[nextIdx], &nsStr[3], 3);
233       nextIdx+=3;
234       strbuf[nextIdx++] = ',';  
235     }
236     if(num>=1000) {
237       strncpy(&strbuf[nextIdx], &nsStr[6], 3);
238       nextIdx+=3;
239       strbuf[nextIdx++] = ',';  
240     }
241     if(num>=0) {
242       strncpy(&strbuf[nextIdx], &nsStr[9], 3);
243       nextIdx+=3;
244     }
245     strbuf[nextIdx]=0;
246 }
247
248 ostream& operator<<(ostream&s, timeLength z) {
249   timeLength tUser = z;
250   int years = static_cast<int>(tUser.getI(timeUnit::year()));
251   timeLength tempT(years,timeUnit::year());
252   tUser -= tempT;
253   int days  = static_cast<int>(tUser.getI(timeUnit::day()));
254   tUser -= timeLength(days,timeUnit::day());
255   int hours = static_cast<int>(tUser.getI(timeUnit::hour()));
256   tUser -= timeLength(hours,timeUnit::hour());
257   int mins  = static_cast<int>(tUser.getI(timeUnit::min()));
258   tUser -= timeLength(mins,timeUnit::min());
259   int secs  = static_cast<int>(tUser.getI(timeUnit::sec()));
260   tUser -= timeLength(secs,timeUnit::sec());
261   int ms    = static_cast<int>(tUser.getI(timeUnit::ms()));
262   tUser -= timeLength(ms,timeUnit::ms());
263   int us    = static_cast<int>(tUser.getI(timeUnit::us()));
264   tUser -= timeLength(us,timeUnit::us());
265   int ns    = static_cast<int>(tUser.getI(timeUnit::ns()));
266
267   bool prev = false, compact = false;
268   char cSt[5] = ", ";
269   // this is a hack for those that want to print the time compressed
270   if(s.flags() & ostream::oct) {  compact=true;  s.flags(ostream::dec);  }
271   if(compact == true) strcpy(cSt,",");
272   s << "[";
273   if(tUser.get_ns() == 0) {  s << "0 time"; }
274   else {
275     if(years!=0) {  s << (prev? cSt:"") << years << " years";   prev=true; }
276     if(days!=0)  {  s << (prev? cSt:"") << days  << " days";    prev=true; }
277     if(hours!=0) {  s << (prev? cSt:"") << hours << " hours";   prev=true; }
278     if(mins!=0)  {  s << (prev? cSt:"") << mins  << " mins";    prev=true; }
279     if(secs!=0)  {  s << (prev? cSt:"") << secs  << " secs";    prev=true; }
280     if(ms!=0)    {  s << (prev? cSt:"") << ms    << " ms";      prev=true; }
281     if(us!=0)    {  s << (prev? cSt:"") << us    << " us";      prev=true; }
282     if(ns!=0)    {  s << (prev? cSt:"") << ns    << " ns";      prev=true; }
283   }
284   s << "]";
285   return s;
286 }
287
288 ostream& operator<<(ostream&s, timeStamp z) {
289   time_t s1970 = static_cast<time_t>(z.getI(timeUnit::sec(), timeBase::b1970()));
290   int64_t nsI1970 = static_cast<int64_t>(s1970) * I64_C(1000000000);
291   int64_t max_time_t = (I64_C(1)<<((sizeof(time_t)*8)-1))-1;  // eg. (2^(32-1)) -1
292   if(z < timeStamp(0, timeUnit::year(), timeBase::b1970()) ||
293      z > timeStamp(max_time_t, timeUnit::sec(), timeBase::b1970())) {
294     timeLength tl(z - timeStamp(0, timeUnit::year(), timeBase::b1970()));
295     // setting the oct flag is just a hack to tell the timeLength ostream<<
296     // to print the time compressed
297 #if !defined(mips_sgi_irix6_4) && !defined(i386_unknown_nt4_0)
298     ostream::fmtflags oldflags;
299 #else
300     long oldflags;  // irix,nt environment doesn't define ostream::fmtflags
301 #endif
302     oldflags = s.flags(ostream::oct);
303     s << "[1970 + " << tl << "]"; 
304     s.flags(oldflags);
305   } else {
306     int64_t nstot = z.getI(timeUnit::ns(), timeBase::b1970());
307     int64_t nsrem = nstot - nsI1970;
308     char dateStr[50];
309     strcpy(dateStr, ctime(&s1970));
310     char *p = strstr(dateStr, "\n");  // erase the nl
311     if(p != NULL) {  *p++ = 0;   *p = 0; }
312     char strFmt[30];
313     insCommas(static_cast<int>(nsrem), strFmt);
314     s << "[" << dateStr << setw(14) << strFmt << "ns]";
315   }
316   return s;
317 }
318
319
320
321