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