xref: /openbsd/share/man/man9/counters_alloc.9 (revision bf0d449c)
1.\"	$OpenBSD: counters_alloc.9,v 1.13 2023/09/16 09:33:28 mpi Exp $
2.\"
3.\" Copyright (c) 2016 David Gwynne <dlg@openbsd.org>
4.\"
5.\" Permission to use, copy, modify, and distribute this software for any
6.\" purpose with or without fee is hereby granted, provided that the above
7.\" copyright notice and this permission notice appear in all copies.
8.\"
9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16.\"
17.Dd $Mdocdate: September 16 2023 $
18.Dt COUNTERS_ALLOC 9
19.Os
20.Sh NAME
21.Nm counters_alloc ,
22.Nm counters_free ,
23.Nm COUNTERS_BOOT_MEMORY ,
24.Nm COUNTERS_BOOT_INITIALIZER ,
25.Nm counters_alloc_ncpus ,
26.Nm counters_enter ,
27.Nm counters_leave ,
28.Nm counters_inc ,
29.Nm counters_add ,
30.Nm counters_pkt ,
31.Nm counters_read ,
32.Nm counters_zero
33.Nd per CPU counters
34.Sh SYNOPSIS
35.In sys/percpu.h
36.Ft struct cpumem *
37.Fn counters_alloc "unsigned int ncounters"
38.Ft void
39.Fn counters_free "struct cpumem *cm" "unsigned int ncounters"
40.Fn COUNTERS_BOOT_MEMORY "NAME" "unsigned int ncounters"
41.Fn COUNTERS_BOOT_INITIALIZER "NAME"
42.Ft struct cpumemt *
43.Fo counters_alloc_ncpus
44.Fa "struct cpumem *cm"
45.Fa "unsigned int ncounters"
46.Fc
47.Ft uint64_t *
48.Fn counters_enter "struct counters_ref *ref" "struct cpumem *cm"
49.Ft void
50.Fn counters_leave "struct counters_ref *ref" "struct cpumem *cm"
51.Ft void
52.Fn counters_inc "struct cpumem *cm" "unsigned int counter"
53.Ft void
54.Fn counters_add "struct cpumem *cm" "unsigned int counter" "uint64_t v"
55.Ft void
56.Fo counters_pkt
57.Fa "struct cpumem *cm"
58.Fa "unsigned int pcounter"
59.Fa "unsigned int bcounter"
60.Fa "uint64_t bytes"
61.Fc
62.Ft void
63.Fo counters_read
64.Fa "struct cpumem *cm"
65.Fa "uint64_t *counters"
66.Fa "unsigned int ncounters"
67.Fa "uint64_t *scratch"
68.Fc
69.Ft void
70.Fn counters_zero "struct cpumem *cm" "unsigned int ncounters"
71.Sh DESCRIPTION
72The per CPU counter API builds on the per CPU memory API and provides
73access to a series of uint64_t counter values on each CPU.
74.Pp
75The API provides versioning of counter updates without using
76interlocked CPU instructions so they can all be read in a consistent
77state.
78Updates to counters should be limited to addition or subtraction
79of uint64_t values.
80.Pp
81An alternate implementation of the API is provided on uni-processor
82systems
83(i.e. when the kernel is not built with
84.Dv MULTIPROCESSOR
85defined)
86that provides no overhead compared to direct access to a
87data structure.
88This allows the API to be used without affecting the performance
89of uni-processor systems.
90.Pp
91.Fn counters_alloc
92allocates memory for a series of uint64_t values on each CPU.
93.Fa ncounters
94specifies the number of counters to be allocated.
95The counters will be zeroed on allocation.
96.Pp
97.Fn counters_free
98deallocates each CPU's counters.
99The same
100.Fa ncounters
101argument originally provided to
102.Fn counters_alloc
103must be passed to
104.Fn counters_free .
105.Pp
106.Fn counters_alloc
107may only be used after all the CPUs in the system have been attached.
108If a set of CPU counters needs to be available during early boot,
109a cpumem pointer and counters for the boot CPU may be statically
110allocated.
111.Pp
112.Fn COUNTERS_BOOT_MEMORY
113statically allocates a set of counter for use on the boot CPU
114before the other CPUs in the system have been attached.
115The allocation is identified by
116.Fa NAME
117and provides memory for the number of counters specified by
118.Fa ncounters .
119The counters will be initialised to zero.
120.Pp
121.Fn COUNTERS_BOOT_INITIALIZER
122is used to initialise a cpumem pointer with the memory that was previously
123allocated using
124.Fn COUNTERS_BOOT_MEMORY
125and identified by
126.Fa NAME .
127.Pp
128.Fn counters_alloc_ncpus
129allocates additional sets of counters for the CPUs that were attached
130during boot.
131The cpumem structure
132.Fa cm
133must have been initialised with
134.Fn COUNTERS_BOOT_INITIALIZER .
135The same number of counters originally passed to
136.Fa COUNTERS_BOOT_MEMORY
137must be specified by
138.Fa ncounters .
139The counters on the boot CPU will be preserved, while the counters
140for the additional CPUs will be zeroed on allocation.
141.Pp
142Counters that have been allocated with
143.Fn COUNTERS_BOOT_MEMORY
144and
145.Fn counters_alloc_ncpus
146cannot be deallocated with
147.Fa counters_free .
148.Pp
149.Fn counters_enter
150provides access to the current CPU's set of counters referenced by
151.Fa cm .
152The caller's reference to the counters is held by
153.Fa ref .
154.Pp
155.Fn counters_leave
156indicates the end of access to the current CPU's set of counters referenced by
157.Fa cm .
158The reference held by
159.Fa ref
160is released by this call.
161.Pp
162.Fn counters_inc
163increments the counter at the index specified by
164.Fa counter
165in the array of counters referenced by
166.Fa cm .
167.Pp
168.Fn counters_add
169adds the value of
170.Fa v
171to the counter at the index specified by
172.Fa counter
173in the array of counters referenced by
174.Fa cm .
175.Pp
176.Fn counters_pkt
177increments the value at the index specified by
178.Fa pcounter
179and adds the value of
180.Fa bytes
181to the counter at the index specified by
182.Fa bcounter
183in the array of counters referenced by
184.Fa cm .
185.Pp
186.Fn counters_read
187iterates over each CPU's set of counters referenced by
188.Fa cm ,
189takes a consistent snapshot of the counters, and then sums them together.
190The sum of the counters is written to the
191.Fa counters
192array.
193The number of counters is specified with
194.Fa ncounters .
195.Fa scratch
196may point to a buffer used to temporarily hold
197.Fa counters .
198If
199.Dv NULL ,
200one will be dynamically allocated and freed.
201.Pp
202.Fn counters_zero
203iterates over each CPU's set of counters referenced by
204.Fa cm
205and zeroes them.
206The number of counters is specified with
207.Fa ncounters .
208.Fn counters_zero
209itself does not prevent concurrent updates of the counters; it is
210up to the caller to serialise this call with other actions.
211.Sh CONTEXT
212.Fn counters_alloc ,
213.Fn counters_free ,
214.Fn counters_alloc_ncpus ,
215and
216.Fn counters_read
217may be called during autoconf, or from process context.
218.Pp
219.Fn counters_enter ,
220.Fn counters_leave ,
221.Fn counters_inc ,
222.Fn counters_add ,
223.Fn counters_pkt ,
224and
225.Fn counters_zero
226may be called during autoconf, from process context, or from interrupt
227context.
228The per CPU counters API does not provide any locking or serialisation
229of access to each CPU's set of counters beyond isolating each CPU's
230update.
231It is up to the caller to provide appropriate locking or serialisation
232around calls to these functions to prevent concurrent access to the
233relevant data structures.
234.Sh RETURN VALUES
235.Fn counters_alloc
236and
237.Fn counters_alloc_ncpus
238will return an opaque cpumem pointer that references each CPU's
239set of counters.
240.Pp
241.Fn counters_enter
242returns a reference to the current CPU's set of counters.
243.Sh EXAMPLES
244The following is an example of providing per CPU counters at boot
245time based on the
246.Xr mbuf 9
247statistics code in
248.Pa sys/kern/uipc_mbuf.c .
249.Bd -literal
250/* mbuf stats */
251COUNTERS_BOOT_MEMORY(mbstat_boot, MBSTAT_COUNT);
252struct cpumem *mbstat = COUNTERS_BOOT_INITIALIZER(mbstat_boot);
253
254/*
255 * this function is called from init_main.c after devices
256 * (including additional CPUs) have been attached
257 */
258void
259mbcpuinit()
260{
261	mbstat = counters_alloc_ncpus(mbstat, MBSTAT_COUNT);
262}
263
264struct mbuf *
265m_get(int nowait, int type)
266{
267	...
268
269        struct counters_ref cr;
270        uint64_t *counters;
271        int s;
272
273	...
274
275        s = splnet();
276        counters = counters_enter(&cr, mbstat);
277        counters[type]++;
278        counters_leave(&cr, mbstat);
279        splx(s);
280
281	...
282}
283
284struct mbuf *
285m_free(struct mbuf *m)
286{
287	...
288
289        struct counters_ref cr;
290        uint64_t *counters;
291        int s;
292
293	...
294
295        s = splnet();
296        counters = counters_enter(&cr, mbstat);
297        counters[m->m_type]--;
298        counters_leave(&cr, mbstat);
299        splx(s);
300
301	...
302}
303.Ed
304.Sh SEE ALSO
305.Xr cpumem_get 9 ,
306.Xr malloc 9
307.Sh HISTORY
308The per CPU counter API first appeared in
309.Ox 6.1 .
310.Sh AUTHORS
311The per CPU counter API was written by
312.An David Gwynne Aq Mt dlg@openbsd.org .
313