14e76af6aSGleb Smirnoff.\"- 24e76af6aSGleb Smirnoff.\" Copyright (c) 2013 Gleb Smirnoff <glebius@FreeBSD.org> 34e76af6aSGleb Smirnoff.\" All rights reserved. 44e76af6aSGleb Smirnoff.\" 54e76af6aSGleb Smirnoff.\" Redistribution and use in source and binary forms, with or without 64e76af6aSGleb Smirnoff.\" modification, are permitted provided that the following conditions 74e76af6aSGleb Smirnoff.\" are met: 84e76af6aSGleb Smirnoff.\" 1. Redistributions of source code must retain the above copyright 94e76af6aSGleb Smirnoff.\" notice, this list of conditions and the following disclaimer. 104e76af6aSGleb Smirnoff.\" 2. Redistributions in binary form must reproduce the above copyright 114e76af6aSGleb Smirnoff.\" notice, this list of conditions and the following disclaimer in the 124e76af6aSGleb Smirnoff.\" documentation and/or other materials provided with the distribution. 134e76af6aSGleb Smirnoff.\" 144e76af6aSGleb Smirnoff.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154e76af6aSGleb Smirnoff.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164e76af6aSGleb Smirnoff.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174e76af6aSGleb Smirnoff.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184e76af6aSGleb Smirnoff.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194e76af6aSGleb Smirnoff.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204e76af6aSGleb Smirnoff.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214e76af6aSGleb Smirnoff.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224e76af6aSGleb Smirnoff.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234e76af6aSGleb Smirnoff.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244e76af6aSGleb Smirnoff.\" SUCH DAMAGE. 254e76af6aSGleb Smirnoff.\" 26*1cd5c35dSKristof Provost.Dd June 19, 2025 274e76af6aSGleb Smirnoff.Dt COUNTER 9 284e76af6aSGleb Smirnoff.Os 294e76af6aSGleb Smirnoff.Sh NAME 304e76af6aSGleb Smirnoff.Nm counter 314e76af6aSGleb Smirnoff.Nd "SMP-friendly kernel counter implementation" 324e76af6aSGleb Smirnoff.Sh SYNOPSIS 334e76af6aSGleb Smirnoff.In sys/types.h 342d875db3SGleb Smirnoff.In sys/systm.h 354e76af6aSGleb Smirnoff.In sys/counter.h 364e76af6aSGleb Smirnoff.Ft counter_u64_t 374e76af6aSGleb Smirnoff.Fn counter_u64_alloc "int wait" 384e76af6aSGleb Smirnoff.Ft void 394e76af6aSGleb Smirnoff.Fn counter_u64_free "counter_u64_t c" 404e76af6aSGleb Smirnoff.Ft void 414e76af6aSGleb Smirnoff.Fn counter_u64_add "counter_u64_t c" "int64_t v" 424e76af6aSGleb Smirnoff.Ft void 434e76af6aSGleb Smirnoff.Fn counter_enter 444e76af6aSGleb Smirnoff.Ft void 454e76af6aSGleb Smirnoff.Fn counter_exit 464e76af6aSGleb Smirnoff.Ft void 474e76af6aSGleb Smirnoff.Fn counter_u64_add_protected "counter_u64_t c" "int64_t v" 484e76af6aSGleb Smirnoff.Ft uint64_t 494e76af6aSGleb Smirnoff.Fn counter_u64_fetch "counter_u64_t c" 504e76af6aSGleb Smirnoff.Ft void 514e76af6aSGleb Smirnoff.Fn counter_u64_zero "counter_u64_t c" 52*1cd5c35dSKristof Provost.Ft struct counter_rate * 53*1cd5c35dSKristof Provost.Fn counter_rate_alloc "int flags" "int period" 5416917020SGleb Smirnoff.Ft int64_t 5516917020SGleb Smirnoff.Fn counter_ratecheck "struct counter_rate *cr" "int64_t limit" 56*1cd5c35dSKristof Provost.Ft uint64_t 57*1cd5c35dSKristof Provost.Fn counter_rate_get "struct counter_rate *cr" 58*1cd5c35dSKristof Provost.Ft void 59*1cd5c35dSKristof Provost.Fn counter_rate_free "struct counter_rate *cr" 60fffcb56fSMark Johnston.Fn COUNTER_U64_SYSINIT "counter_u64_t c" 61fffcb56fSMark Johnston.Fn COUNTER_U64_DEFINE_EARLY "counter_u64_t c" 624e76af6aSGleb Smirnoff.In sys/sysctl.h 63369f5bceSGleb Smirnoff.Fn SYSCTL_COUNTER_U64 parent nbr name access ptr descr 644e76af6aSGleb Smirnoff.Fn SYSCTL_ADD_COUNTER_U64 ctx parent nbr name access ptr descr 65b5b7b142SGleb Smirnoff.Fn SYSCTL_COUNTER_U64_ARRAY parent nbr name access ptr len descr 66b5b7b142SGleb Smirnoff.Fn SYSCTL_ADD_COUNTER_U64_ARRAY ctx parent nbr name access ptr len descr 674e76af6aSGleb Smirnoff.Sh DESCRIPTION 684e76af6aSGleb Smirnoff.Nm 694e76af6aSGleb Smirnoffis a generic facility to create counters 704e76af6aSGleb Smirnoffthat can be utilized for any purpose (such as collecting statistical 714e76af6aSGleb Smirnoffdata). 724e76af6aSGleb SmirnoffA 734e76af6aSGleb Smirnoff.Nm 744e76af6aSGleb Smirnoffis guaranteed to be lossless when several kernel threads do simultaneous 754e76af6aSGleb Smirnoffupdates. 764e76af6aSGleb SmirnoffHowever, 774e76af6aSGleb Smirnoff.Nm 784e76af6aSGleb Smirnoffdoes not block the calling thread, 794e76af6aSGleb Smirnoffalso no 804e76af6aSGleb Smirnoff.Xr atomic 9 814e76af6aSGleb Smirnoffoperations are used for the update, therefore the counters 824e76af6aSGleb Smirnoffcan be used in any non-interrupt context. 834e76af6aSGleb SmirnoffMoreover, 844e76af6aSGleb Smirnoff.Nm 854e76af6aSGleb Smirnoffhas special optimisations for SMP environments, making 864e76af6aSGleb Smirnoff.Nm 874e76af6aSGleb Smirnoffupdate faster than simple arithmetic on the global variable. 884e76af6aSGleb SmirnoffThus 894e76af6aSGleb Smirnoff.Nm 904e76af6aSGleb Smirnoffis considered suitable for accounting in the performance-critical 917c64ddd5SWarren Blockcode paths. 924e76af6aSGleb Smirnoff.Bl -tag -width indent 93fa8175e4SBrad Davis.It Fn counter_u64_alloc wait 944e76af6aSGleb SmirnoffAllocate a new 64-bit unsigned counter. 954e76af6aSGleb SmirnoffThe 964e76af6aSGleb Smirnoff.Fa wait 974e76af6aSGleb Smirnoffargument is the 984e76af6aSGleb Smirnoff.Xr malloc 9 994e76af6aSGleb Smirnoffwait flag, should be either 1004e76af6aSGleb Smirnoff.Va M_NOWAIT 1014e76af6aSGleb Smirnoffor 1024e76af6aSGleb Smirnoff.Va M_WAITOK . 1034e76af6aSGleb SmirnoffIf 104c676e669SAlan Somers.Va M_NOWAIT 10551dc8e7fSKristof Provostis specified the operation may fail and return 10651dc8e7fSKristof Provost.Dv NULL . 1074e76af6aSGleb Smirnoff.It Fn counter_u64_free c 1084e76af6aSGleb SmirnoffFree the previously allocated counter 1094e76af6aSGleb Smirnoff.Fa c . 11051dc8e7fSKristof ProvostIt is safe to pass 11151dc8e7fSKristof Provost.Dv NULL . 1124e76af6aSGleb Smirnoff.It Fn counter_u64_add c v 1134e76af6aSGleb SmirnoffAdd 1144e76af6aSGleb Smirnoff.Fa v 1154e76af6aSGleb Smirnoffto 1164e76af6aSGleb Smirnoff.Fa c . 1174e76af6aSGleb SmirnoffThe KPI does not guarantee any protection from wraparound. 1184e76af6aSGleb Smirnoff.It Fn counter_enter 119640ca09dSEnji CooperEnter mode that would allow the safe update of several counters via 1204e76af6aSGleb Smirnoff.Fn counter_u64_add_protected . 1214e76af6aSGleb SmirnoffOn some machines this expands to 1224e76af6aSGleb Smirnoff.Xr critical 9 1234e76af6aSGleb Smirnoffsection, while on other is a nop. 1244e76af6aSGleb SmirnoffSee 1254e76af6aSGleb Smirnoff.Sx IMPLEMENTATION DETAILS . 1264e76af6aSGleb Smirnoff.It Fn counter_exit 1274e76af6aSGleb SmirnoffExit mode for updating several counters. 1284e76af6aSGleb Smirnoff.It Fn counter_u64_add_protected c v 1294e76af6aSGleb SmirnoffSame as 1304e76af6aSGleb Smirnoff.Fn counter_u64_add , 1314e76af6aSGleb Smirnoffbut should be preceded by 1324e76af6aSGleb Smirnoff.Fn counter_enter . 1334e76af6aSGleb Smirnoff.It Fn counter_u64_fetch c 1344e76af6aSGleb SmirnoffTake a snapshot of counter 1354e76af6aSGleb Smirnoff.Fa c . 1364e76af6aSGleb SmirnoffThe data obtained is not guaranteed to reflect the real cumulative 1374e76af6aSGleb Smirnoffvalue for any moment. 1384e76af6aSGleb Smirnoff.It Fn counter_u64_zero c 1394e76af6aSGleb SmirnoffClear the counter 1404e76af6aSGleb Smirnoff.Fa c 1414e76af6aSGleb Smirnoffand set it to zero. 142*1cd5c35dSKristof Provost.It Fn counter_rate_alloc flags period 143*1cd5c35dSKristof ProvostAllocate a new struct counter_rate. 144*1cd5c35dSKristof Provost.Fa flags 145*1cd5c35dSKristof Provostis passed to 146*1cd5c35dSKristof Provost.Xr malloc 9 . 147*1cd5c35dSKristof Provost.Fa period 148*1cd5c35dSKristof Provostis the time over which the rate is checked. 14916917020SGleb Smirnoff.It Fn counter_ratecheck cr limit 15016917020SGleb SmirnoffThe function is a multiprocessor-friendly version of 15199d528d4SDag-Erling Smørgrav.Fn ppsratecheck 15216917020SGleb Smirnoffwhich uses 15316917020SGleb Smirnoff.Nm 15416917020SGleb Smirnoffinternally. 155640ca09dSEnji CooperReturns non-negative value if the rate is not yet reached during the current 156*1cd5c35dSKristof Provostperiod, and a negative value otherwise. 157*1cd5c35dSKristof ProvostIf the limit was reached during the previous period, but was just reset back 158*1cd5c35dSKristof Provostto zero, then 15916917020SGleb Smirnoff.Fn counter_ratecheck 16016917020SGleb Smirnoffreturns number of events since previous reset. 161*1cd5c35dSKristof Provost.It Fn counter_rate_get cr 162*1cd5c35dSKristof ProvostThe number of hits to this check within the current period. 163*1cd5c35dSKristof Provost.It Fn counter_rate_free cr 164*1cd5c35dSKristof ProvostFree the 165*1cd5c35dSKristof Provost.Fa cr 166*1cd5c35dSKristof Provostcounter. 167fffcb56fSMark Johnston.It Fn COUNTER_U64_SYSINIT c 168fffcb56fSMark JohnstonDefine a 169fffcb56fSMark Johnston.Xr SYSINIT 9 170fffcb56fSMark Johnstoninitializer for the global counter 171fffcb56fSMark Johnston.Fa c . 172fffcb56fSMark Johnston.It Fn COUNTER_U64_DEFINE_EARLY c 173fffcb56fSMark JohnstonDefine and initialize a global counter 174fffcb56fSMark Johnston.Fa c . 175fffcb56fSMark JohnstonIt is always safe to increment 176fffcb56fSMark Johnston.Fa c , 177fffcb56fSMark Johnstonthough updates prior to the 178fffcb56fSMark Johnston.Dv SI_SUB_COUNTER 179fffcb56fSMark Johnston.Xr SYSINIT 9 180fffcb56fSMark Johnstonevent are lost. 181369f5bceSGleb Smirnoff.It Fn SYSCTL_COUNTER_U64 parent nbr name access ptr descr 1824e76af6aSGleb SmirnoffDeclare a static 183640ca09dSEnji Cooper.Xr sysctl 9 1844e76af6aSGleb Smirnoffoid that would represent a 1854e76af6aSGleb Smirnoff.Nm . 1864e76af6aSGleb SmirnoffThe 1874e76af6aSGleb Smirnoff.Fa ptr 1884e76af6aSGleb Smirnoffargument should be a pointer to allocated 1894e76af6aSGleb Smirnoff.Vt counter_u64_t . 1904e76af6aSGleb SmirnoffA read of the oid returns value obtained through 1914e76af6aSGleb Smirnoff.Fn counter_u64_fetch . 1924e76af6aSGleb SmirnoffAny write to the oid zeroes it. 1934e76af6aSGleb Smirnoff.It Fn SYSCTL_ADD_COUNTER_U64 ctx parent nbr name access ptr descr 1944e76af6aSGleb SmirnoffCreate a 195640ca09dSEnji Cooper.Xr sysctl 9 1964e76af6aSGleb Smirnoffoid that would represent a 1974e76af6aSGleb Smirnoff.Nm . 1984e76af6aSGleb SmirnoffThe 1994e76af6aSGleb Smirnoff.Fa ptr 2004e76af6aSGleb Smirnoffargument should be a pointer to allocated 2014e76af6aSGleb Smirnoff.Vt counter_u64_t . 2024e76af6aSGleb SmirnoffA read of the oid returns value obtained through 2034e76af6aSGleb Smirnoff.Fn counter_u64_fetch . 2044e76af6aSGleb SmirnoffAny write to the oid zeroes it. 205b5b7b142SGleb Smirnoff.It Fn SYSCTL_COUNTER_U64_ARRAY parent nbr name access ptr len descr 206b5b7b142SGleb SmirnoffDeclare a static 207640ca09dSEnji Cooper.Xr sysctl 9 208b5b7b142SGleb Smirnoffoid that would represent an array of 209b5b7b142SGleb Smirnoff.Nm . 210b5b7b142SGleb SmirnoffThe 211b5b7b142SGleb Smirnoff.Fa ptr 212b5b7b142SGleb Smirnoffargument should be a pointer to allocated array of 213b5b7b142SGleb Smirnoff.Vt counter_u64_t's . 214b5b7b142SGleb SmirnoffThe 215b5b7b142SGleb Smirnoff.Fa len 216b5b7b142SGleb Smirnoffargument should specify number of elements in the array. 217b5b7b142SGleb SmirnoffA read of the oid returns len-sized array of 218b5b7b142SGleb Smirnoff.Vt uint64_t 219b5b7b142SGleb Smirnoffvalues obtained through 220b5b7b142SGleb Smirnoff.Fn counter_u64_fetch . 221b5b7b142SGleb SmirnoffAny write to the oid zeroes all array elements. 222b5b7b142SGleb Smirnoff.It Fn SYSCTL_ADD_COUNTER_U64_ARRAY ctx parent nbr name access ptr len descr 223b5b7b142SGleb SmirnoffCreate a 224640ca09dSEnji Cooper.Xr sysctl 9 225b5b7b142SGleb Smirnoffoid that would represent an array of 226b5b7b142SGleb Smirnoff.Nm . 227b5b7b142SGleb SmirnoffThe 228b5b7b142SGleb Smirnoff.Fa ptr 229b5b7b142SGleb Smirnoffargument should be a pointer to allocated array of 230b5b7b142SGleb Smirnoff.Vt counter_u64_t's . 231b5b7b142SGleb SmirnoffThe 232b5b7b142SGleb Smirnoff.Fa len 233b5b7b142SGleb Smirnoffargument should specify number of elements in the array. 234b5b7b142SGleb SmirnoffA read of the oid returns len-sized array of 235b5b7b142SGleb Smirnoff.Vt uint64_t 236b5b7b142SGleb Smirnoffvalues obtained through 237b5b7b142SGleb Smirnoff.Fn counter_u64_fetch . 238b5b7b142SGleb SmirnoffAny write to the oid zeroes all array elements. 2394e76af6aSGleb Smirnoff.El 2404e76af6aSGleb Smirnoff.Sh IMPLEMENTATION DETAILS 2414e76af6aSGleb SmirnoffOn all architectures 2424e76af6aSGleb Smirnoff.Nm 2434e76af6aSGleb Smirnoffis implemented using per-CPU data fields that are specially aligned 2444e76af6aSGleb Smirnoffin memory, to avoid inter-CPU bus traffic due to shared use 2454e76af6aSGleb Smirnoffof the variables between CPUs. 2464e76af6aSGleb SmirnoffThese are allocated using 2474e76af6aSGleb Smirnoff.Va UMA_ZONE_PCPU 2484e76af6aSGleb Smirnoff.Xr uma 9 2494e76af6aSGleb Smirnoffzone. 2504e76af6aSGleb SmirnoffThe update operation only touches the field that is private to current CPU. 2514e76af6aSGleb SmirnoffFetch operation loops through all per-CPU fields and obtains a snapshot 2524e76af6aSGleb Smirnoffsum of all fields. 2534e76af6aSGleb Smirnoff.Pp 2544e76af6aSGleb SmirnoffOn amd64 a 2554e76af6aSGleb Smirnoff.Nm counter 2564e76af6aSGleb Smirnoffupdate is implemented as a single instruction without lock semantics, 2574e76af6aSGleb Smirnoffoperating on the private data for the current CPU, 2584e76af6aSGleb Smirnoffwhich is safe against preemption and interrupts. 2594e76af6aSGleb Smirnoff.Pp 2604e76af6aSGleb SmirnoffOn i386 architecture, when machine supports the cmpxchg8 instruction, 2614e76af6aSGleb Smirnoffthis instruction is used. 2624e76af6aSGleb SmirnoffThe multi-instruction sequence provides the same guarantees as the 2634e76af6aSGleb Smirnoffamd64 single-instruction implementation. 2644e76af6aSGleb Smirnoff.Pp 2654e76af6aSGleb SmirnoffOn some architectures updating a counter require a 2664e76af6aSGleb Smirnoff.Xr critical 9 2674e76af6aSGleb Smirnoffsection. 268a435d46fSHans Petter Selasky.Sh EXAMPLES 269a435d46fSHans Petter SelaskyThe following example creates a static counter array exported to 270a435d46fSHans Petter Selaskyuserspace through a sysctl: 271a435d46fSHans Petter Selasky.Bd -literal -offset indent 272a435d46fSHans Petter Selasky#define MY_SIZE 8 273a435d46fSHans Petter Selaskystatic counter_u64_t array[MY_SIZE]; 274a435d46fSHans Petter SelaskySYSCTL_COUNTER_U64_ARRAY(_debug, OID_AUTO, counter_array, CTLFLAG_RW, 275a435d46fSHans Petter Selasky &array[0], MY_SIZE, "Test counter array"); 276a435d46fSHans Petter Selasky.Ed 2774e76af6aSGleb Smirnoff.Sh SEE ALSO 2784e76af6aSGleb Smirnoff.Xr atomic 9 , 2794e76af6aSGleb Smirnoff.Xr critical 9 , 2804e76af6aSGleb Smirnoff.Xr locking 9 , 2814e76af6aSGleb Smirnoff.Xr malloc 9 , 28299d528d4SDag-Erling Smørgrav.Xr ratecheck 9 , 2834e76af6aSGleb Smirnoff.Xr sysctl 9 , 284fffcb56fSMark Johnston.Xr SYSINIT 9 , 2854e76af6aSGleb Smirnoff.Xr uma 9 2864e76af6aSGleb Smirnoff.Sh HISTORY 2874e76af6aSGleb SmirnoffThe 2884e76af6aSGleb Smirnoff.Nm 2894e76af6aSGleb Smirnofffacility first appeared in 2904e76af6aSGleb Smirnoff.Fx 10.0 . 2914e76af6aSGleb Smirnoff.Sh AUTHORS 2924e76af6aSGleb Smirnoff.An -nosplit 2934e76af6aSGleb SmirnoffThe 2944e76af6aSGleb Smirnoff.Nm 2954e76af6aSGleb Smirnofffacility was written by 2964e76af6aSGleb Smirnoff.An Gleb Smirnoff 2974e76af6aSGleb Smirnoffand 2984e76af6aSGleb Smirnoff.An Konstantin Belousov . 299