1*bf0d449cSmpi.\" $OpenBSD: counters_alloc.9,v 1.13 2023/09/16 09:33:28 mpi Exp $ 27d79044fSdlg.\" 37d79044fSdlg.\" Copyright (c) 2016 David Gwynne <dlg@openbsd.org> 47d79044fSdlg.\" 57d79044fSdlg.\" Permission to use, copy, modify, and distribute this software for any 67d79044fSdlg.\" purpose with or without fee is hereby granted, provided that the above 77d79044fSdlg.\" copyright notice and this permission notice appear in all copies. 87d79044fSdlg.\" 97d79044fSdlg.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 107d79044fSdlg.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 117d79044fSdlg.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 127d79044fSdlg.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 137d79044fSdlg.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 147d79044fSdlg.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 157d79044fSdlg.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 167d79044fSdlg.\" 17*bf0d449cSmpi.Dd $Mdocdate: September 16 2023 $ 187d79044fSdlg.Dt COUNTERS_ALLOC 9 197d79044fSdlg.Os 207d79044fSdlg.Sh NAME 217d79044fSdlg.Nm counters_alloc , 227d79044fSdlg.Nm counters_free , 2357d14348Sdlg.Nm COUNTERS_BOOT_MEMORY , 2457d14348Sdlg.Nm COUNTERS_BOOT_INITIALIZER , 2557d14348Sdlg.Nm counters_alloc_ncpus , 267d79044fSdlg.Nm counters_enter , 277d79044fSdlg.Nm counters_leave , 2834b3a856Sdlg.Nm counters_inc , 2934b3a856Sdlg.Nm counters_add , 3034b3a856Sdlg.Nm counters_pkt , 317d79044fSdlg.Nm counters_read , 3256e6bab0Sjmc.Nm counters_zero 337d79044fSdlg.Nd per CPU counters 347d79044fSdlg.Sh SYNOPSIS 357d79044fSdlg.In sys/percpu.h 367d79044fSdlg.Ft struct cpumem * 37f01a839dSjca.Fn counters_alloc "unsigned int ncounters" 387d79044fSdlg.Ft void 39f01a839dSjca.Fn counters_free "struct cpumem *cm" "unsigned int ncounters" 4057d14348Sdlg.Fn COUNTERS_BOOT_MEMORY "NAME" "unsigned int ncounters" 4157d14348Sdlg.Fn COUNTERS_BOOT_INITIALIZER "NAME" 4257d14348Sdlg.Ft struct cpumemt * 4357d14348Sdlg.Fo counters_alloc_ncpus 4457d14348Sdlg.Fa "struct cpumem *cm" 4557d14348Sdlg.Fa "unsigned int ncounters" 4657d14348Sdlg.Fc 477d79044fSdlg.Ft uint64_t * 487d79044fSdlg.Fn counters_enter "struct counters_ref *ref" "struct cpumem *cm" 497d79044fSdlg.Ft void 507d79044fSdlg.Fn counters_leave "struct counters_ref *ref" "struct cpumem *cm" 517d79044fSdlg.Ft void 5234b3a856Sdlg.Fn counters_inc "struct cpumem *cm" "unsigned int counter" 5334b3a856Sdlg.Ft void 5434b3a856Sdlg.Fn counters_add "struct cpumem *cm" "unsigned int counter" "uint64_t v" 5534b3a856Sdlg.Ft void 5634b3a856Sdlg.Fo counters_pkt 5734b3a856Sdlg.Fa "struct cpumem *cm" 5834b3a856Sdlg.Fa "unsigned int pcounter" 5934b3a856Sdlg.Fa "unsigned int bcounter" 6034b3a856Sdlg.Fa "uint64_t bytes" 6134b3a856Sdlg.Fc 6234b3a856Sdlg.Ft void 637d79044fSdlg.Fo counters_read 647d79044fSdlg.Fa "struct cpumem *cm" 657d79044fSdlg.Fa "uint64_t *counters" 667d79044fSdlg.Fa "unsigned int ncounters" 67*bf0d449cSmpi.Fa "uint64_t *scratch" 687d79044fSdlg.Fc 697d79044fSdlg.Ft void 707d79044fSdlg.Fn counters_zero "struct cpumem *cm" "unsigned int ncounters" 717d79044fSdlg.Sh DESCRIPTION 727d79044fSdlgThe per CPU counter API builds on the per CPU memory API and provides 737d79044fSdlgaccess to a series of uint64_t counter values on each CPU. 747d79044fSdlg.Pp 757d79044fSdlgThe API provides versioning of counter updates without using 767d79044fSdlginterlocked CPU instructions so they can all be read in a consistent 777d79044fSdlgstate. 787d79044fSdlgUpdates to counters should be limited to addition or subtraction 797d79044fSdlgof uint64_t values. 807d79044fSdlg.Pp 81f391e9bdSfcambusAn alternate implementation of the API is provided on uni-processor 82e3facf30Sdlgsystems 8356e6bab0Sjmc(i.e. when the kernel is not built with 847d79044fSdlg.Dv MULTIPROCESSOR 857d79044fSdlgdefined) 86e3facf30Sdlgthat provides no overhead compared to direct access to a 877d79044fSdlgdata structure. 887d79044fSdlgThis allows the API to be used without affecting the performance 89e3facf30Sdlgof uni-processor systems. 907d79044fSdlg.Pp 917d79044fSdlg.Fn counters_alloc 927d79044fSdlgallocates memory for a series of uint64_t values on each CPU. 937d79044fSdlg.Fa ncounters 947d79044fSdlgspecifies the number of counters to be allocated. 957d79044fSdlgThe counters will be zeroed on allocation. 967d79044fSdlg.Pp 977d79044fSdlg.Fn counters_free 987d79044fSdlgdeallocates each CPU's counters. 997d79044fSdlgThe same 1007d79044fSdlg.Fa ncounters 101f01a839dSjcaargument originally provided to 1027d79044fSdlg.Fn counters_alloc 1037d79044fSdlgmust be passed to 1047d79044fSdlg.Fn counters_free . 1057d79044fSdlg.Pp 10657d14348Sdlg.Fn counters_alloc 10757d14348Sdlgmay only be used after all the CPUs in the system have been attached. 10857d14348SdlgIf a set of CPU counters needs to be available during early boot, 10957d14348Sdlga cpumem pointer and counters for the boot CPU may be statically 11057d14348Sdlgallocated. 11157d14348Sdlg.Pp 11257d14348Sdlg.Fn COUNTERS_BOOT_MEMORY 11357d14348Sdlgstatically allocates a set of counter for use on the boot CPU 11457d14348Sdlgbefore the other CPUs in the system have been attached. 11557d14348SdlgThe allocation is identified by 11657d14348Sdlg.Fa NAME 11757d14348Sdlgand provides memory for the number of counters specified by 11857d14348Sdlg.Fa ncounters . 11975088f8dSdlgThe counters will be initialised to zero. 12057d14348Sdlg.Pp 12157d14348Sdlg.Fn COUNTERS_BOOT_INITIALIZER 12257d14348Sdlgis used to initialise a cpumem pointer with the memory that was previously 12357d14348Sdlgallocated using 12457d14348Sdlg.Fn COUNTERS_BOOT_MEMORY 12557d14348Sdlgand identified by 12657d14348Sdlg.Fa NAME . 12757d14348Sdlg.Pp 12857d14348Sdlg.Fn counters_alloc_ncpus 12957d14348Sdlgallocates additional sets of counters for the CPUs that were attached 13057d14348Sdlgduring boot. 13157d14348SdlgThe cpumem structure 13257d14348Sdlg.Fa cm 13357d14348Sdlgmust have been initialised with 13457d14348Sdlg.Fn COUNTERS_BOOT_INITIALIZER . 13557d14348SdlgThe same number of counters originally passed to 13657d14348Sdlg.Fa COUNTERS_BOOT_MEMORY 13757d14348Sdlgmust be specified by 13857d14348Sdlg.Fa ncounters . 139309a8aedSdlgThe counters on the boot CPU will be preserved, while the counters 1408ce5b002Sjmcfor the additional CPUs will be zeroed on allocation. 14157d14348Sdlg.Pp 14257d14348SdlgCounters that have been allocated with 14357d14348Sdlg.Fn COUNTERS_BOOT_MEMORY 14457d14348Sdlgand 14557d14348Sdlg.Fn counters_alloc_ncpus 14657d14348Sdlgcannot be deallocated with 14757d14348Sdlg.Fa counters_free . 14857d14348Sdlg.Pp 1497d79044fSdlg.Fn counters_enter 1507d79044fSdlgprovides access to the current CPU's set of counters referenced by 1517d79044fSdlg.Fa cm . 15256e6bab0SjmcThe caller's reference to the counters is held by 1537d79044fSdlg.Fa ref . 1547d79044fSdlg.Pp 1557d79044fSdlg.Fn counters_leave 15656e6bab0Sjmcindicates the end of access to the current CPU's set of counters referenced by 1577d79044fSdlg.Fa cm . 1587d79044fSdlgThe reference held by 1597d79044fSdlg.Fa ref 1607d79044fSdlgis released by this call. 1617d79044fSdlg.Pp 16234b3a856Sdlg.Fn counters_inc 16334b3a856Sdlgincrements the counter at the index specified by 16434b3a856Sdlg.Fa counter 16534b3a856Sdlgin the array of counters referenced by 16634b3a856Sdlg.Fa cm . 16734b3a856Sdlg.Pp 16834b3a856Sdlg.Fn counters_add 1695d360295Sjmcadds the value of 17034b3a856Sdlg.Fa v 17134b3a856Sdlgto the counter at the index specified by 17234b3a856Sdlg.Fa counter 17334b3a856Sdlgin the array of counters referenced by 17434b3a856Sdlg.Fa cm . 17534b3a856Sdlg.Pp 17634b3a856Sdlg.Fn counters_pkt 17734b3a856Sdlgincrements the value at the index specified by 17834b3a856Sdlg.Fa pcounter 17934b3a856Sdlgand adds the value of 18034b3a856Sdlg.Fa bytes 18134b3a856Sdlgto the counter at the index specified by 18234b3a856Sdlg.Fa bcounter 18334b3a856Sdlgin the array of counters referenced by 18434b3a856Sdlg.Fa cm . 18534b3a856Sdlg.Pp 1867d79044fSdlg.Fn counters_read 1877d79044fSdlgiterates over each CPU's set of counters referenced by 1887d79044fSdlg.Fa cm , 1897d79044fSdlgtakes a consistent snapshot of the counters, and then sums them together. 1907d79044fSdlgThe sum of the counters is written to the 1917d79044fSdlg.Fa counters 1927d79044fSdlgarray. 1937d79044fSdlgThe number of counters is specified with 1947d79044fSdlg.Fa ncounters . 195*bf0d449cSmpi.Fa scratch 196*bf0d449cSmpimay point to a buffer used to temporarily hold 197*bf0d449cSmpi.Fa counters . 198*bf0d449cSmpiIf 199*bf0d449cSmpi.Dv NULL , 200*bf0d449cSmpione will be dynamically allocated and freed. 2017d79044fSdlg.Pp 2027d79044fSdlg.Fn counters_zero 20356e6bab0Sjmciterates over each CPU's set of counters referenced by 20456e6bab0Sjmc.Fa cm 2057d79044fSdlgand zeroes them. 2067d79044fSdlgThe number of counters is specified with 2077d79044fSdlg.Fa ncounters . 2087d79044fSdlg.Fn counters_zero 20956e6bab0Sjmcitself does not prevent concurrent updates of the counters; it is 2107d79044fSdlgup to the caller to serialise this call with other actions. 2117d79044fSdlg.Sh CONTEXT 2127d79044fSdlg.Fn counters_alloc , 2137d79044fSdlg.Fn counters_free , 21457d14348Sdlg.Fn counters_alloc_ncpus , 2157d79044fSdlgand 2167d79044fSdlg.Fn counters_read 2177d79044fSdlgmay be called during autoconf, or from process context. 2187d79044fSdlg.Pp 2197d79044fSdlg.Fn counters_enter , 2207d79044fSdlg.Fn counters_leave , 22134b3a856Sdlg.Fn counters_inc , 22234b3a856Sdlg.Fn counters_add , 22334b3a856Sdlg.Fn counters_pkt , 2247d79044fSdlgand 2257d79044fSdlg.Fn counters_zero 2267d79044fSdlgmay be called during autoconf, from process context, or from interrupt 2277d79044fSdlgcontext. 2287d79044fSdlgThe per CPU counters API does not provide any locking or serialisation 2297d79044fSdlgof access to each CPU's set of counters beyond isolating each CPU's 2307d79044fSdlgupdate. 2317d79044fSdlgIt is up to the caller to provide appropriate locking or serialisation 2327d79044fSdlgaround calls to these functions to prevent concurrent access to the 2337d79044fSdlgrelevant data structures. 2347d79044fSdlg.Sh RETURN VALUES 23557d14348Sdlg.Fn counters_alloc 23657d14348Sdlgand 23757d14348Sdlg.Fn counters_alloc_ncpus 2387d79044fSdlgwill return an opaque cpumem pointer that references each CPU's 2397d79044fSdlgset of counters. 2407d79044fSdlg.Pp 2417d79044fSdlg.Fn counters_enter 2427d79044fSdlgreturns a reference to the current CPU's set of counters. 2431a108db9Sdlg.Sh EXAMPLES 2441a108db9SdlgThe following is an example of providing per CPU counters at boot 2451a108db9Sdlgtime based on the 2461a108db9Sdlg.Xr mbuf 9 2471a108db9Sdlgstatistics code in 2481a108db9Sdlg.Pa sys/kern/uipc_mbuf.c . 2491a108db9Sdlg.Bd -literal 2501a108db9Sdlg/* mbuf stats */ 2511a108db9SdlgCOUNTERS_BOOT_MEMORY(mbstat_boot, MBSTAT_COUNT); 2521a108db9Sdlgstruct cpumem *mbstat = COUNTERS_BOOT_INITIALIZER(mbstat_boot); 2531a108db9Sdlg 2541a108db9Sdlg/* 2551a108db9Sdlg * this function is called from init_main.c after devices 2561a108db9Sdlg * (including additional CPUs) have been attached 2571a108db9Sdlg */ 2581a108db9Sdlgvoid 2591a108db9Sdlgmbcpuinit() 2601a108db9Sdlg{ 261f01a839dSjca mbstat = counters_alloc_ncpus(mbstat, MBSTAT_COUNT); 2621a108db9Sdlg} 2631a108db9Sdlg 2641a108db9Sdlgstruct mbuf * 2651a108db9Sdlgm_get(int nowait, int type) 2661a108db9Sdlg{ 2671a108db9Sdlg ... 2681a108db9Sdlg 2691a108db9Sdlg struct counters_ref cr; 2701a108db9Sdlg uint64_t *counters; 2711a108db9Sdlg int s; 2721a108db9Sdlg 2731a108db9Sdlg ... 2741a108db9Sdlg 2751a108db9Sdlg s = splnet(); 2761a108db9Sdlg counters = counters_enter(&cr, mbstat); 2771a108db9Sdlg counters[type]++; 2781a108db9Sdlg counters_leave(&cr, mbstat); 2791a108db9Sdlg splx(s); 2801a108db9Sdlg 2811a108db9Sdlg ... 2821a108db9Sdlg} 2831a108db9Sdlg 2841a108db9Sdlgstruct mbuf * 2851a108db9Sdlgm_free(struct mbuf *m) 2861a108db9Sdlg{ 2871a108db9Sdlg ... 2881a108db9Sdlg 2891a108db9Sdlg struct counters_ref cr; 2901a108db9Sdlg uint64_t *counters; 2911a108db9Sdlg int s; 2921a108db9Sdlg 2931a108db9Sdlg ... 2941a108db9Sdlg 2951a108db9Sdlg s = splnet(); 2961a108db9Sdlg counters = counters_enter(&cr, mbstat); 2971a108db9Sdlg counters[m->m_type]--; 2981a108db9Sdlg counters_leave(&cr, mbstat); 2991a108db9Sdlg splx(s); 3001a108db9Sdlg 3011a108db9Sdlg ... 3021a108db9Sdlg} 3031a108db9Sdlg.Ed 3047d79044fSdlg.Sh SEE ALSO 30556e6bab0Sjmc.Xr cpumem_get 9 , 3067d79044fSdlg.Xr malloc 9 3077d79044fSdlg.Sh HISTORY 3087d79044fSdlgThe per CPU counter API first appeared in 3097d79044fSdlg.Ox 6.1 . 3107d79044fSdlg.Sh AUTHORS 3117d79044fSdlgThe per CPU counter API was written by 3127d79044fSdlg.An David Gwynne Aq Mt dlg@openbsd.org . 313