54#if !defined(_GNU_SOURCE) && !defined(_POSIX_C_SOURCE) && \
55 !defined(_DEFAULT_SOURCE) && !defined(_XOPEN_SOURCE)
69#if !defined(CLOCK_MONOTONIC)
70#error "latrec.h: CLOCK_MONOTONIC undeclared - build with a POSIX-enabled dialect (-std=gnu11 / -std=gnu++17) or define _POSIX_C_SOURCE >= 199309L before any system header."
79#if defined(__GNUC__) || defined(__clang__)
80#define LATREC_STORE_RELEASE(p, v) __atomic_store_n((p), (v), __ATOMIC_RELEASE)
81#define LATREC_LOAD_ACQUIRE(p) __atomic_load_n((p), __ATOMIC_ACQUIRE)
82#define LATREC_PREFETCH_W(p) __builtin_prefetch((p), 1, 0)
83#define LATREC_UNLIKELY(x) __builtin_expect(!!(x), 0)
86#define LATREC_STORE_RELEASE(p, v) do { *(p) = (v); } while (0)
87#define LATREC_LOAD_ACQUIRE(p) (*(p))
88#define LATREC_PREFETCH_W(p) ((void)(p))
89#define LATREC_UNLIKELY(x) (x)
93#define LATREC_HAVE_GETCPU 1
98#if defined(__cplusplus)
99extern int sched_getcpu(
void)
noexcept;
101extern int sched_getcpu(
void);
104#define LATREC_HAVE_GETCPU 0
110#if LATREC_HAVE_GETCPU && (defined(__x86_64__) || defined(__i386__))
111#define LATREC_CPUID_ON_STAMP 1
113#define LATREC_CPUID_ON_STAMP 0
116#define LATREC_CAT_(a, b) a##b
117#define LATREC_CAT(a, b) LATREC_CAT_(a, b)
118#if defined(__cplusplus)
119#define LATREC_STATIC_ASSERT(c, m) static_assert(c, m)
120#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
121#define LATREC_STATIC_ASSERT(c, m) _Static_assert(c, m)
123#define LATREC_STATIC_ASSERT(c, m) \
124 typedef char LATREC_CAT(latrec_static_assert_, __LINE__)[(c) ? 1 : -1]
371#define LATREC_MAGIC 0x31524C41u
372#define LATREC_VERSION 2u
373#define LATREC_HDR_LEN 4096
377#define LATREC_CLOCK_SLOW_NS 100u
422 clock_gettime(CLOCK_MONOTONIC, &ts);
423 return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec;
429 clock_gettime(CLOCK_REALTIME, &ts);
430 return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec;
437#if LATREC_HAVE_GETCPU
438 const int cpu = sched_getcpu();
439 if (cpu >= 0) r->
cpu = (uint32_t)cpu;
449 enum { ITERS = 1000 };
454 if (sink == 0 || t1 <= t0)
return 0;
455 return (uint32_t)((t1 - t0) / (uint64_t)ITERS);
462#ifndef LATREC_DEFAULT_DIR
463#define LATREC_DEFAULT_DIR "/tmp/latrec"
478 memset(r, 0,
sizeof(*r));
487 char path[512], tmp[520];
488 snprintf(path,
sizeof(path),
"%s/%s.latrec", dir, name);
489 snprintf(tmp,
sizeof(tmp),
"%s.part", path);
490 int fd = open(tmp, O_CREAT | O_RDWR | O_TRUNC, 0644);
491 if (fd < 0)
return -1;
492 if (ftruncate(fd, (off_t)len) != 0) { close(fd); unlink(tmp);
return -1; }
493 void* map = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
495 if (map == MAP_FAILED) { unlink(tmp);
return -1; }
510 snprintf(h->
name,
sizeof(h->
name),
"%s", name);
511 if (rename(tmp, path) != 0) { munmap(map, len); unlink(tmp);
return -1; }
514 r->
mask = entries - 1;
522 "[latrec] WARNING %s: CLOCK_MONOTONIC costs %u ns/call; the vDSO "
523 "is unavailable (check the clocksource)\n", name, clock_ns);
546 uint64_t aux, uint64_t aux2, uint64_t t_ns)
549 const uint64_t i = r->
idx++;
551#if LATREC_CPUID_ON_STAMP
552 const uint64_t cpu = (uint64_t)(
unsigned)sched_getcpu();
554 const uint64_t cpu = (uint64_t)r->
cpu;
556 rec->
sc = (seq & 0x0000FFFFFFFFFFFFull)
557 | ((cpu & 0xFFull) << 48)
558 | ((uint64_t)stage << 56);
575 uint64_t aux, uint64_t aux2)
605#ifdef LIBE3_ENABLE_LATREC
633static inline void latrec_tstamp_at(uint64_t seq, uint8_t stage, uint64_t aux,
634 uint64_t aux2, uint64_t t_ns)
646static inline void latrec_tstamp(uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2)
685static inline void latrec_tstamp(uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2)
687 (void)seq; (void)stage; (void)aux; (void)aux2;
690 uint64_t aux2, uint64_t t_ns)
692 (void)seq; (void)stage; (void)aux; (void)aux2; (void)t_ns;
static unsigned entries_log2(const char *role)
__thread latrec_t * latrec_tls
static void latrec_tstamp(uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2)
static uint64_t latrec_tnow(void)
static void latrec_ctx_set(uint64_t seq)
static void latrec_set_output_dir(const char *dir)
static int latrec_open_in(latrec_t *r, const char *dir, const char *name, unsigned entries_log2)
#define LATREC_STATIC_ASSERT(c, m)
static uint64_t latrec_seq_next(void)
static latrec_t * latrec_tls_open(void)
static void latrec_heartbeat(latrec_t *r)
static void latrec_tstamp_at(uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2, uint64_t t_ns)
static uint32_t latrec_measure_clock_ns(void)
static uint64_t latrec_now_ns(void)
@ LATREC_DECODE_E2SM_BEGIN
@ LATREC_DECODE_E2AP_BEGIN
@ LATREC_ENCODE_E3SM_DONE
@ LATREC_ENCODE_E2AP_BEGIN
@ LATREC_DECODE_E2SM_DONE
@ LATREC_DECODE_E3SM_DONE
@ LATREC_DECODE_E2AP_DONE
@ LATREC_ENCODE_E3AP_DONE
@ LATREC_DECODE_E3AP_DONE
@ LATREC_DECODE_E3SM_BEGIN
@ LATREC_ENCODE_E3SM_BEGIN
@ LATREC_APPLY_CONTROL_DONE
@ LATREC_ENCODE_E2SM_DONE
@ LATREC_XAPP_PROCESS_DONE
@ LATREC_APPLY_POLICY_DONE
@ LATREC_ENCODE_E2AP_DONE
@ LATREC_ENCODE_E2SM_BEGIN
static uint64_t latrec_ctx(void)
static void latrec_close(latrec_t *r)
#define LATREC_STORE_RELEASE(p, v)
#define LATREC_DEFAULT_DIR
static void latrec_refresh_cpu(latrec_t *r)
#define LATREC_UNLIKELY(x)
static uint64_t latrec_real_ns(void)
#define LATREC_PREFETCH_W(p)
static int latrec_open(latrec_t *r, const char *name, unsigned entries_log2)
static void latrec_stamp(latrec_t *r, uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2)
#define LATREC_CLOCK_SLOW_NS
static latrec_t * latrec_tls_open_as(const char *role)
@ LATREC_DROP_SESSION_QUEUE
@ LATREC_DROP_REPORT_QUEUE
@ LATREC_SKIP_RANGES_LOST
@ LATREC_SKIP_NO_SUBSCRIBERS
static void latrec_stamp_at(latrec_t *r, uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2, uint64_t t_ns)
uint8_t pad[4096 - 4 *4 - 8 *6 - 64]
uint32_t clock_ns_per_call