package async_kernel
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=01ced973dbc70535f692f38bed524ae82dba17e26e58791b2fbf0d647b160d2e
doc/async_kernel/Async_kernel/Synchronous_time_source/index.html
Module Async_kernel.Synchronous_time_source
Source
A synchronous version of Async_kernel.Time_source
. advance_by_alarms
runs alarms immediately, rather than enqueueing Async jobs.
Synchronous_time_source
is a wrapper around Timing_wheel
. One difference is that Synchronous_time_source
alarms fire in non-decreasing time order, whereas in Timing_wheel
that is only true for alarms in different time intervals as determined by alarm_precision
.
module Id : Core.Unique_id.Id
val invariant_with_jobs :
job:
(Async_kernel__.Types.Execution_context.t, Obj.t -> unit, Obj.t)
Tuple_pool.Slots.t3
Tuple_pool.Pointer.t
Core.Invariant.t ->
t Core.Invariant.t
include Core.Invariant.S with type t := t
id t
returns a unique, consistent identifier which can be used e.g. as a map or hash table key.
val create :
?timing_wheel_config:Timing_wheel.Config.t ->
now:Core.Time_ns.t ->
unit ->
Core.read_write T1.t
create ~now ()
creates a new simulated time source. The default timing_wheel_config
has 100 microsecond precision, with levels of >1s, >1m, >1h, >1d. The timing_wheel_config
is used to tune performance; configuration does not affect the fact that alarms fire in non-decreasing time order.
is_wall_clock
reports whether this time source represents 'wall clock' time, or some alternate source of time.
The behavior of now
is special for wall_clock ()
; it always calls Time_ns.now ()
, so it can return times that the time source has not yet been advanced to.
Removes the special behavior of now
for wall_clock ()
; it always returns the timing wheel's notion of now, which means that the following inequality always holds: timing_wheel_now () <= now ()
.
run_at t at f
schedules an alarm that will run f
during the next subsequent advance_by_alarms t ~to_
that causes now t >= at
. If at <= now t
, then f
will to run at the next call to advance_by_alarms
. f
is allowed to do all Synchronous_time_source
operations except for advance_by_alarms
(because f
is already running during advance_by_alarms
. Adding alarms is not zero-alloc and the underlying events live in the OCaml heap.
val run_after :
[> Core.read ] T1.t ->
Core.Core_private.Time_ns_alternate_sexp.Span.t ->
callback ->
unit
run_after t span f
is run_at t (now t + span) f
.
val run_at_intervals :
?start:Core.Time_ns.t ->
[> Core.read ] T1.t ->
Core.Core_private.Time_ns_alternate_sexp.Span.t ->
callback ->
unit
run_at_intervals t span f
schedules f
to run at intervals start + k * span
, for k = 0, 1, 2, etc. run_at_intervals
raises if span < alarm_precision t
.
If start
is earlier than now t
, the first call to f
run on the next call to advance_by_alarms
. This differs from the behaviour of Time_source.run_at_intervals
.
max_allowed_alarm_time t
returns the greatest at
that can be supplied to add
. max_allowed_alarm_time
is not constant; its value increases as now t
increases.
val duration_of :
[> Core.read ] T1.t ->
(unit -> 'a) ->
'a * Core.Core_private.Time_ns_alternate_sexp.Span.t
duration_of t f
invokes f
and measures how long it takes for the call to finish.
A time source with now t
given by wall-clock time (i.e. Time_ns.now
), and automatically advanced at the start of each Async cycle. The wall clock uses the same timing wheel as that used by the Async scheduler, and is hence similarly affected by the ASYNC_CONFIG
environment variable.
For Scheduler Implementors
length t
returns the number of alarms in the underlying Timing_wheel
.
next_alarm_runs_at t
returns a time to which the clock can be advanced such that an alarm will fire, or None
if t
has no alarms that can ever fire.
Note that this is not necessarily the minimum such time, but it's within alarm_precision
of that.
If an alarm was already fired (e.g. because it was scheduled in the past), but its callbacks were not run yet, this function returns Some now
, to indicate that a trivial time advancement is sufficient for those to run.
advance_by_alarms t ~to_
advances t
's time to to_
, running callbacks for all alarms in t
whose at <= to_
. Callbacks run in nondecreasing order of at
. If to_ <= now t
, then now t
does not change (and in particular does not go backward), but alarms with at <= to_
may still may fire.
val advance_by_alarms_by :
[> Core.write ] T1.t ->
Core.Core_private.Time_ns_alternate_sexp.Span.t ->
unit Core.Or_error.t
advance_by_alarms_by t by
is equivalent to: advance_by_alarms t ~to_:(Time_ns.add (now t) by)
val advance_by_max_alarms_in_each_timing_wheel_interval :
[> Core.write ] T1.t ->
to_:Core.Time_ns.t ->
unit Core.Or_error.t
A version of advance_by_alarms
with some weird behavior caused by timing wheel alarm_precision
: if there are multiple alarms within the same timing_wheel precision bucket, then this function fires them all at the same time (when the last of the bunch of alarms is supposed to fire). The time to_
counts as an alarm for this purpose. (any alarms in the same bucket as to_
will be fired at time to_
.
advance_by_alarms
has no such weirdness, and fires every alarm at the time that alarm is scheduled.
Instead of advance_directly
, you probably should use advance_by_alarms
. advance_directly t ~to_
advances the clock directly to to_
, whereas advance_by_alarms
advances the clock in steps, to each intervening alarm. In particular periodic/rearming timers will fire at most twice.
val advance_directly_by :
[> Core.write ] T1.t ->
Core.Core_private.Time_ns_alternate_sexp.Span.t ->
unit Core.Or_error.t
advance_directly_by t by
is equivalent to: advance_directly_by t ~to_:(Time_ns.add (now t) by)
val max_alarm_time_in_min_timing_wheel_interval :
[> Core.write ] T1.t ->
Core.Time_ns.t option
This value is close to next_alarm_fires_at
but differs from it by at most alarm_precision
. Requires a more expensive iteration of alarms.
This is a closer approximation of the minimum time at which an alarm will fire, but it's still not there (you need min_alarm_time_... for that).
Returns true iff there is work to do without advancing time further. (This can be caused by scheduling events in the past, or starting a recurring event.)