Skip to content
Work Practice Products Coding interviews Machine learning coding Quant developer HFT course Blog Method Why me About Enquire Book a call

Quant developer HFT course · Module 10: Numbers and time

Time, timestamps and clocks

Lesson · 12 min

The question

You need timestamps for latency measurement inside the process and for regulatory reporting of order events. Which clocks do you use for each, and why?

Two kinds of time

  • Wall-clock time (CLOCK_REALTIME, std::chrono::system_clock) answers "what time is it?" in UTC. It can jump: NTP or PTP corrections, an administrator setting the clock, leap-second handling. Needed for anything compared with the outside world: regulatory records, exchange timestamps, logs read by people.
  • Monotonic time (CLOCK_MONOTONIC, std::chrono::steady_clock) answers "how much time has passed?". It never goes backwards and is not set, though it may be slewed slightly by synchronisation. Needed for measuring intervals, timeouts and rate limits.

Measuring a latency with the wall clock can give negative or absurd durations when the clock is adjusted mid-measurement. That is the first point of the answer.

How much a clock read costs

On Linux, clock_gettime for the common clocks is served by the vDSO: a small piece of kernel code mapped into the process, which reads the time-stamp counter and converts it using parameters the kernel publishes, with no system call. That costs a few tens of nanoseconds. On some virtual machines, or with an unsuitable clock source, it falls back to a system call costing much more; cat /sys/devices/system/clocksource/clocksource0/current_clocksource should say tsc.

Tens of nanoseconds per read is acceptable for most purposes and too much for timestamping every stage of every message on the hot path, which is where the TSC comes in.

The TSC

The time-stamp counter is a per-core 64-bit counter read by the rdtsc instruction. On modern x86 processors with an "invariant TSC" (the constant_tsc and nonstop_tsc flags in /proc/cpuinfo), it ticks at a constant rate regardless of frequency changes and power states, and is synchronised across the cores of a machine. Reading it takes on the order of ten to twenty cycles.

Using it correctly:

  • Calibrate. It counts cycles of a nominal frequency, not nanoseconds. Measure its rate against CLOCK_MONOTONIC at start-up (and periodically), and convert with a multiply and shift.
  • Ordering. rdtsc is not a serialising instruction: the CPU may execute it before earlier instructions finish or after later ones start. For measuring a short region precisely, rdtscp waits for earlier instructions, and a fence (lfence) before rdtsc stops it being executed early. For timestamping events in a pipeline, plain rdtsc is usually fine.
  • Cross-machine comparisons need conversion to a common clock: TSCs on different machines are unrelated.
inline std::uint64_t ticks() { return __rdtsc(); }       // stage timestamps on the hot path

struct TscClock {                                          // calibrated at start-up
    std::uint64_t t0; std::int64_t ns0; double ns_per_tick;
    std::int64_t to_ns(std::uint64_t t) const { return ns0 + static_cast<std::int64_t>((t - t0) * ns_per_tick); }
};

Hot-path code records raw TSC values; conversion to nanoseconds and to UTC happens later, off the hot path.

Hardware timestamps

The network card can timestamp packets as they arrive and leave, with its own clock (the PTP hardware clock, PHC). These are the most accurate timestamps of when an event reached or left the machine, unaffected by kernel processing, and the basis of tick-to-trade measurement (Modules 7 and 8).

Synchronising clocks

PTPPTPphc2syscalibraterdtscGPS grandmasterUTC referencePTP switchboundary clockNIC clock (PHC)stamps packetssystem clockCLOCK_REALTIMETSCcheap, per coreapplicationtimestamps
A typical timing chain. PTP disciplines the network card's clock to UTC; phc2sys steers the system clock to the card; the application reads the TSC for cheap timestamps and converts them using a calibration against the system clock.
  • NTP synchronises over the network to within milliseconds, sometimes better, in software.
  • PTP (Precision Time Protocol, IEEE 1588) uses hardware timestamping in network cards and PTP-aware switches to synchronise to within well under a microsecond on a good network, from a grandmaster clock usually disciplined by GPS.
  • On the host, ptp4l keeps the card's PHC in sync with the grandmaster, and phc2sys steers the system clock to the PHC.

Regulation

Regulators require trading firms to record order events with timestamps traceable to UTC. In the European Union, MiFID II's clock-synchronisation rules (RTS 25) require firms engaged in high-frequency algorithmic trading to keep their clocks within 100 microseconds of UTC and to timestamp with a granularity of one microsecond or better, with lower requirements for other activity. US rules (the Consolidated Audit Trail) also set clock tolerances and timestamp granularity for reportable events. Meeting these means PTP-synchronised clocks, monitoring of the offset, and records of that monitoring, which is why the timing chain is a production system in its own right.

The answer

For latency inside the process, the TSC: cheap, monotonic and synchronised across cores on modern x86, read on the hot path and converted to nanoseconds later using a calibration against the monotonic clock. For anything that leaves the process or must be compared with the outside world, UTC from the system clock, which PTP keeps within the regulatory tolerance via the NIC's hardware clock. Network events are best timestamped by the card itself. I would never measure durations with the wall clock, because it can jump.

Check yourself

Question 1 of 3

Why should durations not be measured with std::chrono::system_clock?

Question 2 of 3

What does an invariant TSC guarantee?

Question 3 of 3

Under MiFID II's clock rules, what tolerance applies to firms engaged in high-frequency algorithmic trading?

In the interview

Say your own answer out loud first, then open the one we would give.

What is the difference between steady_clock and system_clock?

system_clock is wall-clock UTC time, which can be adjusted and jump; it is for timestamps compared with the outside world. steady_clock is monotonic, never set backwards, and is for measuring durations, timeouts and rate limits.

How do you timestamp events on the hot path cheaply?

Read the TSC with rdtsc, a few cycles on modern x86 with an invariant TSC, store the raw value, and convert to nanoseconds off the hot path using a calibration against the monotonic clock. Use rdtscp or fences when precise ordering around a short region matters.

How are clocks synchronised in a trading firm?

PTP from GPS-disciplined grandmasters through PTP-aware switches to the network cards' hardware clocks, with ptp4l and phc2sys keeping the card and system clocks in step, monitored continuously. That gives sub-microsecond accuracy, comfortably inside regulatory requirements such as MiFID II's 100 microseconds for high-frequency trading.