.. highlight:: none


.. index::
   pair: clock; design

.. _design-clock:


Fast high-resolution clock
==========================

.. mps:prefix:: design.mps.clock


Introduction
------------

:mps:tag:`intro` This is the design of the clock module, which implements a
fast high-resolution clock for use by the telemetry system.

:mps:tag:`readership` This document is intended for any MPS developer.


Requirements
------------

:mps:tag:`req.monotonic` Successive calls to :c:func:`EVENT_CLOCK()` must yield
values that are monotonically increasing. (So that comparing the
timestamp on two events never gives false positives.)

:mps:tag:`req.fast` :c:func:`EVENT_CLOCK()` should take very little time; it
should not require a system call. (So that programs that use the MPS
remain usable when telemetry is turned on.)

:mps:tag:`req.high-resolution` Successive calls to :c:func:`EVENT_CLOCK()` should
yield values that are strictly monotonically increasing (so that
sorting the telemetry stream puts the events in the order they
happened).


Interface
---------

:c:type:`EventClock`

:mps:tag:`if.type` The type of timestamps. It must be an unsigned 64-bit
integral type, for example a ``typedef`` for ``uint64_t`` or
``unsigned __int64``.

.. c:macro:: EVENT_CLOCK_MAKE(lvalue, low, high)

:mps:tag:`if.make` Construct an :c:type:`EventClock` timestamp from its two
halves. The first parameter is an lvalue with type :c:type:`EventClock`, and
the second and third parameters are 32-bit unsigned integers. The
macro must assign a timestamp to ``lvalue`` with the value ``(high
<< 32) + low``.

.. c:macro:: EVENT_CLOCK(lvalue)

:mps:tag:`if.get` Assign an :c:type:`EventClock` timestamp for the current time to
``lvalue``, which is an lvalue with type :c:type:`EventClock`.

.. c:macro:: EVENT_CLOCK_PRINT(stream, clock)

:mps:tag:`if.print` Write the value of ``clock`` to the standard C output
file handle ``stream`` as 16 hexadecimal digits (with leading zeros,
and capital letters A to F).

.. c:macro:: EVENT_CLOCK_WRITE(stream, clock)

:mps:tag:`if.write` Write the value of ``clock`` to the output stream
``stream`` as 16 hexadecimal digits (with leading zeros, and capital
letters A to F). The macro should be implemented using :c:func:`WriteF()`.


Implementation
--------------

:mps:tag:`impl.tsc` On IA-32 and x86-64, the `Time Stamp Counter
<https://en.wikipedia.org/wiki/Time_Stamp_Counter>`_ returned by the
RDTSC instruction is a suitable clock for single-core CPUs, but on
multiple-core CPUs, different cores may have different values or tick at different speeds, and so it may fail to meet :mps:ref:`.req.monotonic`.