xref: /openbsd-src/share/man/man9/counters_alloc.9 (revision a0747c9f67a4ae71ccb71e62a28d1ea19e06a63c)
1.\"	$OpenBSD: counters_alloc.9,v 1.11 2020/08/27 09:29:16 fcambus 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: August 27 2020 $
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.Fc
68.Ft void
69.Fn counters_zero "struct cpumem *cm" "unsigned int ncounters"
70.Sh DESCRIPTION
71The per CPU counter API builds on the per CPU memory API and provides
72access to a series of uint64_t counter values on each CPU.
73.Pp
74The API provides versioning of counter updates without using
75interlocked CPU instructions so they can all be read in a consistent
76state.
77Updates to counters should be limited to addition or subtraction
78of uint64_t values.
79.Pp
80An alternate implementation of the API is provided on uni-processor
81(i.e. when the kernel is not built with
82.Dv MULTIPROCESSOR
83defined)
84systems that provides no overhead compared to direct access to a
85data structure.
86This allows the API to be used without affecting the performance
87uni-processor systems.
88.Pp
89.Fn counters_alloc
90allocates memory for a series of uint64_t values on each CPU.
91.Fa ncounters
92specifies the number of counters to be allocated.
93The counters will be zeroed on allocation.
94.Pp
95.Fn counters_free
96deallocates each CPU's counters.
97The same
98.Fa ncounters
99argument originally provided to
100.Fn counters_alloc
101must be passed to
102.Fn counters_free .
103.Pp
104.Fn counters_alloc
105may only be used after all the CPUs in the system have been attached.
106If a set of CPU counters needs to be available during early boot,
107a cpumem pointer and counters for the boot CPU may be statically
108allocated.
109.Pp
110.Fn COUNTERS_BOOT_MEMORY
111statically allocates a set of counter for use on the boot CPU
112before the other CPUs in the system have been attached.
113The allocation is identified by
114.Fa NAME
115and provides memory for the number of counters specified by
116.Fa ncounters .
117The counters will be initialised to zero.
118.Pp
119.Fn COUNTERS_BOOT_INITIALIZER
120is used to initialise a cpumem pointer with the memory that was previously
121allocated using
122.Fn COUNTERS_BOOT_MEMORY
123and identified by
124.Fa NAME .
125.Pp
126.Fn counters_alloc_ncpus
127allocates additional sets of counters for the CPUs that were attached
128during boot.
129The cpumem structure
130.Fa cm
131must have been initialised with
132.Fn COUNTERS_BOOT_INITIALIZER .
133The same number of counters originally passed to
134.Fa COUNTERS_BOOT_MEMORY
135must be specified by
136.Fa ncounters .
137The counters on the boot CPU will be preserved, while the counters
138for the additional CPUs will be zeroed on allocation.
139.Pp
140Counters that have been allocated with
141.Fn COUNTERS_BOOT_MEMORY
142and
143.Fn counters_alloc_ncpus
144cannot be deallocated with
145.Fa counters_free .
146Any attempt to do so will lead to undefined behaviour.
147.Pp
148.Fn counters_enter
149provides access to the current CPU's set of counters referenced by
150.Fa cm .
151The caller's reference to the counters is held by
152.Fa ref .
153.Pp
154.Fn counters_leave
155indicates the end of access to the current CPU's set of counters referenced by
156.Fa cm .
157The reference held by
158.Fa ref
159is released by this call.
160.Pp
161.Fn counters_inc
162increments the counter at the index specified by
163.Fa counter
164in the array of counters referenced by
165.Fa cm .
166.Pp
167.Fn counters_add
168adds the value of
169.Fa v
170to the counter at the index specified by
171.Fa counter
172in the array of counters referenced by
173.Fa cm .
174.Pp
175.Fn counters_pkt
176increments the value at the index specified by
177.Fa pcounter
178and adds the value of
179.Fa bytes
180to the counter at the index specified by
181.Fa bcounter
182in the array of counters referenced by
183.Fa cm .
184.Pp
185.Fn counters_read
186iterates over each CPU's set of counters referenced by
187.Fa cm ,
188takes a consistent snapshot of the counters, and then sums them together.
189The sum of the counters is written to the
190.Fa counters
191array.
192The number of counters is specified with
193.Fa ncounters .
194.Pp
195.Fn counters_zero
196iterates over each CPU's set of counters referenced by
197.Fa cm
198and zeroes them.
199The number of counters is specified with
200.Fa ncounters .
201.Fn counters_zero
202itself does not prevent concurrent updates of the counters; it is
203up to the caller to serialise this call with other actions.
204.Sh CONTEXT
205.Fn counters_alloc ,
206.Fn counters_free ,
207.Fn counters_alloc_ncpus ,
208and
209.Fn counters_read
210may be called during autoconf, or from process context.
211.Pp
212.Fn counters_enter ,
213.Fn counters_leave ,
214.Fn counters_inc ,
215.Fn counters_add ,
216.Fn counters_pkt ,
217and
218.Fn counters_zero
219may be called during autoconf, from process context, or from interrupt
220context.
221The per CPU counters API does not provide any locking or serialisation
222of access to each CPU's set of counters beyond isolating each CPU's
223update.
224It is up to the caller to provide appropriate locking or serialisation
225around calls to these functions to prevent concurrent access to the
226relevant data structures.
227.Sh RETURN VALUES
228.Fn counters_alloc
229and
230.Fn counters_alloc_ncpus
231will return an opaque cpumem pointer that references each CPU's
232set of counters.
233.Pp
234.Fn counters_enter
235returns a reference to the current CPU's set of counters.
236.Sh EXAMPLES
237The following is an example of providing per CPU counters at boot
238time based on the
239.Xr mbuf 9
240statistics code in
241.Pa sys/kern/uipc_mbuf.c .
242.Bd -literal
243/* mbuf stats */
244COUNTERS_BOOT_MEMORY(mbstat_boot, MBSTAT_COUNT);
245struct cpumem *mbstat = COUNTERS_BOOT_INITIALIZER(mbstat_boot);
246
247/*
248 * this function is called from init_main.c after devices
249 * (including additional CPUs) have been attached
250 */
251void
252mbcpuinit()
253{
254	mbstat = counters_alloc_ncpus(mbstat, MBSTAT_COUNT);
255}
256
257struct mbuf *
258m_get(int nowait, int type)
259{
260	...
261
262        struct counters_ref cr;
263        uint64_t *counters;
264        int s;
265
266	...
267
268        s = splnet();
269        counters = counters_enter(&cr, mbstat);
270        counters[type]++;
271        counters_leave(&cr, mbstat);
272        splx(s);
273
274	...
275}
276
277struct mbuf *
278m_free(struct mbuf *m)
279{
280	...
281
282        struct counters_ref cr;
283        uint64_t *counters;
284        int s;
285
286	...
287
288        s = splnet();
289        counters = counters_enter(&cr, mbstat);
290        counters[m->m_type]--;
291        counters_leave(&cr, mbstat);
292        splx(s);
293
294	...
295}
296.Ed
297.Sh SEE ALSO
298.Xr cpumem_get 9 ,
299.Xr malloc 9
300.Sh HISTORY
301The per CPU counter API first appeared in
302.Ox 6.1 .
303.Sh AUTHORS
304The per CPU counter API was written by
305.An David Gwynne Aq Mt dlg@openbsd.org .
306