|
| static uint64_t | latrec_now_ns (void) |
| static uint64_t | latrec_real_ns (void) |
| static void | latrec_refresh_cpu (latrec_t *r) |
| static uint32_t | latrec_measure_clock_ns (void) |
| static int | latrec_open_in (latrec_t *r, const char *dir, const char *name, unsigned entries_log2) |
| static int | latrec_open (latrec_t *r, const char *name, unsigned entries_log2) |
| static void | latrec_stamp_at (latrec_t *r, uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2, uint64_t t_ns) |
| static void | latrec_stamp (latrec_t *r, uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2) |
| static void | latrec_heartbeat (latrec_t *r) |
| static void | latrec_close (latrec_t *r) |
| static void | latrec_set_output_dir (const char *dir) |
| static latrec_t * | latrec_tls_open_as (const char *role) |
| static latrec_t * | latrec_tls_open (void) |
| static uint64_t | latrec_seq_next (void) |
| static void | latrec_tstamp (uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2) |
| static void | latrec_tstamp_at (uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2, uint64_t t_ns) |
| static uint64_t | latrec_tnow (void) |
| static void | latrec_ctx_set (uint64_t seq) |
| static uint64_t | latrec_ctx (void) |
Lock-free per-thread latency stamp recorder (header-only, C99).
One mmap-backed ring per writer thread, single producer, no locks: a stamp is one CLOCK_MONOTONIC read and four stores, with no syscall, allocation or formatting. Records are 32 bytes (seq:48 | cpu:8 | stage:8, t_ns, aux, aux2); seq is assigned once at the producer and joins the stages offline, aux/aux2 carry the per-stage payloads listed in the stage catalog below.
CLOCK_MONOTONIC shares an origin across processes, so RAN, dApp and xApp stamps join without calibration.
t_ns is stored last, with release ordering: a reader that acquire-loads a nonzero t_ns also observes that record's sc, aux and aux2. That makes one record self-consistent; it does not stop the slot being reused, so a reader of a ring that has wrapped may pair one write's t_ns with the next write's payload. A live reader must therefore keep up, or detect the wrap from rec_count and the single descent in t_ns.
Gated once, at compile time, by LIBE3_ENABLE_LATREC: off by default, so a normal build carries none of this, not even a disabled-ring branch. With it on, tracing runs – there is no second per-run opt-in. See the bottom of this file, and docs/latrec.md for where the rings are written.
File layout: a 4 KiB latrec_hdr followed by entries 32-byte records. v1 field offsets are frozen and v2 fields appended inside the header pad, so a v1 reader parses a v2 file. Readers detect a byte-swapped LATREC_MAGIC. 64-bit hosts only: a 32-bit host can tear the t_ns store.
Installed as <libe3/latrec.h>, so a component that links libe3 includes it from there. Components that do not link libe3 mirror the layout instead, and the stage catalog below carries their ids too, so it stays the one place a new id is checked for collisions.
- See also
- docs/latrec.md for the full guide: the clock model, ring naming/sizing, the stage catalog table, and the capture-to-CSV workflow.
-
docs/path-a-e3-loop.md and docs/path-b-e2-e3-loop.md for the loop boxes the stage catalog names.
SPDX-FileCopyrightText: Copyright (c) 2026 Northeastern University SPDX-License-Identifier: Apache-2.0
Definition in file latrec.h.