COUNTER(9)

πŸ“¦ version 15.1, in freebsd 15.1

πŸ’– COUNTER(9) β€” SMP-friendly kernel counter realness πŸ’–

okay so bestie, this is the Kernel Developer's Manual page for counter, and it is literally the β€œSMP-friendly kernel counter implementation.” no cap, every function and flag is staying right here. ✨


🌸 NAME 🌸

counter β€” SMP-friendly kernel counter implementation

πŸ¦‹ SYNOPSIS πŸ¦‹

#include <sys/types.h>
#include <sys/systm.h>
#include <sys/counter.h>

counter_u64_t
counter_u64_alloc(int wait);

void
counter_u64_free(counter_u64_t c);

void
counter_u64_add(counter_u64_t c, int64_t v);

void
counter_enter();

void
counter_exit();

void
counter_u64_add_protected(counter_u64_t c, int64_t v);

uint64_t
counter_u64_fetch(counter_u64_t c);

void
counter_u64_zero(counter_u64_t c);

struct counter_rate *
counter_rate_alloc(int flags, int period);

int64_t
counter_ratecheck(struct counter_rate *cr, int64_t limit);

uint64_t
counter_rate_get(struct counter_rate *cr);

void
counter_rate_free(struct counter_rate *cr);

COUNTER_U64_SYSINIT(counter_u64_t c);

COUNTER_U64_DEFINE_EARLY(counter_u64_t c);

#include <sys/sysctl.h>

SYSCTL_COUNTER_U64(parent, nbr, name, access, ptr, descr);

SYSCTL_ADD_COUNTER_U64(ctx, parent, nbr, name, access, ptr, descr);

SYSCTL_COUNTER_U64_ARRAY(parent, nbr, name, access, ptr, len, descr);

SYSCTL_ADD_COUNTER_U64_ARRAY(ctx, parent, nbr, name, access, ptr, len,
    descr);

πŸ’… DESCRIPTION πŸ’…

counter is a generic facility to create counters that can be used for any purpose β€” collecting statistical data is the classic vibe. A counter is guaranteed to be lossless when several kernel threads do simultaneous updates. 🫢

But here's the important part, bestie: counter does not block the calling thread, and no atomic(9) operations are used for the update. So the counters can be used in any non-interrupt context. ✨

Moreover, counter has special optimisations for SMP environments, making counter update faster than simple arithmetic on the global variable. Thus counter is considered suitable for accounting in the performance-critical code paths. πŸ”₯

  • counter_u64_alloc(wait) β€” Allocate a new 64-bit unsigned counter. The wait argument is the malloc(9) wait flag, should be either M_NOWAIT or M_WAITOK. If M_NOWAIT is specified the operation may fail and return NULL. 😭
  • counter_u64_free(c) β€” Free the previously allocated counter c. It is safe to pass NULL. 🧚
  • counter_u64_add(c, v) β€” Add v to c. The KPI does not guarantee any protection from wraparound β€” so don't come expecting wraparound protection, because it is literally not promised. πŸ’€
  • counter_enter() β€” Enter mode that would allow the safe update of several counters via counter_u64_add_protected(). On some machines this expands to critical(9) section, while on other is a nop. See β€œIMPLEMENTATION DETAILS”. πŸŽ€
  • counter_exit() β€” Exit mode for updating several counters. 🌈
  • counter_u64_add_protected(c, v) β€” Same as counter_u64_add(), but should be preceded by counter_enter(). πŸ‘‘
  • counter_u64_fetch(c) β€” Take a snapshot of counter c. The data obtained is not guaranteed to reflect the real cumulative value for any moment. πŸ™ˆ
  • counter_u64_zero(c) β€” Clear the counter c and set it to zero. ✨
  • counter_rate_alloc(flags, period) β€” Allocate a new struct counter_rate. flags is passed to malloc(9). period is the time over which the rate is checked. πŸ¦‹
  • counter_ratecheck(cr, limit) β€” The function is a multiprocessor-friendly version of ppsratecheck() which uses counter internally. Returns non-negative value if the rate is not yet reached during the current period, and a negative value otherwise. If the limit was reached during the previous period, but was just reset back to zero, then counter_ratecheck() returns number of events since previous reset. πŸ”₯
  • counter_rate_get(cr) β€” The number of hits to this check within the current period. ⭐
  • counter_rate_free(cr) β€” Free the cr counter. πŸŽ€
  • COUNTER_U64_SYSINIT(c) β€” Define a SYSINIT(9) initializer for the global counter c. πŸ’œ
  • COUNTER_U64_DEFINE_EARLY(c) β€” Define and initialize a global counter c. It is always safe to increment c, though updates prior to the SI_SUB_COUNTER SYSINIT(9) event are lost. 😭
  • SYSCTL_COUNTER_U64(parent, nbr, name, access, ptr, descr) β€” Declare a static sysctl(9) oid that would represent a counter. The ptr argument should be a pointer to allocated counter_u64_t. A read of the oid returns value obtained through counter_u64_fetch(). Any write to the oid zeroes it. 🫢
  • SYSCTL_ADD_COUNTER_U64(ctx, parent, nbr, name, access, ptr, descr) β€” Create a sysctl(9) oid that would represent a counter. The ptr argument should be a pointer to allocated counter_u64_t. A read of the oid returns value obtained through counter_u64_fetch(). Any write to the oid zeroes it. 🌸
  • SYSCTL_COUNTER_U64_ARRAY(parent, nbr, name, access, ptr, len, descr) β€” Declare a static sysctl(9) oid that would represent an array of counter. The ptr argument should be a pointer to allocated array of counter_u64_t's. The len argument should specify number of elements in the array. A read of the oid returns len-sized array of uint64_t values obtained through counter_u64_fetch(). Any write to the oid zeroes all array elements. πŸ¦‹
  • SYSCTL_ADD_COUNTER_U64_ARRAY(ctx, parent, nbr, name, access, ptr, len, descr) β€” Create a sysctl(9) oid that would represent an array of counter. The ptr argument should be a pointer to allocated array of counter_u64_t's. The len argument should specify number of elements in the array. A read of the oid returns len-sized array of uint64_t values obtained through counter_u64_fetch(). Any write to the oid zeroes all array elements. πŸ’–

🧚 IMPLEMENTATION DETAILS 🧚

On all architectures counter is implemented using per-CPU data fields that are specially aligned in memory, to avoid inter-CPU bus traffic due to shared use of the variables between CPUs. These are allocated using UMA_ZONE_PCPU uma(9) zone. The update operation only touches the field that is private to current CPU. Fetch operation loops through all per-CPU fields and obtains a snapshot sum of all fields. 🌈

  • On amd64 a counter update is implemented as a single instruction without lock semantics, operating on the private data for the current CPU, which is safe against preemption and interrupts. πŸ”₯
  • On i386 architecture, when machine supports the cmpxchg8 instruction, this instruction is used. The multi-instruction sequence provides the same guarantees as the amd64 single-instruction implementation. ⭐
  • On some architectures updating a counter require a critical(9) section. πŸ’…

πŸŽ€ EXAMPLES πŸŽ€

The following example creates a static counter array exported to userspace through a sysctl:

#define MY_SIZE 8
static counter_u64_t array[MY_SIZE];
SYSCTL_COUNTER_U64_ARRAY(_debug, OID_AUTO, counter_array, CTLFLAG_RW,
    &array[0], MY_SIZE, "Test counter array");

🌟 SEE ALSO 🌟

πŸ¦‹ HISTORY πŸ¦‹

The counter facility first appeared in FreeBSD 10.0. πŸ‘‘

πŸ’œ AUTHORS πŸ’œ

The counter facility was written by Gleb Smirnoff and Konstantin Belousov. 🫢


πŸ’– That's the whole page, bestie β€” source/version is Debian, dated June 19, 2025, and the manpage tag is COUNTER(9). πŸŽ€

πŸ“¦ where this page comes from
  • freebsd 15.1: base 15.1
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms