source: src/libcfa/time @ 6ecc079

aaron-thesisarm-ehcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumwith_gc
Last change on this file since 6ecc079 was 6ecc079, checked in by Peter A. Buhr <pabuhr@…>, 5 years ago

first draft of time package

  • Property mode set to 100644
File size: 14.8 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// calendar --
8//
9// Author           : Peter A. Buhr
10// Created On       : Wed Mar 14 23:18:57 2018
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Thu Mar 22 17:11:19 2018
13// Update Count     : 495
14//
15
16#pragma once
17
18// http://en.cppreference.com/w/cpp/header/chrono
19// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0355r5.html#refcc
20
21#include <time.h>
22extern "C" {
23#include <sys/time.h>
24int snprintf( char * buf, size_t size, const char * fmt, ... );
25}
26#include <fstream>
27
28enum {
29        CLOCKGRAN = 15_000_000L,                                                        // ALWAYS in nanoseconds, MUST BE less than 1 second
30        TIMEGRAN = 1_000_000_000L                                                       // nanosecond granularity, except for timeval
31};
32
33
34#if defined( REALTIME_POSIX )
35#define tv_XSEC tv_nsec
36#else
37#define tv_XSEC tv_usec
38#endif
39
40
41#if defined( __linux__ )
42// fake a few things
43#define CLOCK_REALTIME  0                                                               // real (clock on the wall) time
44#endif
45
46// conversions for existing time types
47static inline void ?{}( timeval & t ) {}
48static inline void ?{}( timeval & t, time_t sec ) { t.tv_sec = sec; t.tv_usec = 0; }
49static inline void ?{}( timeval & t, time_t sec, suseconds_t usec ) { t.tv_sec = sec; t.tv_usec = usec; }
50
51static inline void ?{}( timespec & t ) {}
52static inline void ?{}( timespec & t, time_t sec ) { t.tv_sec = sec; t.tv_nsec = 0; }
53static inline void ?{}( timespec & t, time_t sec, __syscall_slong_t nsec ) { t.tv_sec = sec; t.tv_nsec = nsec; }
54
55static inline char * ctime( time_t tp ) { char * buf = ctime( &tp ); buf[24] = '\0'; return buf; }
56static inline char * ctime_r( time_t tp, char * buf ) { ctime_r( &tp, buf ); buf[24] = '\0'; return buf; }
57static inline tm * gmtime( time_t tp ) { return gmtime( &tp ); }
58static inline tm * gmtime_r( time_t tp, tm * result ) { return gmtime_r( &tp, result ); }
59static inline tm * localtime( time_t tp ) { return localtime( &tp ); }
60static inline tm * localtime_r( time_t tp, tm * result ) { return localtime_r( &tp, result ); }
61
62
63//######################### Duration #########################
64
65struct Duration {
66        int64_t tv;
67};
68
69static inline void ?{}( Duration & dur ) with( dur ) { tv = 0; }
70static inline void ?{}( Duration & dur, Duration d ) with( dur ) { tv = d.tv; }
71
72static inline void ?{}( Duration & dur, timeval t ) with( dur ) {
73        tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000;
74} // Duration
75
76static inline void ?{}( Duration & dur, timespec t ) with( dur ) {
77        tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
78} // Duration
79
80static inline Duration ?=?( Duration & dur, timeval t ) with( dur ) {
81        tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000;
82        return dur;
83} // ?=?
84
85static inline Duration ?=?( Duration & dur, timespec t ) with( dur ) {
86        tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
87        return dur;
88} // ?=? timespec
89
90static inline void ?{}( timeval & t, Duration dur ) with( dur ) {
91        t.tv_sec = tv / TIMEGRAN;                                                       // seconds
92        t.tv_usec = tv % TIMEGRAN / ( TIMEGRAN / 1000000L ); // microseconds
93} // ?{}
94
95static inline void ?{}( timespec & t, Duration dur ) with( dur ) {
96        t.tv_sec = tv / TIMEGRAN;                                                       // seconds
97        t.tv_nsec = tv % TIMEGRAN;                                                      // nanoseconds
98} // Timespec
99
100static inline int64_t nsecs( Duration dur ) with( dur ) { return tv; }
101
102static inline Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tv }; }
103static inline Duration ?+?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tv + rhs.tv }; }
104static inline Duration ?+=?( Duration & lhs, Duration rhs ) { lhs = lhs + rhs; return lhs; }
105
106static inline Duration -?( Duration rhs ) with( rhs ) { return (Duration)@{ -tv }; }
107static inline Duration ?-?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tv - rhs.tv }; }
108static inline Duration ?-=?( Duration & lhs, Duration rhs ) { lhs = lhs - rhs; return lhs; }
109
110static inline Duration ?*?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tv * rhs }; }
111static inline Duration ?*?( int64_t lhs, Duration rhs ) { return (Duration)@{ lhs * rhs.tv }; }
112static inline Duration ?*=?( Duration & lhs, int64_t rhs ) { lhs = lhs * rhs; return lhs; }
113
114static inline Duration ?/?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tv / rhs }; }
115static inline int64_t ?/?( Duration lhs, Duration rhs ) { return lhs.tv / rhs.tv; }
116static inline Duration ?/=?( Duration & lhs, int64_t rhs ) { lhs = lhs / rhs; return lhs; }
117
118static inline Duration ?%?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tv % rhs }; }
119static inline int64_t ?%?( int64_t lhs, Duration rhs ) { return lhs % (rhs.tv / TIMEGRAN); }
120static inline int64_t ?%?( Duration lhs, Duration rhs ) { return lhs.tv % rhs.tv; }
121
122static inline _Bool ?==?( Duration lhs, Duration rhs ) { return lhs.tv == rhs.tv; }
123static inline _Bool ?!=?( Duration lhs, Duration rhs ) { return lhs.tv != rhs.tv; }
124static inline _Bool ?<?( Duration lhs, Duration rhs ) { return lhs.tv < rhs.tv; }
125static inline _Bool ?<=?( Duration lhs, Duration rhs ) { return lhs.tv <= rhs.tv; }
126static inline _Bool ?>?( Duration lhs, Duration rhs ) { return lhs.tv > rhs.tv; }
127static inline _Bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tv >= rhs.tv; }
128
129static inline Duration abs( Duration lhs ) {
130        return lhs.tv >= 0 ? lhs : -lhs;
131} // abs
132
133static inline forall( dtype ostype | ostream( ostype ) )
134ostype & ?|?( ostype & os, Duration dur ) with( dur ) {
135        os | tv / TIMEGRAN;
136        char buf[16];
137        snprintf( buf, 16, "%09ld", ((tv < 0 ? -tv : tv) % TIMEGRAN) );
138        int i;
139        for ( i = 8; i >= 0 && buf[i] == '0' ; i -= 1 );        // find least significant digit
140        if ( i != -1 ) { buf[i + 1] = '\0';     os | '.' | buf; }
141        return os;
142}
143
144static inline Duration ?`ns( int64_t nsec ) { return (Duration)@{ nsec }; }
145static inline Duration ?`us( int64_t usec ) { return (Duration)@{ usec * (TIMEGRAN / 1_000l) }; }
146static inline Duration ?`ms( int64_t msec ) { return (Duration)@{ msec * (TIMEGRAN / 1_000_000l) }; }
147static inline Duration ?`s ( int64_t sec ) { return (Duration)@{ sec * TIMEGRAN }; }
148static inline Duration ?`s ( double  sec ) { return (Duration)@{ sec * TIMEGRAN }; }
149static inline Duration ?`m ( int64_t min ) { return (Duration)@{ min * (60L * TIMEGRAN) }; }
150static inline Duration ?`m ( double  min ) { return (Duration)@{ min * (60L * TIMEGRAN) }; }
151static inline Duration ?`h ( int64_t hours ) { return (Duration)@{ hours * (3600L * TIMEGRAN) }; }
152static inline Duration ?`h ( double  hours ) { return (Duration)@{ hours * (3600L * TIMEGRAN) }; }
153static inline Duration ?`d ( int64_t days ) { return (Duration)@{ days * (24L * 3600L * TIMEGRAN) }; }
154static inline Duration ?`d ( double  days ) { return (Duration)@{ days * (24L * 3600L * TIMEGRAN) }; }
155static inline Duration ?`w ( int64_t weeks ) { return (Duration)@{ weeks * (7L * 24L * 3600L * TIMEGRAN) }; }
156static inline Duration ?`f ( int64_t fortnight ) { return (Duration)@{ fortnight * (14L * 24L * 3600L * TIMEGRAN) }; }
157
158static inline int64_t ?`s ( Duration dur ) { return dur.tv / TIMEGRAN; }
159static inline int64_t ?`m ( Duration dur ) { return dur.tv / (60L * TIMEGRAN); }
160static inline int64_t ?`h ( Duration dur ) { return dur.tv / (3600L * TIMEGRAN); }
161static inline int64_t ?`d ( Duration dur ) { return dur.tv / (24L * 3600L * TIMEGRAN); }
162static inline int64_t ?`w ( Duration dur ) { return dur.tv / (7L * 24L * 3600L * TIMEGRAN); }
163static inline int64_t ?`f ( Duration dur ) { return dur.tv / (14L * 24L * 3600L * TIMEGRAN); }
164
165
166//######################### Time #########################
167
168
169struct Time {
170        uint64_t tv;
171};
172
173#ifdef __CFA_DEBUG__
174#define CreateFmt "Attempt to create Time( year=%d, month=%d, day=%d, hour=%d, min=%d, sec=%d, nsec=%d ), " \
175        "which exceeds range 00:00:00 UTC, January 1, 1970 to 03:14:07 UTC, January 19, 2038."
176#endif // __CFA_DEBUG__
177
178void mktime( Time & time, int year, int month, int day, int hour, int min, int sec, int nsec ) with( time ) {
179        tm tm;
180
181//      tzset();                                                                                        // initialize time global variables
182        tm.tm_isdst = -1;                                                                       // let mktime determine if alternate timezone is in effect
183        tm.tm_year = year - 1900;                                                       // mktime uses 1900 as its starting point
184        tm.tm_mon = month - 1;
185        tm.tm_mday = day;                                                                       // mktime uses range 1-31
186        tm.tm_hour = hour;
187        tm.tm_min = min;
188        tm.tm_sec = sec;
189        time_t epochsec = mktime( &tm );
190#ifdef __CFA_DEBUG__
191        if ( epochsec == (time_t)-1 ) {
192                abort( CreateFmt, year, month, day, hour, min, sec, nsec );
193        } // if
194#endif // __CFA_DEBUG__
195        tv = (int64_t)(epochsec) * TIMEGRAN + nsec;                     // convert to nanoseconds
196#ifdef __CFA_DEBUG__
197        if ( tv > 2147483647LL * TIMEGRAN ) {                           // between 00:00:00 UTC, January 1, 1970 and 03:14:07 UTC, January 19, 2038.
198                abort( CreateFmt, year, month, day, hour, min, sec, nsec );
199        } // if
200#endif // __CFA_DEBUG__
201} // mktime
202
203static inline void ?{}( Time & t ) with( t ) {
204        tv = 0;
205} // Time
206
207// These two constructors must not call mktime because it calls malloc. The malloc calls lead to recursion problems
208// because Time values are created from the sigalrm handler in composing the next context switch event.
209
210static inline void ?{}( Time & t, int sec ) with( t ) {
211#ifdef __CFA_DEBUG__
212        if ( tv < 0 || tv > 2147483647LL ) {                            // between 00:00:00 UTC, January 1, 1970 and 03:14:07 UTC, January 19, 2038.
213            abort( CreateFmt, 1970, 0, 0, 0, 0, sec, 0 );
214        } // if
215#endif // __CFA_DEBUG__
216        tv = (int64_t)sec * TIMEGRAN;
217} // Time
218
219static inline void ?{}( Time & t, int sec, int nsec ) with( t ) {
220#ifdef __U_DEBUG__
221        if ( tv < 0 || tv > 2147483647LL || nsec < 0 ) {        // between 00:00:00 UTC, January 1, 1970 and 03:14:07 UTC, January 19, 2038.
222            abort( CreateFmt, 1970, 0, 0, 0, 0, sec, nsec );
223        } // if
224#endif // __U_DEBUG__
225        tv = (int64_t)sec * TIMEGRAN + nsec;
226} // Time
227
228static inline void ?{}( Time & time, int min, int sec, long int nsec ) {
229        mktime( time, 1970, 1, 1, 0, min, sec, nsec );
230} // Time
231
232static inline void ?{}( Time & time, int hour, int min, int sec, long int nsec ) {
233        mktime( time, 1970, 1, 1, hour, min, sec, nsec );
234} // Time
235
236static inline void ?{}( Time & time, int day, int hour, int min, int sec, long int nsec ) {
237        mktime( time, 1970, 1, day, hour, min, sec, nsec );
238} // Time
239
240static inline void ?{}( Time & time, int month, int day, int hour, int min, int sec, long int nsec ) {
241        mktime( time, 1970, month, day, hour, min, sec, nsec );
242} // Time
243
244static inline void ?{}( Time & time, int year, int month, int day, int hour, int min, int sec, long int nsec ) {
245        mktime( time, year, month, day, hour, min, sec, nsec );
246} // Time
247
248static inline void ?{}( Time & time, timeval t ) with( time ) {
249        tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000;
250} // Time
251
252static inline void ?{}( Time & time, timespec t ) with( time ) {
253        tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
254} // Time
255
256static inline Time ?=?( Time & time, timeval t ) with( time ) {
257        tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000;
258        return time;
259} // ?=?
260
261static inline Time ?=?( Time & time, timespec t ) with( time ) {
262        tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
263        return time;
264} // ?=?
265
266static inline void ?{}( timeval & t, Time time ) with( time ) {
267        t.tv_sec = tv / TIMEGRAN;                                                       // seconds
268        t.tv_usec = tv % TIMEGRAN / ( TIMEGRAN / 1_000_000L ); // microseconds
269} // ?{}
270
271static inline void ?{}( timespec & t, Time time ) with( time ) {
272        t.tv_sec = tv / TIMEGRAN;                                                       // seconds
273        t.tv_nsec = tv % TIMEGRAN;                                                      // nanoseconds
274} // ?{}
275
276static inline int64_t nsec( Time time ) with( time ) { return tv; }
277
278static inline Time ?+?( Time & lhs, Duration rhs ) { return (Time)@{ lhs.tv + rhs.tv }; }
279static inline Time ?+?( Duration lhs, Time rhs ) { return rhs + lhs; }
280static inline Time ?+=?( Time & lhs, Duration rhs ) { lhs = lhs + rhs; return lhs; }
281
282static inline Duration ?-?( Time lhs, Time rhs ) { return (Duration)@{ lhs.tv - rhs.tv }; }
283static inline Time ?-?( Time lhs, Duration rhs ) { return (Time)@{ lhs.tv - rhs.tv }; }
284static inline Time ?-=?( Time & lhs, Duration rhs ) { lhs = lhs - rhs; return lhs; }
285static inline _Bool ?==?( Time lhs, Time rhs ) { return lhs.tv == rhs.tv; }
286static inline _Bool ?!=?( Time lhs, Time rhs ) { return lhs.tv != rhs.tv; }
287static inline _Bool ?<?( Time lhs, Time rhs ) { return lhs.tv < rhs.tv; }
288static inline _Bool ?<=?( Time lhs, Time rhs ) { return lhs.tv <= rhs.tv; }
289static inline _Bool ?>?( Time lhs, Time rhs ) { return lhs.tv > rhs.tv; }
290static inline _Bool ?>=?( Time lhs, Time rhs ) { return lhs.tv >= rhs.tv; }
291
292static inline char * yymmd( Time time, char * buf ) with( time ) {
293        tm tm;
294        time_t s = tv / TIMEGRAN;
295        gmtime_r( &s, &tm );
296        snprintf( buf, 9, "%02d/%02d/%02d", tm.tm_year % 99, tm.tm_mon, tm.tm_mday );
297        return buf;
298} // yymmd
299
300static inline char * mmyyd( Time time, char * buf ) with( time ) {
301        tm tm;
302        time_t s = tv / TIMEGRAN;
303        gmtime_r( &s, &tm );
304        snprintf( buf, 9, "%02d/%02d/%02d", tm.tm_mon, tm.tm_year % 99, tm.tm_mday );
305        return buf;
306} // yymmd
307
308static inline char * dmmyy( Time time, char * buf ) with( time ) {
309        tm tm;
310        time_t s = tv / TIMEGRAN;
311        gmtime_r( &s, &tm );
312        snprintf( buf, 9, "%02d/%02d/%02d", tm.tm_mday, tm.tm_mon, tm.tm_year % 99 );
313        return buf;
314} // yymmd
315
316static inline forall( dtype ostype | ostream( ostype ) )
317ostype & ?|?( ostype & os, Time time ) with( time ) {
318        char buf[32];                                                                           // at least 26
319        time_t s = tv / TIMEGRAN;
320        tm tm;
321        gmtime_r( &s, &tm );                                                            // ctime_r adjusts for timezone
322        asctime_r( &tm, (char *)&buf );
323        buf[24] = '\0';                                                                         // remove trailing '\n'
324        long int ns = (tv < 0 ? -tv : tv) % TIMEGRAN;
325        if ( ns == 0 ) {
326                os | buf;
327        } else {
328                buf[19] = '\0';
329                os | buf;
330                char buf2[16];
331                snprintf( buf2, 16, "%09ld", ns );
332                int i;
333                for ( i = 8; i >= 0 && buf2[i] == '0' ; i -= 1 ); // find least significant digit
334                if ( i != -1 ) { buf2[i + 1] = '\0'; os | '.' | buf2; }
335                os | ' ' | &buf[20];
336        } // if
337        return os;
338} // ?|?
339
340//######################### Clock #########################
341
342
343struct Clock {
344        Duration offset;                                                                        // for virtual clock: contains offset from real-time
345        int clocktype;                                                                          // implementation only -1 (virtual), CLOCK_REALTIME
346};
347
348void resetClock( Clock & clk ) with( clk ) {
349        clocktype = CLOCK_REALTIME;
350} // Clock::resetClock
351
352void resetClock( Clock & clk, Duration adj ) with( clk ) {
353        clocktype = -1;
354        Duration tz = (timeval){ timezone, 0 };
355        offset = adj + tz;
356} // resetClock
357
358void ?{}( Clock & clk ) {
359        resetClock( clk );
360} // Clock
361
362void ?{}( Clock & clk, Duration adj ) {
363        resetClock( clk, adj );
364} // Clock
365
366Duration getRes() {
367        struct timespec res;
368        clock_getres( CLOCK_REALTIME, &res );
369        return (Duration){ res };
370} // getRes
371
372Time getTime() {
373        timespec curr;
374        clock_gettime( CLOCK_REALTIME_COARSE, &curr );
375        return (Time){ curr };
376} // getTime
377
378Time getTime( Clock & clk ) with( clk ) {
379        return getTime() + offset;
380} // getTime
381
382Time ?()( Clock & clk ) with( clk ) {                                   // alternative syntax
383        return getTime() + offset;
384} // getTime
385
386timeval getTime( Clock & clk ) {
387        return (timeval){ clk() };
388} // getTime
389
390tm getTime( Clock & clk ) with( clk ) {
391        tm ret;
392        localtime_r( getTime( clk ).tv_sec, &ret );
393        return ret;
394} // getTime
395
396// Local Variables: //
397// mode: c //
398// tab-width: 4 //
399// End: //
400
Note: See TracBrowser for help on using the repository browser.