module Time_stamp_counter:sig
..end
This module provides the fast function now ()
which is our best effort
high-performance cycle counter for a given platform. For x86 systems this retrieves
the CPU's internal time stamp counter using the RDTSC instruction. For systems that
do not have a RDTSC instruction, we fallback to using
clock_gettime(CLOCK_MONOTONIC)
.
Here is a benchmark of execution time in nanos and allocations in words:
Name Time/Run mWd/Run ---------------------------- ---------- --------- Time.now 37.93ns 2.00w Time_ns.now 28.18ns TSC.Calibrator.calibrate 115.43ns 28.00w TSC.now 7.14ns TSC.to_time 3.44ns 2.00w TSC.to_time (TSC.now ()) 8.24ns 2.00w TSC.to_time_ns 14.20ns TSC.to_time_ns(TSC.now ()) 9.80ns id 2.91ns TSC.Span.of_ns 5.81ns TSC.Span.to_ns 3.70ns
Type t
is an Int63.t
and consequently has no allocation overhead (on 64-bit
machines), unlike Time.now ()
which returns a boxed float.
Functions are also provided to estimate the relationship of CPU time-stamp-counter
frequency to real time, thereby allowing one to convert from t
to Time.t
. There
are some caveats to this that are worth noting:
Time.t
depends on an estimate of the time-stamp-counter
frequency. This frequency may be volatile on some systems, thereby reducing the
utility of this conversion. See the Calibrator
module below for details.t
can only be converted to a Time.t
if one also has a
recently calibrated Calibrator.t
from the same machine.typet = private
Core_kernel.Std.Int63.t
module Calibrator:sig
..end
module Span:sig
..end
Span
indicates some integer number of cycles.
val now : unit -> t
val diff : t -> t -> Span.t
val add : t -> Span.t -> t
val to_int63 : t -> Core_kernel.Std.Int63.t
to_int63 t
returns the TSC value represented by t
as an Int63.t
.val to_time : ?calibrator:Calibrator.t -> t -> Time.t
to_time t
converts a t
to a Time.t
. It is guaranteed that repeated calls
of to_time ()
will return nondecreasing Time.t
values.val to_time_ns : ?calibrator:Calibrator.t ->
t -> Core_kernel.Std.Time_ns.t
to_time_ns t
converts a t
to an integer number of nanos since the epoch.val t_of_sexp : Sexplib.Sexp.t -> t
val sexp_of_t : t -> Sexplib.Sexp.t
val compare : t -> t -> int
val bin_t : t Core_kernel.Std.Bin_prot.Type_class.t
val bin_read_t : t Core_kernel.Std.Bin_prot.Read.reader
val __bin_read_t__ : (int -> t) Core_kernel.Std.Bin_prot.Read.reader
val bin_reader_t : t Core_kernel.Std.Bin_prot.Type_class.reader
val bin_size_t : t Core_kernel.Std.Bin_prot.Size.sizer
val bin_write_t : t Core_kernel.Std.Bin_prot.Write.writer
val bin_writer_t : t Core_kernel.Std.Bin_prot.Type_class.writer
.ml
file)
Calibration at the rate of 0.1, 1 or 2 secs produces errors (measured as the
difference between Time.now
and the reported time here) on the order of 1-2us.
Given the precision of 52bit float mantissa values, this is very close to least error
one can have on these values. Calibration once per 10sec produces errors that are
+/-4us. Calibration once per minute produces errors that are +/-15us and calibration
once in 3mins produces errors +/-30us. (It is worth remarking that the error has a
positive bias of 1us -- i.e. the error dances around the 1us mark, rather than around
0. It is unclear where this bias is introduced, though it probably does not matter for
most applications.)
This module maintains an instance of t
internal to the module. The internal
instance of t
can be updated via calls to calibrate ()
, i.e. without specifying
the t
parameter. In all the functions below that take an optional Calibrator.t
argument, the internal instance is used when no calibrator is explicitly specified.
create ()
creates an uninitialized calibrator instance. Creating a calibrator
takes about 3ms. One needs a recently calibrated Calibrator.t
and the TSC value
from the same machine to meaningfully convert the TSC value to a Time.t
.
calibrate ~t
updates t
by measuring the current value of the TSC and
Time.now
.
Returns the estimated MHz of the CPU's time-stamp-counter based on the TSC and
Time.now ()
. This function is undefined on 32bit machines.
Span
indicates some integer number of cycles.
to_int63 t
returns the TSC value represented by t
as an Int63.t
.
to_time t
converts a t
to a Time.t
. It is guaranteed that repeated calls
of to_time ()
will return nondecreasing Time.t
values.
to_time_ns t
converts a t
to an integer number of nanos since the epoch.