xref: /openbsd-src/share/man/man9/counters_alloc.9 (revision bf0d449c49808ab2d0a67677895f728770d3c8af)
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