xtc_stats(3)

---

xtc_stats(3)

runtime statistics: counters, gauges, histograms

XTC_STATS(3) Library Functions Manual XTC_STATS(3)

xtc_counter_create, xtc_counter_inc, xtc_counter_add, xtc_counter_read, xtc_counter_destroy, xtc_gauge_create, xtc_gauge_set, xtc_gauge_add, xtc_gauge_read, xtc_gauge_destroy, xtc_hist_create, xtc_hist_record, xtc_hist_quantile, xtc_hist_count, xtc_hist_destroy, xtc_metrics_iterate, xtc_metrics_dump_prometheusruntime statistics: counters, gauges, histograms

#include <xtc.h>
#include <xtc_stats.h>

int
xtc_counter_create(const char *name, xtc_counter_t **out);

void
xtc_counter_inc(xtc_counter_t *c);

void
xtc_counter_add(xtc_counter_t *c, int64_t delta);

uint64_t
xtc_counter_read(const xtc_counter_t *c);

void
xtc_counter_destroy(xtc_counter_t *c);

int
xtc_gauge_create(const char *name, xtc_gauge_t **out);

void
xtc_gauge_set(xtc_gauge_t *g, int64_t v);

int64_t
xtc_gauge_read(const xtc_gauge_t *g);

void
xtc_gauge_destroy(xtc_gauge_t *g);

int
xtc_hist_create(const char *name, xtc_hist_t **out);

void
xtc_hist_record(xtc_hist_t *h, int64_t value_ns);

int64_t
xtc_hist_quantile(const xtc_hist_t *h, double q);

void
xtc_hist_destroy(xtc_hist_t *h);

int
xtc_metrics_iterate(xtc_metric_visit_fn fn, void *user);

int
xtc_metrics_dump_prometheus(int fd);

xtc_stats is the runtime telemetry layer. Three metric kinds:

counter
Monotonic non-negative count (requests served, errors observed).
gauge
Current value, can move up or down (active connections, queue depth).
histogram
Distribution; supports quantile queries (p50, p99, p999). For latency tracking.

:

  • Counters are : () hits one cache-line-isolated atomic on the calling CPU. No cross-CPU coherence traffic on the hot path. Reads sum all shards.
  • Gauges are a single _Atomic int64_t. For low-frequency-update gauges this is fine; high-frequency gauges should be modeled as a counter pair instead.
  • Histograms are per-CPU sharded (one log-linear bucket array per CPU); () hits one shard's atomic counter. () merges shards under no lock (relaxed atomic loads).

: the implementation is designed not to obscure observability tools. Updating a counter compiles to one CPU-shard sched_getcpu (cached in TLS) plus one atomic_fetch_add; under perf-stat(1) this shows up as the program's CPU pattern, not as overhead in the telemetry layer.

(), (), () register the metric in a global registry keyed by name (up to 64 chars). The matching (), (), and () unregister and free a metric. The registry supports walking via () or dumping in Prometheus exposition format via () to a file descriptor.

xtc_counter_t *requests;
xtc_hist_t    *latency;

xtc_counter_create("rexis.requests", &requests);
xtc_hist_create  ("rexis.req_latency_ns", &latency);

/* Hot path: */
int64_t t0 = now_ns();
handle_request();
xtc_counter_inc(requests);
xtc_hist_record(latency, now_ns() - t0);

/* Periodic dump (e.g. via xtc_timer): */
xtc_metrics_dump_prometheus(scrape_fd);

xtc_metrics_dump_prometheus() emits, for each metric:

# TYPE rexis.requests counter
rexis.requests 12345
# TYPE rexis.queue_depth gauge
rexis.queue_depth 42
# TYPE rexis.req_latency_ns histogram
rexis.req_latency_ns_count 12345
rexis.req_latency_ns_p50 1500
rexis.req_latency_ns_p99 9800
rexis.req_latency_ns_p999 24000

A trivial scrape server reads fd and forwards to HTTP. See examples/05_rexis/metrics.c for an example dump-on-timer pattern.

xtc_log(3), xtc_cfg(3), xtc(7), perf-stat(1)

Appeared in xtc 0.1.

May 28, 2026 Debian

View the mdoc source