# You are allowed to redistribute it and sell it, alone or is a part of
# another product.
-# Provides the Clock utility class to keep time of real time flow
-module realtime is c_linker_option("-lrt")
+# Services to keep time of the wall clock time
+module realtime is ldflags "-lrt"
in "C header" `{
#ifdef _POSIX_C_SOURCE
#include <time.h>
`}
-extern Timespec `{struct timespec*`}
+in "C" `{
+
+#if defined(__MACH__) && !defined(CLOCK_REALTIME)
+/* OS X does not have clock_gettime, mascarade it and use clock_get_time
+ * cf http://stackoverflow.com/questions/11680461/monotonic-clock-on-osx
+*/
+#include <mach/clock.h>
+#include <mach/mach.h>
+#define CLOCK_REALTIME CALENDAR_CLOCK
+#define CLOCK_MONOTONIC SYSTEM_CLOCK
+void clock_gettime(clock_t clock_name, struct timespec *ts) {
+ clock_serv_t cclock;
+ mach_timespec_t mts;
+ host_get_clock_service(mach_host_self(), clock_name, &cclock);
+ clock_get_time(cclock, &mts);
+ mach_port_deallocate(mach_task_self(), cclock);
+ ts->tv_sec = mts.tv_sec;
+ ts->tv_nsec = mts.tv_nsec;
+}
+#endif
+`}
+
+# Elapsed time representation.
+extern class Timespec `{struct timespec*`}
+
+ # Init a new Timespec from `s` seconds and `ns` nanoseconds.
new ( s, ns : Int ) `{
struct timespec* tv = malloc( sizeof(struct timespec) );
tv->tv_sec = s; tv->tv_nsec = ns;
return tv;
`}
+
+ # Init a new Timespec from now.
new monotonic_now `{
struct timespec* tv = malloc( sizeof(struct timespec) );
clock_gettime( CLOCK_MONOTONIC, tv );
return tv;
`}
+
+ # Init a new Timespec copied from another.
new copy_of( other : Timespec ) `{
struct timespec* tv = malloc( sizeof(struct timespec) );
tv->tv_sec = other->tv_sec;
return tv;
`}
+ # Update `self` clock.
fun update `{
- clock_gettime( CLOCK_MONOTONIC, recv );
+ clock_gettime(CLOCK_MONOTONIC, self);
`}
- fun - ( o : Timespec ) : Timespec
- do
- var s = sec - o.sec
- var ns = nanosec - o.nanosec
- if ns > nanosec then s += 1
- return new Timespec( s, ns )
- end
+ # Subtract `other` from `self`
+ fun -(other: Timespec): Timespec `{
+ time_t s = self->tv_sec - other->tv_sec;
+ long ns = self->tv_nsec - other->tv_nsec;
+ if (ns < 0) {
+ s -= 1;
+ ns += 1000000000l;
+ }
+ struct timespec* tv = malloc(sizeof(struct timespec));
+ tv->tv_sec = s; tv->tv_nsec = ns;
+ return tv;
+ `}
+
+ # Number of whole seconds of elapsed time.
fun sec : Int `{
- return recv->tv_sec;
+ return self->tv_sec;
`}
+
+ # Rest of the elapsed time (a fraction of a second).
+ #
+ # Number of nanoseconds.
fun nanosec : Int `{
- return recv->tv_nsec;
+ return self->tv_nsec;
+ `}
+
+ # Elapsed time in microseconds, with both whole seconds and the rest
+ #
+ # May cause an `Int` overflow, use only with a low number of seconds.
+ fun microsec: Int `{
+ return self->tv_sec*1000000 + self->tv_nsec/1000;
+ `}
+
+ # Elapsed time in milliseconds, with both whole seconds and the rest
+ #
+ # May cause an `Int` overflow, use only with a low number of seconds.
+ fun millisec: Int `{
+ return self->tv_sec*1000 + self->tv_nsec/1000000;
`}
- fun destroy `{
- free( recv );
+ # Number of seconds as a `Float`
+ #
+ # Incurs a loss of precision, but the result is pretty to print.
+ fun to_f: Float `{
+ return (double)self->tv_sec + 0.000000001 * self->tv_nsec;
`}
+
+ redef fun to_s do return "{to_f}s"
end
# Keeps track of real time
+#
+# ~~~
+# var clock = new Clock
+#
+# # sleeping at least 1s
+# 1.0.sleep
+# assert clock.total >= 1.0
+# assert clock.lapse >= 1.0
+#
+# # sleeping at least 5ms
+# 0.005.sleep
+# assert clock.total >= 1.005
+# assert clock.lapse >= 0.005
+# ~~~
class Clock
- # Time at instanciation
- protected var time_at_beginning : Timespec
+ super FinalizableOnce
- # Time at last time a lapse method was called
- protected var time_at_last_lapse : Timespec
+ # TODO use less mallocs
- init
- do
- time_at_beginning = new Timespec.monotonic_now
- time_at_last_lapse = new Timespec.monotonic_now
- end
+ # Time at creation
+ protected var time_at_beginning = new Timespec.monotonic_now
+
+ # Time at last time a lapse method was called
+ protected var time_at_last_lapse = new Timespec.monotonic_now
# Smallest time frame reported by clock
- fun resolution : Timespec `{
+ fun resolution: Timespec `{
struct timespec* tv = malloc( sizeof(struct timespec) );
+#if defined(__MACH__) && !defined(CLOCK_REALTIME)
+ clock_serv_t cclock;
+ int nsecs;
+ mach_msg_type_number_t count;
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+ clock_get_attributes(cclock, CLOCK_GET_TIME_RES, (clock_attr_t)&nsecs, &count);
+ mach_port_deallocate(mach_task_self(), cclock);
+ tv->tv_sec = 0;
+ tv->tv_nsec = nsecs;
+#else
clock_getres( CLOCK_MONOTONIC, tv );
+#endif
return tv;
`}
- # Return timelapse since instanciation of this instance
- fun total : Timespec
+ # Seconds since the creation of this instance
+ fun total: Float
do
- return new Timespec.monotonic_now - time_at_beginning
+ var now = new Timespec.monotonic_now
+ var diff = now - time_at_beginning
+ var r = diff.to_f
+ diff.free
+ now.free
+ return r
end
- # Return timelapse since last call to lapse
- fun lapse : Timespec
+ # Seconds since the last call to `lapse`
+ fun lapse: Float
do
var nt = new Timespec.monotonic_now
var dt = nt - time_at_last_lapse
+ var r = dt.to_f
+ dt.free
+ time_at_last_lapse.free
time_at_last_lapse = nt
- return dt
+ return r
+ end
+
+ # Seconds since the last call to `lapse`, without resetting the lapse counter
+ fun peek_lapse: Float
+ do
+ var nt = new Timespec.monotonic_now
+ var dt = nt - time_at_last_lapse
+ var r = dt.to_f
+ nt.free
+ dt.free
+ return r
+ end
+
+ redef fun finalize_once
+ do
+ time_at_beginning.free
+ time_at_last_lapse.free
end
end